Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: casa updated dependencies and manifests #202

Merged
merged 2 commits into from
May 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docker-casa/.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# include required files/directories
!scripts
!templates
!LICENSE
!requirements.txt
!jetty
!conf
72 changes: 61 additions & 11 deletions docker-casa/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
FROM bellsoft/liberica-openjre-alpine:11.0.13-8
FROM bellsoft/liberica-openjre-alpine:11.0.15

# ===============
# Alpine packages
# ===============

RUN apk update \
&& apk add --no-cache py3-pip openssl tini py3-cryptography py3-lxml py3-psycopg2 \
&& apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/v3.15/community py3-grpcio \
&& apk add --no-cache --virtual build-deps git wget zip \
&& apk upgrade \
&& apk add --no-cache python3 openssl tini py3-cryptography py3-lxml py3-psycopg2 py3-grpcio \
&& apk add --no-cache --virtual .build-deps git wget zip \
&& mkdir -p /usr/java/latest \
&& ln -sf /usr/lib/jvm/jre /usr/java/latest/jre

# =====
# Jetty
# =====

ARG JETTY_VERSION=10.0.6
ARG JETTY_VERSION=11.0.8
ARG JETTY_HOME=/opt/jetty
ARG JETTY_BASE=/opt/jans/jetty
ARG JETTY_USER_HOME_LIB=/home/jetty/lib
Expand All @@ -35,7 +35,7 @@ EXPOSE 8080
# ====

ENV GLUU_VERSION=5.0.0-SNAPSHOT
ENV GLUU_BUILD_DATE='2022-03-17 11:52'
ENV GLUU_BUILD_DATE='2022-04-29 12:53'
ENV GLUU_SOURCE_URL=https://jenkins.gluu.org/maven/org/gluu/casa/${GLUU_VERSION}/casa-${GLUU_VERSION}.war

# Install Casa
Expand All @@ -54,15 +54,65 @@ RUN mkdir -p ${JETTY_BASE}/casa/webapps \
# ======

COPY requirements.txt /app/requirements.txt
RUN pip3 install -U pip wheel \
&& pip3 install -r /app/requirements.txt --no-cache-dir
RUN python3 -m ensurepip \
&& pip3 install --no-cache-dir -U pip wheel \
&& pip3 install --no-cache-dir -r /app/requirements.txt \
&& pip3 uninstall -y pip wheel

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

ENV JANS_LINUX_SETUP_VERSION=eb113d09421b95671fe1ab4eaa5c4bafc2aed6af
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

