Skip to content

Commit

Permalink
feat(docker-jans-scim): allow creating initial persistence entry (#2035)
Browse files Browse the repository at this point in the history
The changeset add feature to allow creating entry directly from docker-jans-scim.
Redundant code in docker-jans-persistence-loader and docker-jans-configurator are removed.
  • Loading branch information
iromli authored Aug 8, 2022
1 parent bc56a50 commit e485618
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 49 deletions.
22 changes: 0 additions & 22 deletions docker-jans-configurator/scripts/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -735,14 +735,6 @@ def radius_ctx(self):
partial(encode_template, fn, self.ctx, basedir),
)

def scim_ctx(self):
self.set_config("scim_client_id", lambda: f"1201.{uuid4()}")
scim_client_pw = self.set_secret("scim_client_pw", get_random_chars)
self.set_secret(
"scim_client_encoded_pw",
partial(encode_text, scim_client_pw, self.get_secret("encoded_salt"))
)

def couchbase_ctx(self):
# TODO: move this to persistence-loader?
self.set_config("couchbaseTrustStoreFn", "/etc/certs/couchbase.pkcs12")
Expand All @@ -758,14 +750,6 @@ def jackrabbit_ctx(self):
def sql_ctx(self):
self.set_secret("sql_password", self.params["sql_pw"])

def casa_ctx(self):
self.set_config("casa_client_id", lambda: f"1902.{uuid4()}")
casa_client_pw = self.set_secret("casa_client_pw", get_random_chars)
self.set_secret(
"casa_client_encoded_pw",
partial(encode_text, casa_client_pw, self.get_secret("encoded_salt"))
)

def generate(self):
opt_scopes = self.params["optional_scopes"]

Expand All @@ -786,9 +770,6 @@ def generate(self):
# self.oxshibboleth_ctx()
# self.radius_ctx()

if "scim" in opt_scopes:
self.scim_ctx()

if "couchbase" in opt_scopes:
self.couchbase_ctx()

Expand All @@ -797,9 +778,6 @@ def generate(self):
if "sql" in opt_scopes:
self.sql_ctx()

if "casa" in opt_scopes:
self.casa_ctx()

self.admin_ui_ctx()
self.jans_cli_ctx()

Expand Down
2 changes: 1 addition & 1 deletion docker-jans-configurator/scripts/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@

OPTIONAL_SCOPES = (
"ldap",
"scim",
"couchbase",
"redis",
"sql",
Expand All @@ -34,6 +33,7 @@
"fido2",
"client-api",
"casa",
"scim",
)


Expand Down
24 changes: 0 additions & 24 deletions docker-jans-persistence-loader/scripts/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,6 @@ def get_base_ctx(manager):
"auth_openidScopeBackwardCompatibility": manager.config.get("auth_openidScopeBackwardCompatibility"),

"admin_inum": manager.config.get("admin_inum"),
"scim_client_id": manager.config.get("scim_client_id"),
"scim_client_encoded_pw": manager.secret.get("scim_client_encoded_pw"),
"jca_client_id": manager.config.get("jca_client_id"),
"jca_client_encoded_pw": manager.secret.get("jca_client_encoded_pw"),
}
Expand Down Expand Up @@ -201,20 +199,6 @@ def merge_auth_ctx(ctx):
return ctx


def merge_scim_ctx(ctx):
basedir = '/app/templates/jans-scim'
file_mappings = {
'scim_dynamic_conf_base64': 'dynamic-conf.json',
'scim_static_conf_base64': 'static-conf.json',
}

for key, file_ in file_mappings.items():
file_path = os.path.join(basedir, file_)
with open(file_path) as fp:
ctx[key] = generate_base64_contents(fp.read() % ctx)
return ctx


def merge_config_api_ctx(ctx):
def transform_url(url):
auth_server_url = os.environ.get("CN_AUTH_SERVER_URL", "")
Expand Down Expand Up @@ -303,7 +287,6 @@ def prepare_template_ctx(manager):
ctx = merge_extension_ctx(ctx)
ctx = merge_auth_ctx(ctx)
ctx = merge_config_api_ctx(ctx)
ctx = merge_scim_ctx(ctx)
ctx = merge_jans_cli_ctx(manager, ctx)
return ctx

