From d9a0de1c688d530daf6dfdeaf2f7bbf586e7fc41 Mon Sep 17 00:00:00 2001 From: pedro Date: Wed, 8 Jan 2025 22:34:34 +0100 Subject: [PATCH 1/3] add env var ENABLE_DOMAIN_CHECKER when using localhost and standalone idhub instance we could avoid this checker to facilitate testing and deployment --- idhub/mixins.py | 4 ++-- trustchain_idhub/settings.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/idhub/mixins.py b/idhub/mixins.py index 055f867..ab7cafa 100644 --- a/idhub/mixins.py +++ b/idhub/mixins.py @@ -33,7 +33,7 @@ class UserView(LoginRequiredMixin): ] def get(self, request, *args, **kwargs): - if not settings.DEVELOPMENT: + if settings.ENABLE_DOMAIN_CHECKER: err_txt = "User domain is {} which does not match server domain {}".format( request.get_host(), settings.DOMAIN ) @@ -56,7 +56,7 @@ class UserView(LoginRequiredMixin): return url or response def post(self, request, *args, **kwargs): - if not settings.DEVELOPMENT: + if settings.ENABLE_DOMAIN_CHECKER: err_txt = "User domain is {} which does not match server domain {}".format( request.get_host(), settings.DOMAIN ) diff --git a/trustchain_idhub/settings.py b/trustchain_idhub/settings.py index 7610a49..01da39c 100644 --- a/trustchain_idhub/settings.py +++ b/trustchain_idhub/settings.py @@ -241,5 +241,6 @@ OIDC_ORGS = config('OIDC_ORGS', '') ENABLE_EMAIL = config('ENABLE_EMAIL', default=True, cast=bool) CREATE_TEST_USERS = config('CREATE_TEST_USERS', default=False, cast=bool) ENABLE_2FACTOR_AUTH = config('ENABLE_2FACTOR_AUTH', default=True, cast=bool) +ENABLE_DOMAIN_CHECKER = config('ENABLE_DOMAIN_CHECKER', default=True, cast=bool) COMMIT = config('COMMIT', default='') -- 2.30.2 From 6e4f3d7be3266e45d6993d09015e5d69c67e68d6 Mon Sep 17 00:00:00 2001 From: pedro Date: Wed, 8 Jan 2025 22:35:05 +0100 Subject: [PATCH 2/3] bugfix requirement error error was ``` idhub-1 | ValueError: numpy.dtype size changed, may indicate binary incompatibility. Expected 96 from C header, got 88 from PyObject idhub-1 exited with code 1 ``` > The solution is to pin down the numpy version to any before the 2.0.0 related https://stackoverflow.com/questions/78634235/numpy-dtype-size-changed-may-indicate-binary-incompatibility-expected-96-from --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 0a75cdd..78e85b1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,6 +6,7 @@ black==23.9.1 python-decouple==3.8 jsonschema[format]==4.19.1 pandas==2.1.1 +numpy>=1.21,<2.0 xlrd==2.0.1 odfpy==1.4.1 requests==2.31.0 -- 2.30.2 From 6f9a06faa15eaef3ee7ec14eb41c590162f00241 Mon Sep 17 00:00:00 2001 From: pedro Date: Wed, 8 Jan 2025 22:37:14 +0100 Subject: [PATCH 3/3] add docker integration for localhost --- .env.example | 34 +++++++++ docker-compose.yml | 33 +++++++++ docker-reset.sh | 35 ++++++++++ docker/idhub.Dockerfile | 34 +++++++++ docker/idhub.entrypoint.sh | 139 +++++++++++++++++++++++++++++++++++++ 5 files changed, 275 insertions(+) create mode 100644 .env.example create mode 100644 docker-compose.yml create mode 100755 docker-reset.sh create mode 100644 docker/idhub.Dockerfile create mode 100755 docker/idhub.entrypoint.sh diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..6474d34 --- /dev/null +++ b/.env.example @@ -0,0 +1,34 @@ +# IDHUB +#### + +IDHUB_DOMAIN=localhost +IDHUB_ALLOWED_HOSTS=${IDHUB_DOMAIN},${IDHUB_DOMAIN}:9001,127.0.0.1,127.0.0.1:9001 +IDHUB_TIME_ZONE='Europe/Madrid' +#IDHUB_SECRET_KEY='uncomment-it-and-fill-this' +# enable dev flags when DEVELOPMENT deployment +# adapt to your domain in a production/reverse proxy env +IDHUB_CSRF_TRUSTED_ORIGINS='https://idhub.example.org' + +# fill this section with your email credentials +IDHUB_DEFAULT_FROM_EMAIL="user@example.org" +IDHUB_EMAIL_HOST="smtp.example.org" +IDHUB_EMAIL_HOST_USER="smtp_user" +IDHUB_EMAIL_HOST_PASSWORD="smtp_passwd" +IDHUB_EMAIL_PORT=25 +IDHUB_EMAIL_USE_TLS=True +IDHUB_EMAIL_BACKEND="django.core.mail.backends.smtp.EmailBackend" + +# replace with production data +# this is used when IDHUB_DEPLOYMENT is not equal to DEVELOPMENT +IDHUB_ADMIN_USER='admin' +IDHUB_ADMIN_PASSWD='admin' +IDHUB_ADMIN_EMAIL='admin@example.org' + +# this option needs to be set to 'n' to be able to make work idhub in docker +# by default it is set to 'y' to facilitate idhub dev when outside docker +IDHUB_SYNC_ORG_DEV='n' + +# TODO that is only for testing +IDHUB_ENABLE_EMAIL=false +IDHUB_ENABLE_2FACTOR_AUTH=false +IDHUB_ENABLE_DOMAIN_CHECKER=false diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..b7d941e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,33 @@ +services: + + idhub: + init: true + build: + dockerfile: docker/idhub.Dockerfile + environment: + - DOMAIN=${IDHUB_DOMAIN:-localhost} + - ALLOWED_HOSTS=${IDHUB_ALLOWED_HOSTS:-$IDHUB_DOMAIN} + - DEBUG=true + - INITIAL_ADMIN_EMAIL=${IDHUB_ADMIN_EMAIL} + - INITIAL_ADMIN_PASSWORD=${IDHUB_ADMIN_PASSWD} + - CREATE_TEST_USERS=true + - ENABLE_EMAIL=${IDHUB_ENABLE_EMAIL:-true} + - ENABLE_2FACTOR_AUTH=${IDHUB_ENABLE_2FACTOR_AUTH:-true} + - ENABLE_DOMAIN_CHECKER=${IDHUB_ENABLE_DOMAIN_CHECKER:-true} + - SECRET_KEY=${IDHUB_SECRET_KEY:-publicsecretisnotsecureVtmKBfxpVV47PpBCF2Nzz2H6qnbd} + - STATIC_ROOT=${IDHUB_STATIC_ROOT:-/static/} + - MEDIA_ROOT=${IDHUB_MEDIA_ROOT:-/media/} + - PORT=${IDHUB_PORT:-9001} + - DEFAULT_FROM_EMAIL=${IDHUB_DEFAULT_FROM_EMAIL} + - EMAIL_HOST=${IDHUB_EMAIL_HOST} + - EMAIL_HOST_USER=${IDHUB_EMAIL_HOST_USER} + - EMAIL_HOST_PASSWORD=${IDHUB_EMAIL_HOST_PASSWORD} + - EMAIL_PORT=${IDHUB_EMAIL_PORT} + - EMAIL_USE_TLS=${IDHUB_EMAIL_USE_TLS} + - EMAIL_BACKEND=${IDHUB_EMAIL_BACKEND} + - SUPPORTED_CREDENTIALS=['CourseCredential', 'EOperatorClaim', 'FederationMembership', 'FinancialVulnerabilityCredential', 'MembershipCard'] + - SYNC_ORG_DEV=${IDHUB_SYNC_ORG_DEV} + ports: + - 9001:9001 + volumes: + - .:/opt/idhub diff --git a/docker-reset.sh b/docker-reset.sh new file mode 100755 index 0000000..6d1b3f9 --- /dev/null +++ b/docker-reset.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +# SPDX-License-Identifier: AGPL-3.0-or-later + +set -e +set -u +# DEBUG +set -x + +main() { + cd "$(dirname "${0}")" + + rm -fv ./db.sqlite3 + if [ ! -f .env ]; then + cp -v .env.example .env + echo "WARNING: .env was not there, .env.example was copied, this only happens once" + fi + + docker compose down -v + docker compose build + docker compose up ${detach_arg:-} + + # TODO docker registry + #project=dkr-dsg.ac.upc.edu/trustchain-oc1-orchestral + #idhub_image=${project}/idhub:${idhub_tag} + #idhub_branch=$(git -C IdHub branch --show-current) + # docker build -f docker/idhub.Dockerfile -t ${idhub_image} -t ${project}/idhub:${idhub_branch}__latest . + #docker tag hello-world:latest farga.pangea.org/pedro/test/hello-world + #docker push farga.pangea.org/pedro/test/hello-world:latest +} + +main "${@}" + +# written in emacs +# -*- mode: shell-scrip; -*-t diff --git a/docker/idhub.Dockerfile b/docker/idhub.Dockerfile new file mode 100644 index 0000000..f1cb831 --- /dev/null +++ b/docker/idhub.Dockerfile @@ -0,0 +1,34 @@ +FROM python:3.11.7-slim-bookworm + +# last line is dependencies for weasyprint (for generating pdfs in lafede pilot) https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#debian-11 +RUN apt update && \ + apt-get install -y \ + git \ + sqlite3 \ + jq \ + libpango-1.0-0 libpangoft2-1.0-0 \ + && pip install cffi brotli \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /opt/idhub + +# reduce size (python specifics) -> src https://stackoverflow.com/questions/74616667/removing-pip-cache-after-installing-dependencies-in-docker-image +ENV PYTHONDONTWRITEBYTECODE=1 +# here document in dockerfile src https://stackoverflow.com/questions/40359282/launch-a-cat-command-unix-into-dockerfile +RUN cat > /etc/pip.conf < status_data <&2 + ./manage.py initial_datas + + if [ "${OIDC_ORGS:-}" ]; then + config_oidc4vp + else + echo "Note: skipping oidc4vp config" + fi + fi +} + +_set() { + key="${1}" + value="${2}" + domain="${3}" + sqlite3 db.sqlite3 "update oidc4vp_organization set ${key}='${value}' where domain='${domain}';" +} + +_get() { + sqlite3 -json db.sqlite3 "select * from oidc4vp_organization;" +} + +_lines () { + local myfile="${1}" + cat "${myfile}" | wc -l +} + +config_oidc4vp() { + # populate your config + data="$(_get)" + echo "${data}" | jq --arg domain "${DOMAIN}" '{ ($domain): .}' > /sharedsecret/${DOMAIN} + + while true; do + echo wait the other idhubs to write, this is the only oportunity to sync with other idhubs in the docker compose + ## break when no empty files left + if ! wc -l /sharedsecret/* | awk '{print $1;}' | grep -qE '^0$'; then + break + fi + sleep 1 + done + # get other configs + for host in /sharedsecret/*; do + # we are flexible on querying for DOMAIN: the first one based on regex + target_domain="$(cat "${host}" | jq -r 'keys[0]')" + if [ "${target_domain}" != "${DOMAIN}" ]; then + filtered_data="$(cat "${host}" | jq --arg domain "${DOMAIN}" 'first(.[][] | select(.domain | test ($domain)))')" + client_id="$(echo "${filtered_data}" | jq -r '.client_id')" + client_secret="$(echo "${filtered_data}" | jq -r '.client_secret')" + + _set my_client_id ${client_id} ${target_domain} + _set my_client_secret ${client_secret} ${target_domain} + fi + done +} + +runserver() { + PORT="${PORT:-8000}" + if [ ! "${DEBUG:-}" = "true" ]; then + ./manage.py collectstatic + if [ "${EXPERIMENTAL:-}" = "true" ]; then + # reloading on source code changing is a debugging future, maybe better then use debug + # src https://stackoverflow.com/questions/12773763/gunicorn-autoreload-on-source-change/24893069#24893069 + # gunicorn with 1 worker, with more than 1 worker this is not expected to work + gunicorn --access-logfile - --error-logfile - -b :${PORT} trustchain_idhub.wsgi:application + else + ./manage.py runserver 0.0.0.0:${PORT} + fi + else + ./manage.py runserver 0.0.0.0:${PORT} + fi +} + +check_app_is_there() { + if [ ! -f "./manage.py" ]; then + usage + fi +} + +main() { + idhub_dir='/opt/idhub' + cd "${idhub_dir}" + + check_app_is_there + + deployment_strategy + + inject_env_vars + + runserver +} + +main "${@}" -- 2.30.2