# sync static files from linux-setup
RUN cd /tmp/jans \
&& cp -R ${JANS_SETUP_DIR}/static/rdbm/sql_data_types.json /app/static/rdbm/ \
&& cp -R ${JANS_SETUP_DIR}/static/rdbm/ldap_sql_data_type_mapping.json /app/static/rdbm/ \
&& cp -R ${JANS_SETUP_DIR}/static/rdbm/opendj_attributes_syntax.json /app/static/rdbm/ \
&& cp -R ${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/

# ===============
# flex setup sync
# ===============

ENV FLEX_VERSION=a8251496ff2ade9dd8101873b45f4c490ae9c64e
ARG FLEX_SETUP_DIR=flex-linux-setup/flex_linux_setup
ARG CASA_EXTRAS_DIR=casa/extras

RUN mkdir -p /app/templates /app/static/extension/person_authentication

RUN git clone --filter blob:none --no-checkout https://github.com/GluuFederation/flex.git /tmp/flex \
&& cd /tmp/flex \
&& git sparse-checkout init --cone \
&& git checkout ${FLEX_VERSION} \
&& git sparse-checkout add ${FLEX_SETUP_DIR} \
&& cp ${FLEX_SETUP_DIR}/templates/casa_*.ldif /app/templates \
&& git sparse-checkout add ${CASA_EXTRAS_DIR} \
&& cp ${CASA_EXTRAS_DIR}/Casa.py /app/static/extension/person_authentication/

# =======
# Cleanup
# =======

RUN apk del build-deps \
&& rm -rf /var/cache/apk/*
RUN apk del .build-deps \
&& rm -rf /var/cache/apk/* \
&& rm -rf /tmp/jans \
&& rm -rf /tmp/flex

# =======
# License
Expand Down Expand Up @@ -173,7 +223,7 @@ RUN mkdir -p /etc/certs \
COPY jetty/casa.xml ${JETTY_BASE}/casa/webapps/
COPY jetty/log4j2.xml ${JETTY_BASE}/casa/resources/
COPY jetty/casa_web_resources.xml ${JETTY_BASE}/casa/webapps/
COPY templates /app/templates/
COPY conf/*.tmpl /app/templates/
COPY scripts /app/scripts
RUN chmod +x /app/scripts/entrypoint.sh

Expand Down
File renamed without changes.
3 changes: 1 addition & 2 deletions docker-casa/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
ldif==4.1.1
webdavclient3>=3.14.5
libcst<0.4
# pinned to py3-grpcio version to avoid failure on native extension build
grpcio==1.41.0
git+https://github.com/JanssenProject/jans@878bd69b3ac75f0b9455d4bac85063054189b3ad#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
git+https://github.com/JanssenProject/jans@f2e653ef917efd017195f2330b64e64c333f4699#egg=jans-pycloudlib&subdirectory=jans-pycloudlib
119 changes: 119 additions & 0 deletions docker-casa/scripts/bootstrap.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import contextlib
import json
import logging.config
import os
import re
from uuid import uuid4
from string import Template
from functools import cached_property

from jans.pycloudlib import get_manager
from jans.pycloudlib.persistence import render_couchbase_properties
Expand All @@ -14,7 +17,16 @@
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 import CouchbaseClient
from jans.pycloudlib.persistence import LdapClient
from jans.pycloudlib.persistence import SpannerClient
from jans.pycloudlib.persistence import SqlClient
from jans.pycloudlib.persistence import doc_id_from_dn
from jans.pycloudlib.persistence import id_from_dn
from jans.pycloudlib.utils import cert_to_truststore
from jans.pycloudlib.utils import get_random_chars
from jans.pycloudlib.utils import encode_text
from jans.pycloudlib.utils import generate_base64_contents

from settings import LOGGING_CONFIG

Expand Down Expand Up @@ -176,6 +188,113 @@ def main():
modify_webdefault_xml()
configure_logging()

persistence_setup = PersistenceSetup(manager)
persistence_setup.import_ldif_files()


class PersistenceSetup:
def __init__(self, manager):
self.manager = manager

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

# determine persistence type
self.persistence_type = os.environ.get("CN_PERSISTENCE_TYPE", "ldap")
ldap_mapping = os.environ.get("CN_PERSISTENCE_LDAP_MAPPING", "default")

if self.persistence_type == "hybrid":
if ldap_mapping == "default":
client_cls = LdapClient
self.persistence_type = "ldap"
else:
client_cls = CouchbaseClient
self.persistence_type = "couchbase"

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

@cached_property
def ctx(self):
hostname = self.manager.config.get("hostname")

ctx = {
"hostname": hostname,
"casa_redirect_uri": f"https://{hostname}/casa",
"casa_redirect_logout_uri": f"https://{hostname}/casa/bye.zul",
"casa_frontchannel_logout_uri": f"https://{hostname}/casa/autologout",
}

with open("/app/static/extension/person_authentication/Casa.py") as f:
ctx["casa_person_authentication_script"] = generate_base64_contents(f.read())

# Casa client
ctx["casa_client_id"] = self.manager.config.get("casa_client_id")
if not ctx["casa_client_id"]:
ctx["casa_client_id"] = f"1902.{uuid4()}"
self.manager.config.set("casa_client_id", ctx["casa_client_id"])

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

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

# finalized contexts
return ctx

@cached_property
def ldif_files(self):
filenames = ["casa_config.ldif", "casa_client.ldif"]
# add casa_person_authentication_script.ldif if there's no existing casa script in persistence to avoid error
# java.lang.IllegalStateException: Duplicate key casa (attempted merging values 1 and 1)
if not self._deprecated_script_exists():
filenames.append("casa_person_authentication_script.ldif")
return [f"/app/templates/{filename}" for filename in filenames]

def _deprecated_script_exists(self):
script_exists = False

# deprecated Casa script DN
id_ = "inum=BABA-CACA,ou=scripts,o=jans"

# sql and spanner
if self.persistence_type in ("sql", "spanner"):
script_exists = bool(self.client.get("jansCustomScr", doc_id_from_dn(id_)))

# couchbase
elif self.persistence_type == "couchbase":
bucket = os.environ.get("CN_COUCHBASE_BUCKET_PREFIX", "jans")
key = id_from_dn(id_)
req = self.client.exec_query(
f"SELECT META().id, {bucket}.* FROM {bucket} USE KEYS '{key}'"
)
with contextlib.suppress(IndexError):
entry = req.json()["results"][0]
script_exists = bool(entry["id"])

# ldap
else:
script_exists = bool(self.client.get(id_))

return script_exists

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


if __name__ == "__main__":
main()