Expand Down Expand Up @@ -346,13 +329,6 @@ def default_files():
"jans-cli/client.ldif",
]

if "scim" in optional_scopes:
files += [
"jans-scim/configuration.ldif",
"jans-scim/scopes.ldif",
"jans-scim/clients.ldif",
]

return files

def user_files():
Expand Down
1 change: 1 addition & 0 deletions docker-jans-scim/.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@
!scripts
!LICENSE
!requirements.txt
!templates
38 changes: 37 additions & 1 deletion docker-jans-scim/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ RUN wget -q https://maven.jans.io/maven/io/jans/jython-installer/${JYTHON_VERSIO
# ====

ENV CN_VERSION=1.0.2-SNAPSHOT
ENV CN_BUILD_DATE='2022-08-03 12:38'
ENV CN_BUILD_DATE='2022-08-04 15:32'
ENV CN_SOURCE_URL=https://jenkins.jans.io/maven/io/jans/jans-scim-server/${CN_VERSION}/jans-scim-server-${CN_VERSION}.war

# Install SCIM
Expand All @@ -60,6 +60,41 @@ RUN mkdir -p ${JETTY_BASE}/jans-scim/webapps \
&& java -jar ${JETTY_HOME}/start.jar jetty.home=${JETTY_HOME} jetty.base=${JETTY_BASE}/jans-scim --add-to-start=server,deploy,resources,http,http-forwarded,jsp,websocket,cdi-decorate \
&& rm -rf /tmp/jans-scim.war /tmp/WEB-INF

# =====================
# jans-linux-setup sync
# =====================

ENV JANS_LINUX_SETUP_VERSION=2c1414dfc4edd2c14061d375622d56ed8542e08d
ARG JANS_SETUP_DIR=jans-linux-setup/jans_setup

# note that as we're pulling from a monorepo (with multiple project in it)
# we are using partial-clone and sparse-checkout to get the jans-linux-setup code
RUN git clone --filter blob:none --no-checkout https://github.com/janssenproject/jans /tmp/jans \
&& cd /tmp/jans \
&& git sparse-checkout init --cone \
&& git checkout ${JANS_LINUX_SETUP_VERSION} \
&& git sparse-checkout set ${JANS_SETUP_DIR}

RUN mkdir -p /app/static/rdbm \
/app/schema \
/app/templates/jans-scim

# sync static files from linux-setup
RUN cd /tmp/jans \
&& cp ${JANS_SETUP_DIR}/static/rdbm/sql_data_types.json /app/static/rdbm/ \
&& cp ${JANS_SETUP_DIR}/static/rdbm/ldap_sql_data_type_mapping.json /app/static/rdbm/ \
&& cp ${JANS_SETUP_DIR}/static/rdbm/opendj_attributes_syntax.json /app/static/rdbm/ \
&& cp ${JANS_SETUP_DIR}/static/rdbm/sub_tables.json /app/static/rdbm/ \
&& cp ${JANS_SETUP_DIR}/schema/jans_schema.json /app/schema/ \
&& cp ${JANS_SETUP_DIR}/schema/custom_schema.json /app/schema/ \
&& cp ${JANS_SETUP_DIR}/schema/opendj_types.json /app/schema/ \
&& cp ${JANS_SETUP_DIR}/templates/jans-scim/configuration.ldif /app/templates/jans-scim/ \
&& cp ${JANS_SETUP_DIR}/templates/jans-scim/dynamic-conf.json /app/templates/jans-scim/ \
&& cp ${JANS_SETUP_DIR}/templates/jans-scim/static-conf.json /app/templates/jans-scim/

# cleanup
RUN rm -rf /tmp/jans

# ======
# Python
# ======
Expand Down Expand Up @@ -187,6 +222,7 @@ RUN mkdir -p /etc/certs \
COPY jetty/jans-scim.xml ${JETTY_BASE}/jans-scim/webapps/
COPY jetty/log4j2.xml ${JETTY_BASE}/jans-scim/resources/
COPY conf/*.tmpl /app/templates/
COPY templates /app/templates

COPY scripts /app/scripts
RUN chmod +x /app/scripts/entrypoint.sh
Expand Down
91 changes: 91 additions & 0 deletions docker-jans-scim/scripts/bootstrap.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
from __future__ import annotations

import json
import os
import re
import typing as _t
from functools import cached_property
from string import Template
from uuid import uuid4

from jans.pycloudlib import get_manager
from jans.pycloudlib.persistence import render_couchbase_properties
Expand All @@ -13,12 +18,25 @@
from jans.pycloudlib.persistence import sync_ldap_truststore
from jans.pycloudlib.persistence import render_sql_properties
from jans.pycloudlib.persistence import render_spanner_properties
from jans.pycloudlib.persistence.couchbase import CouchbaseClient
from jans.pycloudlib.persistence.ldap import LdapClient
from jans.pycloudlib.persistence.spanner import SpannerClient
from jans.pycloudlib.persistence.sql import SqlClient
from jans.pycloudlib.persistence.utils import PersistenceMapper
from jans.pycloudlib.utils import cert_to_truststore
from jans.pycloudlib.utils import encode_text
from jans.pycloudlib.utils import generate_base64_contents
from jans.pycloudlib.utils import get_random_chars

import logging.config
from settings import LOGGING_CONFIG

if _t.TYPE_CHECKING: # pragma: no cover
# imported objects for function type hint, completion, etc.
# these won't be executed in runtime
from jans.pycloudlib.manager import Manager


logging.config.dictConfig(LOGGING_CONFIG)
logger = logging.getLogger("entrypoint")

Expand Down Expand Up @@ -115,6 +133,9 @@ def main():
modify_webdefault_xml()
configure_logging()

persistence_setup = PersistenceSetup(manager)
persistence_setup.import_ldif_files()


def configure_logging():
# default config
Expand Down Expand Up @@ -185,5 +206,75 @@ def configure_logging():
f.write(tmpl.safe_substitute(config))


class PersistenceSetup:
def __init__(self, manager: Manager) -> None:
self.manager = manager

client_classes = {
"ldap": LdapClient,
"couchbase": CouchbaseClient,
"spanner": SpannerClient,
"sql": SqlClient,
}

# determine persistence type
mapper = PersistenceMapper()
self.persistence_type = mapper.mapping["default"]

# determine persistence client
client_cls = client_classes.get(self.persistence_type)
self.client = client_cls(manager)

@cached_property
def ctx(self) -> dict[str, _t.Any]:
ctx = {
"hostname": self.manager.config.get("hostname"),
}

# SCIM client
ctx["scim_client_id"] = self.manager.config.get("scim_client_id")

if not ctx["scim_client_id"]:
ctx["scim_client_id"] = f"1201.{uuid4()}"
self.manager.config.set("scim_client_id", ctx["scim_client_id"])

ctx["scim_client_pw"] = self.manager.secret.get("scim_client_pw")

if not ctx["scim_client_pw"]:
ctx["scim_client_pw"] = get_random_chars()
self.manager.secret.set("scim_client_pw", ctx["scim_client_pw"])

ctx["scim_client_encoded_pw"] = self.manager.secret.get("scim_client_encoded_pw")

if not ctx["scim_client_encoded_pw"]:
ctx["scim_client_encoded_pw"] = encode_text(
ctx["scim_client_pw"], self.manager.secret.get("encoded_salt"),
).decode()
self.manager.secret.set("scim_client_encoded_pw", ctx["scim_client_encoded_pw"])

# pre-populate scim_dynamic_conf_base64
with open("/app/templates/jans-scim/dynamic-conf.json") as f:
ctx["scim_dynamic_conf_base64"] = generate_base64_contents(f.read() % ctx)

# pre-populate scim_static_conf_base64
with open("/app/templates/jans-scim/static-conf.json") as f:
ctx["scim_static_conf_base64"] = generate_base64_contents(f.read())

return ctx

@cached_property
def ldif_files(self) -> list[str]:
files = [
f"/app/templates/jans-scim/{file_}"
for file_ in ["configuration.ldif", "scopes.ldif", "clients.ldif"]
]
return files

def import_ldif_files(self) -> None:
for file_ in self.ldif_files:
logger.info(f"Importing {file_}")
self.client.create_from_ldif(file_, self.ctx)


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,3 @@ jansSubjectTyp: pairwise
jansTknEndpointAuthMethod: client_secret_basic
objectClass: top
objectClass: jansClnt

0 comments on commit e485618

Please sign in to comment.