diff --git a/SAS/TMSS/bin/tmss b/SAS/TMSS/bin/tmss index d3cc71d890adbfb1117af6eb8d32aa5ccf330ac1..d96fd3b05568f7f6c1017473f25ce0889a564f99 100755 --- a/SAS/TMSS/bin/tmss +++ b/SAS/TMSS/bin/tmss @@ -21,7 +21,7 @@ # Startup script for the development TMSS server #defaults -PORT=8000 +PORT=8008 CREDENTIALS="tmss" # Parse args: diff --git a/SAS/TMSS/docker/tmss-testenv/docker-compose.yml b/SAS/TMSS/docker/tmss-testenv/docker-compose.yml index 8cd3fcfbad06e52252ed2fcaf5f434508dd18564..a0aff9ea3abb8d5d73918ad6015defefb1fe6c47 100644 --- a/SAS/TMSS/docker/tmss-testenv/docker-compose.yml +++ b/SAS/TMSS/docker/tmss-testenv/docker-compose.yml @@ -6,13 +6,13 @@ services: dockerfile: tmss_testenv_Dockerfile container_name: tmss_test ports: - - "8000:8000" - - "3000:3000" + - "8008:8008" + - "3003:3003" tmss_test_nginx: build: context: . dockerfile: tmss_nginx_Dockerfile container_name: tmss_test_nginx ports: - - "5000:5000" + - "5005:5005" diff --git a/SAS/TMSS/docker/tmss-testenv/nginx.conf b/SAS/TMSS/docker/tmss-testenv/nginx.conf index ec3ceff56aeab6b4e93e705cebf7d3e2ca4379cc..66d9a68ca353a00841ade2a9273ac7c607648007 100644 --- a/SAS/TMSS/docker/tmss-testenv/nginx.conf +++ b/SAS/TMSS/docker/tmss-testenv/nginx.conf @@ -2,7 +2,7 @@ events {} http { server { - listen 5000; + listen 5005; proxy_http_version 1.1; proxy_set_header Host $http_host; @@ -18,22 +18,27 @@ http { } location @api_proxy { - proxy_pass http://tmss_test:8000$uri; + proxy_pass http://tmss_test:8008$uri; proxy_intercept_errors on; recursive_error_pages on; error_page 404 = @frontend_proxy; } location @frontend_proxy { - proxy_pass http://tmss_test:3000$uri; + proxy_pass http://tmss_test:3003$uri; } location /api/ { - proxy_pass http://tmss_test:8000; + proxy_pass http://tmss_test:8008; } location /frontend/ { - proxy_pass http://tmss_test:3000; + proxy_pass http://tmss_test:3003; } + + location /oidc/ { + proxy_pass http://tmss_test:8008; + } + } } \ No newline at end of file diff --git a/SAS/TMSS/docker/tmss-testenv/tmss_testenv_Dockerfile b/SAS/TMSS/docker/tmss-testenv/tmss_testenv_Dockerfile index 99d01469505b5a4bbbc8312e747638e25a03d860..ba62c365dbb69387bafafb05e967faf607e0ac0f 100644 --- a/SAS/TMSS/docker/tmss-testenv/tmss_testenv_Dockerfile +++ b/SAS/TMSS/docker/tmss-testenv/tmss_testenv_Dockerfile @@ -14,14 +14,14 @@ RUN yum -y groupinstall 'Development Tools' && \ RUN echo "Installing packages for TMSS..." && \ yum -y install https://download.postgresql.org/pub/repos/yum/9.4/redhat/rhel-7-x86_64/pgdg-centos94-9.4-3.noarch.rpm && \ yum -y install postgresql94-devel openldap-devel postgresql94-server which && \ - pip3 install django-filter django-auth-ldap coreapi python-ldap-test django-jsonforms django-json-widget "git+git://github.com/nnseva/django-jsoneditor.git" psycopg2-binary markdown ldap3 drf-yasg flex swagger-spec-validator testing.postgresql + pip3 install django-filter django-auth-ldap coreapi python-ldap-test django-jsonforms django-json-widget "git+git://github.com/nnseva/django-jsoneditor.git" psycopg2-binary markdown ldap3 drf-yasg flex swagger-spec-validator testing.postgresql mozilla_django_oidc ENV PATH=$PATH:/usr/pgsql-9.4/bin/ RUN echo "Checking out code base" && \ git clone https://git.astron.nl/ro/lofar.git && \ cd lofar && \ - git checkout master && \ + git checkout TMSS-134 && \ . CMake/gen_LofarPackageList_cmake.sh && \ PACKAGE=TMSS && \ VARIANT=gnucxx11_opt && \ @@ -62,7 +62,7 @@ ENTRYPOINT /bin/bash -c 'export VARIANT=gnucxx11_opt; \ sleep 15 && \ tmss & \ cd /lofar/build/gnucxx11_opt/installed/share/www && \ - serve -s . -p 3000' + serve -s . -p 3003' # It also works to serve the dev server for interactive development as such: # cd /lofar/build/gnucxx11_opt/SAS/TMSS/frontend/frontend_poc && \ diff --git a/SAS/TMSS/frontend/frontend_poc/CMakeLists.txt b/SAS/TMSS/frontend/frontend_poc/CMakeLists.txt index ea46d4e1f1d4156bcc94b54dbdf356630641f630..8d54d6e333c1ef15dea6f37c22121de0d3327785 100644 --- a/SAS/TMSS/frontend/frontend_poc/CMakeLists.txt +++ b/SAS/TMSS/frontend/frontend_poc/CMakeLists.txt @@ -1,4 +1,4 @@ include(NPMInstall) -message(WARNING "disabled npm_install, because it currently fails to build. FIX THIS, or remove it.") -#npm_install(package.json PUBLIC public SOURCE src DESTINATION share/www) +#message(WARNING "disabled npm_install, because it currently fails to build. FIX THIS, or remove it.") +npm_install(package.json PUBLIC public SOURCE src DESTINATION share/www) diff --git a/SAS/TMSS/src/remakemigrations.py b/SAS/TMSS/src/remakemigrations.py index 015794aac00b3b4d6890e23f8cc402ef008d330e..9decd35f5d7e8d193060f2528c332df7bedd8a61 100755 --- a/SAS/TMSS/src/remakemigrations.py +++ b/SAS/TMSS/src/remakemigrations.py @@ -41,7 +41,7 @@ def delete_old_migrations(): for f in [path for path in files if ("auto" in path or "populate" in path)]: logger.info('Deleting: %s' % f) os.remove(f) - execute_and_log('svn rm %s' % f) + execute_and_log('git rm %s' % f) def make_django_migrations(): @@ -80,7 +80,7 @@ def put_migrations_under_version_control(): logger.info('Putting migrations under version control...') files = glob_migrations() for f in files: - execute_and_log('svn add %s' % f) + execute_and_log('git add %s' % f) def remake_migrations(): @@ -98,4 +98,4 @@ if __name__ == "__main__": handler.setLevel(logging.INFO) logger.addHandler(handler) - remake_migrations() \ No newline at end of file + remake_migrations() diff --git a/SAS/TMSS/src/templates/rest_framework/api.html b/SAS/TMSS/src/templates/rest_framework/api.html index 1224623e4a7ba3b2beb17b306cd5dfc0d9a9cf33..36a74512e955026bed46b1785651d0632f2df408 100644 --- a/SAS/TMSS/src/templates/rest_framework/api.html +++ b/SAS/TMSS/src/templates/rest_framework/api.html @@ -4,4 +4,15 @@ <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootswatch/3.3.7/yeti/bootstrap.min.css" type="text/css"> {% endblock %} -{% block bootstrap_navbar_variant %}{% endblock %} \ No newline at end of file +{% block bootstrap_navbar_variant %}{% endblock %} + + +{% block userlinks %} + {% if request.user.is_authenticated %} + <p>Current user: {{ request.user.email }}</p> + {% else %} + <a href="{% url 'oidc_authentication_init' %}">Login</a> + {% endif %} +{% endblock %} + + diff --git a/SAS/TMSS/src/tmss/settings.py b/SAS/TMSS/src/tmss/settings.py index 046f8de35906fd6d5c5753625ee5a4c04de7f1aa..a734abb34c175c2bcdc7f872045cbd95cf1e6ad0 100644 --- a/SAS/TMSS/src/tmss/settings.py +++ b/SAS/TMSS/src/tmss/settings.py @@ -18,8 +18,54 @@ from lofar.common import dbcredentials # logger logger = logging.getLogger('django_auth_ldap') logger.addHandler(logging.StreamHandler()) -logger.setLevel(logging.INFO) - +logger.setLevel(logging.DEBUG) + +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse', + }, + 'require_debug_true': { + '()': 'django.utils.log.RequireDebugTrue', + }, + }, + 'formatters': { + 'django.server': { + '()': 'django.utils.log.ServerFormatter', + 'format': '[%(server_time)s] %(message)s', + }, + }, + 'handlers': { + 'console': { + 'level': 'DEBUG', + 'filters': ['require_debug_true'], + 'class': 'logging.StreamHandler', + }, + 'django.server': { + 'level': 'DEBUG', + 'class': 'logging.StreamHandler', + 'formatter': 'django.server', + }, + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler' + }, + }, + 'loggers': { + 'django': { + 'handlers': ['console', 'mail_admins'], + 'level': 'DEBUG', + }, + 'django.server': { + 'handlers': ['django.server'], + 'level': 'DEBUG', + 'propagate': False, + }, + } +} # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -55,6 +101,7 @@ INSTALLED_APPS = [ 'jsoneditor', 'drf_yasg', 'django_filters', + 'mozilla_django_oidc', # Load after auth ] MIDDLEWARE = [ @@ -65,6 +112,7 @@ MIDDLEWARE = [ 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'mozilla_django_oidc.middleware.SessionRefresh', ] ROOT_URLCONF = 'tmss.urls' @@ -127,8 +175,9 @@ DATABASES = { REST_FRAMEWORK = { # Authentication 'DEFAULT_AUTHENTICATION_CLASSES': ( - 'rest_framework.authentication.BasicAuthentication', + 'mozilla_django_oidc.contrib.drf.OIDCAuthentication', 'rest_framework.authentication.SessionAuthentication', + #'rest_framework.authentication.BasicAuthentication', ), 'DEFAULT_PERMISSION_CLASSES': [ #'rest_framework.permissions.AllowAny', @@ -171,8 +220,34 @@ AUTH_LDAP_USER_ATTR_MAP = { "email": "mail" } +# OPEN-ID CONNECT + +OIDC_DRF_AUTH_BACKEND = 'mozilla_django_oidc.auth.OIDCAuthenticationBackend' + +# For talking to PYOP Identity Provider: +#OIDC_VERIFY_SSL = False # TODO: Remove for production! +#OIDC_RP_CLIENT_ID = os.environ.get('OIDC_RP_CLIENT_ID', 'a0PF52uaIQxu') # Secret, do not put real credentials on Git +#OIDC_RP_CLIENT_SECRET = os.environ.get('OIDC_RP_CLIENT_SECRET', '93863d5aad044c0baaf1f0021b2542db') # Secret, do not put real credentials on Git +#OIDC_OP_AUTHORIZATION_ENDPOINT = "https://localhost:9090/authentication" +#OIDC_OP_TOKEN_ENDPOINT = "https://localhost:9090/token" +#OIDC_OP_USER_ENDPOINT = "https://localhost:9090/userinfo" + + +# For talking to Mozilla Identity Provider: +OIDC_RP_CLIENT_ID = os.environ.get('OIDC_RP_CLIENT_ID', '1') # Secret, do not put real credentials on Git +OIDC_RP_CLIENT_SECRET = os.environ.get('OIDC_RP_CLIENT_SECRET', 'secret') # Secret, do not put real credentials on Git +OIDC_OP_AUTHORIZATION_ENDPOINT="http://localhost:8088/openid/authorize" +OIDC_OP_TOKEN_ENDPOINT="http://localhost:8088/openid/token" +OIDC_OP_USER_ENDPOINT="http://localhost:8088/openid/userinfo" + +LOGIN_REDIRECT_URL = "/api/" +LOGIN_REDIRECT_URL_FAILURE = "/api/" +LOGOUT_REDIRECT_URL = "/api/" +LOGOUT_REDIRECT_URL_FAILURE = "/api/" + AUTHENTICATION_BACKENDS = ( - 'django_auth_ldap.backend.LDAPBackend', + #'django_auth_ldap.backend.LDAPBackend', + 'mozilla_django_oidc.auth.OIDCAuthenticationBackend', 'django.contrib.auth.backends.ModelBackend', ) diff --git a/SAS/TMSS/src/tmss/tmssapp/migrations/0002_auto_20190606_1535.py b/SAS/TMSS/src/tmss/tmssapp/migrations/0002_auto_20200123_1057.py similarity index 98% rename from SAS/TMSS/src/tmss/tmssapp/migrations/0002_auto_20190606_1535.py rename to SAS/TMSS/src/tmss/tmssapp/migrations/0002_auto_20200123_1057.py index 33a161265deb650b743573fd7a853f29be6cb01e..1bccdfe6ac7fbf01c71031f992938c4e25aca38d 100644 --- a/SAS/TMSS/src/tmss/tmssapp/migrations/0002_auto_20190606_1535.py +++ b/SAS/TMSS/src/tmss/tmssapp/migrations/0002_auto_20200123_1057.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.6 on 2019-06-06 15:35 +# Generated by Django 2.0.6 on 2020-01-23 10:57 import django.contrib.postgres.fields import django.contrib.postgres.fields.jsonb @@ -864,70 +864,70 @@ class Migration(migrations.Migration): ), migrations.AddIndex( model_name='taskrelationdraft', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_tas_tags_0c3200_gin'), + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_tas_tags_aeef84_gin'), ), migrations.AddIndex( model_name='taskrelationblueprint', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_tas_tags_3c4525_gin'), + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_tas_tags_256437_gin'), ), migrations.AddIndex( model_name='taskconnectors', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_tas_tags_e164c1_gin'), + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_tas_tags_0ebd6d_gin'), ), migrations.AddIndex( model_name='subtaskoutput', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_sub_tags_cf41ca_gin'), + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_sub_tags_e25b4c_gin'), ), migrations.AddIndex( model_name='subtaskinput', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_sub_tags_aca69a_gin'), + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_sub_tags_fb9960_gin'), ), migrations.AddIndex( model_name='subtaskconnector', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_sub_tags_e6cfc0_gin'), + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_sub_tags_60e299_gin'), ), migrations.AddIndex( model_name='subtask', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_sub_tags_ffd87d_gin'), + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_sub_tags_d2fc43_gin'), ), migrations.AddIndex( model_name='defaultworkrelationselectiontemplate', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_eef600_gin'), + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_b652d9_gin'), ), migrations.AddIndex( model_name='defaulttasktemplate', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_ad763c_gin'), + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_c88200_gin'), ), migrations.AddIndex( model_name='defaultsubtasktemplate', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_f7ca32_gin'), + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_e9c73d_gin'), ), migrations.AddIndex( model_name='defaultschedulingunittemplate', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_c3916a_gin'), + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_3ab2d6_gin'), ), migrations.AddIndex( model_name='defaultgeneratortemplate', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_2b9ef8_gin'), + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_89c89d_gin'), ), migrations.AddIndex( model_name='defaultdataproductspecificationstemplate', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_0a7453_gin'), + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_269b1f_gin'), ), migrations.AddIndex( model_name='dataproducttransform', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_dat_tags_e9dc5f_gin'), + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_dat_tags_380c1f_gin'), ), migrations.AddIndex( model_name='dataproducthash', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_dat_tags_1712df_gin'), + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_dat_tags_dae145_gin'), ), migrations.AddIndex( model_name='dataproductarchiveinfo', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_dat_tags_7f581b_gin'), + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_dat_tags_ebf2ef_gin'), ), migrations.AddIndex( model_name='dataproduct', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_dat_tags_567f63_gin'), + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_dat_tags_5932a3_gin'), ), ] diff --git a/SAS/TMSS/src/tmss/tmssapp/migrations/0003_populate.py b/SAS/TMSS/src/tmss/tmssapp/migrations/0003_populate.py index 7dbb6053394aa14a436f508a58abec3dfd5251bd..8fcea39a130ebe08b53939653c6465d3343d71d5 100644 --- a/SAS/TMSS/src/tmss/tmssapp/migrations/0003_populate.py +++ b/SAS/TMSS/src/tmss/tmssapp/migrations/0003_populate.py @@ -6,7 +6,7 @@ from ..populate import * class Migration(migrations.Migration): dependencies = [ - ('tmssapp', '0002_auto_20190606_1535'), + ('tmssapp', '0002_auto_20200123_1057'), ] operations = [ migrations.RunPython(populate_choices) ] diff --git a/SAS/TMSS/src/tmss/urls.py b/SAS/TMSS/src/tmss/urls.py index c96864991dd29a38fa6b9ed385f1288f6684a14d..fd80e0ea5a09c91653c7fb3148b134a048ae3f9c 100644 --- a/SAS/TMSS/src/tmss/urls.py +++ b/SAS/TMSS/src/tmss/urls.py @@ -15,6 +15,7 @@ Including another URLconf """ from django.contrib import admin +from django.contrib.auth.views import LoginView, LogoutView from django.urls import path, re_path from django.conf.urls import url, include from django.views.generic.base import TemplateView @@ -25,6 +26,7 @@ from rest_framework.documentation import include_docs_urls from drf_yasg.views import get_schema_view from drf_yasg import openapi + # # Django style patterns # @@ -46,6 +48,7 @@ swagger_schema_view = get_schema_view( urlpatterns = [ path('admin/', admin.site.urls), + path('logout/', LogoutView.as_view(), name='logout'), path('docs/', include_docs_urls(title='TMSS API')), re_path(r'^swagger(?P<format>\.json|\.yaml)$', swagger_schema_view.without_ui(cache_timeout=0), name='schema-json'), path('swagger/', swagger_schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), @@ -145,4 +148,4 @@ router.register(r'task_blueprint_C', viewsets.TaskBlueprintViewSetJSONeditorOnli urlpatterns.extend(router.urls) # prefix everything for proxy -urlpatterns = [url(r'^api/', include(urlpatterns))] \ No newline at end of file +urlpatterns = [url(r'^api/', include(urlpatterns)), url(r'^oidc/', include('mozilla_django_oidc.urls')),] \ No newline at end of file diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/.circleci/config.yml b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/.circleci/config.yml new file mode 100644 index 0000000000000000000000000000000000000000..7c2b7c3c55992eb980b14c96eaa1a879ef170369 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/.circleci/config.yml @@ -0,0 +1,100 @@ +# Python CircleCI 2.0 configuration file +# +# Check https://circleci.com/docs/2.0/language-python/ for more details +# +version: 2 +jobs: + build: + docker: + - image: mozilla/cidockerbases:docker-latest + working_directory: / + + steps: + - run: + name: Get info + command: uname -v + + - setup_remote_docker + + - run: + name: Get info + command: docker info + + - run: + name: Install essential packages + command: apt-get install make + + - checkout: + path: /oidc_testprovider + + - run: + name: Build Docker images + working_directory: /oidc_testprovider + command: | + make build + + - run: + name: Push to Dockerhub on tag + working_directory: /oidc_testprovider + command: | + function retry { + set +e + local n=0 + local max=3 + while true; do + "$@" && break || { + if [[ $n -lt $max ]]; then + ((n++)) + echo "Command failed. Attempt $n/$max:" + else + echo "Failed after $n attempts." + exit 1 + fi + } + done + set -e + } + + # Namespace on dockerhub to push: + # https://hub.docker.com/u/mozilla/oidc-testprovider + export DOCKER_NAMESPACE=mozilla/oidc-testprovider + export IMAGES=(oidc_e2e_setup_py2 oidc_e2e_setup_py3 oidc_testprovider oidc_testrp_py2 oidc_testrp_py3 oidc_testrunner) + + # If a tag was pushed to github, push tagged images and latest + # images to Dockerhub + if [ -n "${CIRCLE_TAG}" ]; then + # Log into Dockerhub + echo "${DOCKER_PASS}" | docker login -u="${DOCKER_USER}" --password-stdin + + for IMAGE in "${IMAGES[@]}" + do + echo "" + echo ">>> WORKING ON ${IMAGE}..." + echo "" + # Tag and push tagged image. + retry docker tag "${IMAGE}:latest" "${DOCKER_NAMESPACE}:${IMAGE}-${CIRCLE_TAG}" + retry docker push "${DOCKER_NAMESPACE}:${IMAGE}-${CIRCLE_TAG}" + + # Tag and push latest image. + retry docker tag "${IMAGE}:latest" "${DOCKER_NAMESPACE}:${IMAGE}-latest" + retry docker push "${DOCKER_NAMESPACE}:${IMAGE}-latest" + done + fi + +workflows: + version: 2 + + # workflow jobs are _not_ run in tag builds by default + # we use filters to whitelist jobs that should be run for tags + + # workflow jobs are run in _all_ branch builds by default + # we use filters to blacklist jobs that shouldn't be run for a branch + + # see: https://circleci.com/docs/2.0/workflows/#git-tag-job-execution + + build-test-push: + jobs: + - build: + filters: + tags: + only: /.*/ diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/HISTORY.md b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/HISTORY.md new file mode 100644 index 0000000000000000000000000000000000000000..4d8d62422483fd93d04159b64dcc376cec4ae539 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/HISTORY.md @@ -0,0 +1,35 @@ +HISTORY +======= + +v0.9.3 (October 23rd, 2019) +--------------------------- + +Bugs: + +* fix docker push code + + +v0.9.2 (October 22nd, 2019) +--------------------------- + +No substantive changes. Doing a new tag so as to push images to dockerhub. + + +v0.9.1 (October 22nd, 2019) +--------------------------- + +Bugs: + +* fix `build` and `pull` rules in Makefile to use the correct tags + + +v0.9.0 (October 22nd, 2019) +--------------------------- + +First tagged release. + +Features: + +* new `createuser` command in `oidc_testprovider` image +* redid how images are tagged and we're now pushing them to dockerhub + in the `mozilla` user diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/Makefile b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..091744b79538494207e8499c5d2ab1d9a57d49d4 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/Makefile @@ -0,0 +1,33 @@ +DEFAULT_GOAL := help + +NS ?= mozilla/oidc-testprovider +IMAGES := oidc_testprovider oidc_testrunner oidc_testrp_py2 oidc_testrp_py3 oidc_e2e_setup_py2 oidc_e2e_setup_py3 +BUILD := $(addprefix build-,${IMAGES}) +PULL := $(addprefix pull-,$(IMAGES)) +CLEAN := $(addprefix clean-,$(IMAGES)) + +.PHONY: help +help: + @fgrep -h "##" Makefile | fgrep -v fgrep | sed 's/\(.*\):.*##/\1:/' + +.PHONY: build +build: ${BUILD} ## Build all images + +.PHONY: pull +pull: ${PULL} ## Pull all -latest images + +.PHONY: clean +clean: ${CLEAN} ## Clean images and other artifacts + +.PHONY: ${BUILD} +${BUILD}: build-%: + docker build -t $* -f dockerfiles/$* . + +.PHONY: ${PULL} +${PULL}: pull-%: + docker pull ${NS}:$*-latest + +.PHONY: ${CLEAN} +${CLEAN}: clean-%: + docker rmi ${NS}/$(subst _py,:py,$(*)) + docker rmi $(subst _py,:py,$(*)) diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/README.md b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9037b454463959b2a99f01058e314f7d0d8de937 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/README.md @@ -0,0 +1,98 @@ +# docker-test-mozilla-django-oidc + +The purpose of these docker images is to setup a local environment to develop and test +`mozilla-django-oidc`. + + +## oidc-testprovider + +https://hub.docker.com/r/mozilla/oidc-testprovider/tags?name=testprovider + +* Provides a docker image for an OIDC OP with preconfigured OIDC client IDs and secrets +* OIDC provider endpoint is exposed in port `8080` +* Provides a Django management command for creating users +* Uses `django-oidc-provider` + + +### Usage + +In order for this setup to work `testprovider`, `testrp` hostnames should resolve to the +IP of the docker image (for local development it's `127.0.0.1`). + +You can add the resolution to your `/etc/hosts` file. + +You can also use [nip.io](http://nip.io/). For example, if you name the service +"oidcprovider", then you could have these three variables: + +``` +OIDC_OP_AUTHORIZATION_ENDPOINT=http://oidcprovider.127.0.0.1.nip.io:8080/openid/authorize +OIDC_OP_TOKEN_ENDPOINT=http://oidcprovider.127.0.0.1.nip.io:8080/openid/token +OIDC_OP_USER_ENDPOINT=http://oidcprovider.127.0.0.1.nip.io:8080/openid/userinfo +``` + +### Example setup + +`docker-compose.yml` + +``` +version: '3' +services: + testprovider: + image: mozilla/oidc-testprovider:oidc_testprovider-v0.9.3 + ports: + - "8080:8080" +``` + + +### Creating users in the container + +The `testprovider` image has a Django management command for creating users in +the OIDC provider. This lets you create users on the command line. + +With an already running `testprovider` container run: + +``` +docker-compose exec testprovider manage.py createuser USERNAME PASSWORD EMAIL +``` + + +## Other images + +All images are pushed to: https://hub.docker.com/r/mozilla/oidc-testprovider + +* `oidc_testprovider` (See above) +* `oidc_testrunner` +* `oidc_testrp_py{2,3}` + * Test django project preconfigured to work with `testprovider` + * Uses `mozilla-django-oidc` as an authentication backend + * Test RP is exposed in port `8081` + * Builds based in both python 2/3 + * Environment variables + * `TEST_OIDC_ALGO={hs,rs}` +* `oidc_e2e_setup_py{2,3}` + * Dockerized setup for e2e testing of mozilla-django-oidc + + +### Example setup for oidc_testrp + +`docker-compose.yml` + +``` +version: '3' +services: + testrp: + image: mozilla/oidc-testprovider:oidc_testrp_py3-v0.9.3 + ports: + - "8081:8081" + environment: + - TEST_OIDC_ALGO=hs +``` + +## Development + +We use `make` to automate the docker image workflow. + +For more info run `make help`. + +Pushing a tag to GitHub will trigger building images and uploading them +to Dockerhub. diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/docker-compose.yml b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..a1022994588976175c6169fee1051c60b7b89cdf --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/docker-compose.yml @@ -0,0 +1,6 @@ +version: '3' +services: + testprovider: + image: mozilla/oidc-testprovider:oidc_testprovider-v0.9.3 + ports: + - "8080:8080" diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/dockerfiles/oidc_e2e_setup_py2 b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/dockerfiles/oidc_e2e_setup_py2 new file mode 100644 index 0000000000000000000000000000000000000000..ac0e6a7bf389c7c6cb802137e8544f889b863853 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/dockerfiles/oidc_e2e_setup_py2 @@ -0,0 +1,29 @@ +FROM python:2-stretch + +EXPOSE 8080 8081 + +RUN pip install virtualenv +RUN virtualenv /testrp_env +RUN virtualenv /testprovider_env + +COPY testprovider /testprovider/ +COPY testrp /testrp/ + +RUN . /testprovider_env/bin/activate && pip install -r /testprovider/requirements.txt +RUN . /testrp_env/bin/activate && pip install -r /testrp/requirements.txt + +# Install python and python dependencies +RUN apt-get update && \ + apt-get install -y wait-for-it + +# Install firefox +RUN apt-get install -y --no-install-recommends firefox-esr && \ + wget "https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US" -O /tmp/firefox.tar.bz2 && \ + tar xvf /tmp/firefox.tar.bz2 -C /opt && \ + rm /usr/bin/firefox && \ + ln -s /opt/firefox/firefox /usr/bin/firefox + +# Install geckodriver +RUN wget "https://github.com/mozilla/geckodriver/releases/download/v0.23.0/geckodriver-v0.23.0-linux32.tar.gz" -O /tmp/geckodriver.tar.gz && \ + tar xvf /tmp/geckodriver.tar.gz -C /opt && \ + ln -s /opt/geckodriver /usr/bin/geckodriver diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/dockerfiles/oidc_e2e_setup_py3 b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/dockerfiles/oidc_e2e_setup_py3 new file mode 100644 index 0000000000000000000000000000000000000000..9ed6e566c6b88dd21d5782d7e1b477290042b501 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/dockerfiles/oidc_e2e_setup_py3 @@ -0,0 +1,29 @@ +FROM python:3.6-stretch + +EXPOSE 8080 8081 + +RUN pip install virtualenv +RUN virtualenv /testrp_env +RUN virtualenv /testprovider_env + +COPY testprovider /testprovider/ +COPY testrp /testrp/ + +RUN . /testprovider_env/bin/activate && pip install -r /testprovider/requirements.txt +RUN . /testrp_env/bin/activate && pip install -r /testrp/requirements.txt + +# Install python and python dependencies +RUN apt-get update && \ + apt-get install -y wait-for-it + +# Install firefox +RUN apt-get install -y --no-install-recommends firefox-esr && \ + wget "https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US" -O /tmp/firefox.tar.bz2 && \ + tar xvf /tmp/firefox.tar.bz2 -C /opt && \ + rm /usr/bin/firefox && \ + ln -s /opt/firefox/firefox /usr/bin/firefox + +# Install geckodriver +RUN wget "https://github.com/mozilla/geckodriver/releases/download/v0.23.0/geckodriver-v0.23.0-linux32.tar.gz" -O /tmp/geckodriver.tar.gz && \ + tar xvf /tmp/geckodriver.tar.gz -C /opt && \ + ln -s /opt/geckodriver /usr/bin/geckodriver diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/dockerfiles/oidc_testprovider b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/dockerfiles/oidc_testprovider new file mode 100644 index 0000000000000000000000000000000000000000..464d90658afcef9c571ddcd4e6fb1f64bad37fe8 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/dockerfiles/oidc_testprovider @@ -0,0 +1,7 @@ +FROM python:3.6 +EXPOSE 8088 +COPY testprovider /code/ +WORKDIR /code + +RUN pip install -r requirements.txt +CMD ./bin/run.sh diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/dockerfiles/oidc_testrp_py2 b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/dockerfiles/oidc_testrp_py2 new file mode 100644 index 0000000000000000000000000000000000000000..369b2742d7ca7d06b7fa6e2aa20bc71aad6e089d --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/dockerfiles/oidc_testrp_py2 @@ -0,0 +1,7 @@ +FROM python:2-stretch +EXPOSE 8081 +COPY testrp /code/ +WORKDIR /code + +RUN pip install -r requirements.txt +CMD ./bin/run.sh diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/dockerfiles/oidc_testrp_py3 b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/dockerfiles/oidc_testrp_py3 new file mode 100644 index 0000000000000000000000000000000000000000..f4d52e4dfe609d8e4fc6168da02bb518200d6f2d --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/dockerfiles/oidc_testrp_py3 @@ -0,0 +1,7 @@ +FROM python:3-stretch +EXPOSE 8081 +COPY testrp /code/ +WORKDIR /code + +RUN pip install -r requirements.txt +CMD ./bin/run.sh diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/dockerfiles/oidc_testrunner b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/dockerfiles/oidc_testrunner new file mode 100644 index 0000000000000000000000000000000000000000..422da4a032271f4268b88120df86fbd18e2f13f8 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/dockerfiles/oidc_testrunner @@ -0,0 +1,18 @@ +FROM python:3-stretch + +# Install python and python dependencies +RUN apt-get update && \ + apt-get install -y wait-for-it && \ + pip install six splinter + +# Install firefox +RUN apt-get install -y --no-install-recommends firefox-esr && \ + wget "https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US" -O /tmp/firefox.tar.bz2 && \ + tar xvf /tmp/firefox.tar.bz2 -C /opt && \ + rm /usr/bin/firefox && \ + ln -s /opt/firefox/firefox /usr/bin/firefox + +# Install geckodriver +RUN wget "https://github.com/mozilla/geckodriver/releases/download/v0.23.0/geckodriver-v0.23.0-linux32.tar.gz" -O /tmp/geckodriver.tar.gz && \ + tar xvf /tmp/geckodriver.tar.gz -C /opt && \ + ln -s /opt/geckodriver /usr/bin/geckodriver diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/bin/run.sh b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/bin/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..7008ec74df50c3a95634872328fa89ff59d98f42 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/bin/run.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +python manage.py migrate --noinput +python manage.py loaddata fixtures.json +python ./manage.py createuser paulus pauluspass paulus@localhost +python manage.py runserver 0.0.0.0:8088 + diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/fixtures.json b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/fixtures.json new file mode 100644 index 0000000000000000000000000000000000000000..8682aa8ab4f7fcca32dd6b9d2a26978208efe87b --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/fixtures.json @@ -0,0 +1,140 @@ +[ + { + "model": "sites.site", + "pk": 1, + "fields": { + "domain": "testprovider:8088", + "name": "testprovider" + } + }, + { + "model": "oidc_provider.responsetype", + "pk": 1, + "fields": { + "value": "code", + "description": "code (Authorization Code Flow)" + } + }, + { + "model": "oidc_provider.responsetype", + "pk": 2, + "fields": { + "value": "id_token", + "description": "id_token (Implicit Flow)" + } + }, + { + "model": "oidc_provider.responsetype", + "pk": 3, + "fields": { + "value": "id_token token", + "description": "id_token token (Implicit Flow)" + } + }, + { + "model": "oidc_provider.responsetype", + "pk": 4, + "fields": { + "value": "code token", + "description": "code token (Hybrid Flow)" + } + }, + { + "model": "oidc_provider.responsetype", + "pk": 5, + "fields": { + "value": "code id_token", + "description": "code id_token (Hybrid Flow)" + } + }, + { + "model": "oidc_provider.responsetype", + "pk": 6, + "fields": { + "value": "code id_token token", + "description": "code id_token token (Hybrid Flow)" + } + }, + { + "model": "oidc_provider.client", + "pk": 1, + "fields": { + "name": "testrpHS256", + "owner": null, + "client_type": "confidential", + "client_id": "1", + "client_secret": "secret", + "jwt_alg": "HS256", + "date_created": "2017-11-10", + "website_url": "", + "terms_url": "", + "contact_email": "", + "logo": "", + "reuse_consent": true, + "require_consent": true, + "_redirect_uris": "http://localhost:5005/oidc/callback/", + "_post_logout_redirect_uris": "", + "_scope": "", + "response_types": [ + 1 + ] + } + }, + { + "model": "oidc_provider.client", + "pk": 2, + "fields": { + "name": "testrpHS256", + "owner": null, + "client_type": "confidential", + "client_id": "2", + "client_secret": "secret", + "jwt_alg": "HS256", + "date_created": "2017-11-10", + "website_url": "", + "terms_url": "", + "contact_email": "", + "logo": "", + "reuse_consent": true, + "require_consent": true, + "_redirect_uris": "http://localhost:8008/oidc/callback/", + "_post_logout_redirect_uris": "", + "_scope": "", + "response_types": [ + 1 + ] + } + }, + { + "model": "oidc_provider.client", + "pk": 3, + "fields": { + "name": "testrpRS256", + "owner": null, + "client_type": "confidential", + "client_id": "3", + "client_secret": "secret", + "jwt_alg": "RS256", + "date_created": "2017-11-10", + "website_url": "", + "terms_url": "", + "contact_email": "", + "logo": "", + "reuse_consent": true, + "require_consent": true, + "_redirect_uris": "http://localhost:8008/oidc/callback/", + "_post_logout_redirect_uris": "", + "_scope": "", + "response_types": [ + 1 + ] + } + }, + { + "model": "oidc_provider.rsakey", + "pk": 3, + "fields": { + "key": "-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQDAAgiIdiJG7GSMKTRbnGjWpHp1ulJ43/iQjDywWh5MP3in2PK8\nPVI6ItxIFLV81nWZMymA7hjfP7adOlxKY6rI+fExn8cTimI3W/oX6mHrPXm52uj/\nwe839pxxkeD7cmWgaif9Sujuy5AHUuUM1BTlO55POHkmhWyYMKC2P29qgQIDAQAB\nAoGAUHdJri6b1M8yoA6Qk6frw7AwZfAMqf1qxOEQefN6aQfcf7MKntqwAA8l88tB\n96xEokxvo0mlAMJJvIB9tusn4dIHKpmQGacQWVd/KONxPkvyuGgQXX5KCusZTbg7\ni6YQM52RGbExVFWLdGYJRBvzyfRkWX0b4LiderPZUiD6J/UCQQDZIgnLqYyGw3Ro\nnNboWYyOtLhKMF59f/0aSMXLlWdsnFG8kVm/7tw6jcDBalELci/+ExL2JACGwDea\n8DpvWiEDAkEA4mCovWmMDiS8tQCeY5NDic1wMp51+Ya8RX47bvb5F+X7SSE9L87y\n6eU9zVBSY8F+9npkvrxoU9PlKbS3Lzz1KwJAZ5/8BsuS+lnbe3Wmhtr93rlW3mk5\nHzHu7BVg+GkEI+xygcjoiVYImpU+MdB4fzrutpYJzZie+7BOmU4exTfBWwJBAKj+\nN3mO/Xrhee41VAhJuzV4I7XmDXQFXS8TmRKxVCq/COQC6EZ0W2q4M3a964OEw18E\n54hr5gYOPRjxS378JpkCQDjKw2Vyw0S0M8O2hOGuNsUtlGApYKt2iA41jGUf7bvO\nWz/tQuEIXQMd4e9zxNxOzPJOtjR1gyPZyi/FvsgDJDU=\n-----END RSA PRIVATE KEY-----" + } + } +] diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/manage.py b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/manage.py new file mode 100755 index 0000000000000000000000000000000000000000..5fccf17e2ac7382f4d86d3e79a1d789f72bda004 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "oidcprovider.settings") + try: + from django.core.management import execute_from_command_line + except ImportError: + # The above import may fail for some other reason. Ensure that the + # issue is really that Django is missing to avoid masking other + # exceptions on Python 2. + try: + import django + except ImportError: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) + raise + execute_from_command_line(sys.argv) diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/__init__.py b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/management/__init__.py b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/management/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/management/commands/__init__.py b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/management/commands/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/management/commands/createuser.py b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/management/commands/createuser.py new file mode 100644 index 0000000000000000000000000000000000000000..11fc496c521cf65641dbe5bc4e10509e379f231c --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/management/commands/createuser.py @@ -0,0 +1,33 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +""" +Create a user in the OIDC provider. +""" + +from django.contrib.auth.models import User +from django.core.management.base import BaseCommand + + +class Command(BaseCommand): + help = "Create a user in the OIDC provider." + + def add_arguments(self, parser): + parser.add_argument("username", help="account username") + parser.add_argument("password", help="account password") + parser.add_argument("email", help="account email address") + + def handle(self, **options): + username = options["username"] + password = options["password"] + email = options["email"] + + if User.objects.filter(username=username).exists(): + self.stdout.write("User {} already exists.".format(username)) + return + + user = User.objects.create(username=username, email=email) + user.set_password(password) + user.save() + self.stdout.write("User {} created.".format(username)) diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/settings.py b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/settings.py new file mode 100644 index 0000000000000000000000000000000000000000..9f2eca62c36f16daada5279a294470405c38cfdb --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/settings.py @@ -0,0 +1,149 @@ +""" +Django settings for oidcprovider project. + +Generated by 'django-admin startproject' using Django 1.11.6. + +For more information on this file, see +https://docs.djangoproject.com/en/1.11/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.11/ref/settings/ +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = '_brj&4ea0ec%ybc(rz32jpqwypdy4@d9lttg&g7!^e(m!-52si' +SESSION_COOKIE_NAME = 'oidcprovider' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ['*'] +SITE_ID = 1 + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django.contrib.sites', + + 'oidc_provider', + 'oidcprovider', + 'pinax_theme_bootstrap', + 'account', + 'bootstrapform', + + +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + + # django-user-accounts + 'account.middleware.LocaleMiddleware', + 'account.middleware.TimezoneMiddleware' +] + +ROOT_URLCONF = 'oidcprovider.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + 'pinax_theme_bootstrap.context_processors.theme', + 'account.context_processors.account', + ], + }, + }, +] + +WSGI_APPLICATION = 'oidcprovider.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/1.11/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} + + +# Password validation +# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/1.11/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.11/howto/static-files/ + +STATIC_URL = '/static/' + + +# OIDC provider settings +LOGIN_URL = '/account/login' +ACCOUNT_EMAIL_CONFIRMATION_EMAIL = False + + +# Workaround to actually delete the account instead of marking it as inactive +def _delete_user(obj): + obj.user.delete() + + +ACCOUNT_DELETION_MARK_CALLBACK = _delete_user diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/templates/home.html b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/templates/home.html new file mode 100644 index 0000000000000000000000000000000000000000..6daa91684373aadf91bc4e4c9fcbb835e32260be --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/templates/home.html @@ -0,0 +1,14 @@ +{% extends "site_base.html" %} + +{% block head_title %}Home{% endblock %} + +{% block body %} +<h1>Welcome to {% if SITE_NAME %}{{ SITE_NAME }}{% else %}testprovider{% endif %}!</h1> +<div> + {% if request.user.is_authenticated %} + <p>Current user: {{ user.email }}</p> + {% else %} + <p>User not logged in</p> + {% endif %} +</div> +{% endblock body %} diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/templates/site_base.html b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/templates/site_base.html new file mode 100644 index 0000000000000000000000000000000000000000..909a80cc317bb3043c437609636d45f44a184112 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/templates/site_base.html @@ -0,0 +1,28 @@ +{% extends "theme_bootstrap/base.html" %} +{% load static %} + +{% block footer %} + <p>Test OIDC provider</p> +{% endblock %} + +{% block styles %} + <link rel="stylesheet" href="{% static 'pinax/css/theme.css' %}"> + <link rel="stylesheet" + href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" + integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" + crossorigin="anonymous"> + <link rel="stylesheet" + href="https://stackpath.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" + integrity="sha384-MI32KR77SgI9QAPUs+6R7leEOwtop70UsjEtFEezfKnMjXWx15NENsZpfDgq8m8S" + crossorigin="anonymous"> +{% endblock styles %} + +{% block scripts %} + <script src="https://code.jquery.com/jquery-2.2.4.min.js" + integrity="sha384-rY/jv8mMhqDabXSo+UCggqKtdmBfd3qC2/KvyTDNQ6PcUJXaxK1tMepoQda4g5vB" + crossorigin="anonymous"></script> + <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" + integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" + crossorigin="anonymous"></script> +{% endblock scripts %} + diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/urls.py b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..3f8296b1167063f2b99f397ea3d166361a41e2a2 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/urls.py @@ -0,0 +1,12 @@ +from django.conf.urls import include, url +from django.contrib import admin + +from .views import HomePageView + +urlpatterns = [ + url(r'^openid/', include('oidc_provider.urls', namespace='oidc_provider')), + url(r'^account/', include('account.urls')), + url(r'^admin/', admin.site.urls), + url(r'^$', HomePageView.as_view(), name='home'), + +] diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/views.py b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/views.py new file mode 100644 index 0000000000000000000000000000000000000000..14cc50fec47aa54e48618de782f6e235eab07fda --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/views.py @@ -0,0 +1,6 @@ +from django.views.generic.base import TemplateView + + +class HomePageView(TemplateView): + + template_name = "home.html" diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/wsgi.py b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/wsgi.py new file mode 100644 index 0000000000000000000000000000000000000000..a995efc052615dc3c1882ffff6318636e1f3711d --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/oidcprovider/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for oidcprovider project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "oidcprovider.settings") + +application = get_wsgi_application() diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/requirements.txt b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..78415f8c8b022fbacb3f6dbe4678483093b76c1d --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testprovider/requirements.txt @@ -0,0 +1,4 @@ +django<3 +django-oidc-provider +django-user-accounts +pinax-theme-bootstrap diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/bin/run.sh b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/bin/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..6c365a5d40df50b7d86136df18a16d4cb67d3358 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/bin/run.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +TEST_OIDC_ALGO=${TEST_OIDC_ALGO} +RUNNER="./bin/run_$TEST_OIDC_ALGO.sh" + +exec $RUNNER diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/bin/run_hs.sh b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/bin/run_hs.sh new file mode 100755 index 0000000000000000000000000000000000000000..d2880cfa48ecabdfa4ad011e7d972eb71b365d37 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/bin/run_hs.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +export OIDC_RP_CLIENT_ID='1' +export OIDC_RP_CLIENT_SECRET='bd01adf93cfb' +python manage.py migrate --noinput +python manage.py runserver 0.0.0.0:8081 diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/bin/run_rs.sh b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/bin/run_rs.sh new file mode 100755 index 0000000000000000000000000000000000000000..82e27b82659ce09f09899f653a8f8c51735ce816 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/bin/run_rs.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +export OIDC_RP_IDP_SIGN_KEY=$(cat provider_rsa.key) +export OIDC_RP_CLIENT_ID='2' +export OIDC_RP_CLIENT_SECRET='a6b4dad2f215' +export OIDC_RP_SIGN_ALGO='RS256' +python manage.py migrate --noinput +python manage.py runserver 0.0.0.0:8081 diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/manage.py b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/manage.py new file mode 100755 index 0000000000000000000000000000000000000000..b588f3da043208c06dc027303e704d9a2f35b0f5 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testrp.settings") + try: + from django.core.management import execute_from_command_line + except ImportError: + # The above import may fail for some other reason. Ensure that the + # issue is really that Django is missing to avoid masking other + # exceptions on Python 2. + try: + import django + except ImportError: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) + raise + execute_from_command_line(sys.argv) diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/provider_rsa.key b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/provider_rsa.key new file mode 100644 index 0000000000000000000000000000000000000000..8d4b4180509d3405354da78ac948c4eda504dc3d --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/provider_rsa.key @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAAgiIdiJG7GSMKTRbnGjWpHp1 +ulJ43/iQjDywWh5MP3in2PK8PVI6ItxIFLV81nWZMymA7hjfP7adOlxKY6rI+fEx +n8cTimI3W/oX6mHrPXm52uj/we839pxxkeD7cmWgaif9Sujuy5AHUuUM1BTlO55P +OHkmhWyYMKC2P29qgQIDAQAB +-----END PUBLIC KEY----- diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/requirements.txt b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..4bb815165fb59dae48ce4d0cf1aff7e6ee6c610b --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/requirements.txt @@ -0,0 +1,6 @@ +django +djangorestframework +python-decouple +mozilla-django-oidc +six +splinter diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/testrp/__init__.py b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/testrp/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/testrp/settings.py b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/testrp/settings.py new file mode 100644 index 0000000000000000000000000000000000000000..e746e99f9d076b29e5a1724eb0317b1b87f8e113 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/testrp/settings.py @@ -0,0 +1,153 @@ +""" +Django settings for testrp project. + +Generated by 'django-admin startproject' using Django 1.11.6. + +For more information on this file, see +https://docs.djangoproject.com/en/1.11/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.11/ref/settings/ +""" + +import os + +from decouple import config + + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = '@n!q#(pw!ta3_^*!i7&8m(ev91qdju(5^ijx)a%5+upwv+s_u-' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ['*'] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + + 'rest_framework', + 'mozilla_django_oidc', + 'testrp' +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +# Django<1.10 Compatibility +MIDDLEWARE_CLASSES = MIDDLEWARE + +ROOT_URLCONF = 'testrp.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'testrp.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/1.11/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} + + +# Password validation +# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/1.11/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.11/howto/static-files/ + +STATIC_URL = '/static/' + +REST_FRAMEWORK = { + 'DEFAULT_AUTHENTICATION_CLASSES': [ + 'mozilla_django_oidc.contrib.drf.OIDCAuthentication' + ] +} + + +# OIDC SETUP +AUTHENTICATION_BACKENDS = ( + 'mozilla_django_oidc.auth.OIDCAuthenticationBackend', +) + +OIDC_RP_CLIENT_ID = config('OIDC_RP_CLIENT_ID') +OIDC_RP_CLIENT_SECRET = config('OIDC_RP_CLIENT_SECRET') +OIDC_RP_SIGN_ALGO = config('OIDC_RP_SIGN_ALGO', default='HS256') +OIDC_RP_IDP_SIGN_KEY = config('OIDC_RP_IDP_SIGN_KEY', default=None) +OIDC_OP_AUTHORIZATION_ENDPOINT = 'http://testprovider:8080/openid/authorize' +OIDC_OP_TOKEN_ENDPOINT = 'http://testprovider:8080/openid/token' +OIDC_OP_USER_ENDPOINT = 'http://testprovider:8080/openid/userinfo' + +LOGOUT_REDIRECT_URL = '/' +LOGIN_REDIRECT_URL = '/' diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/testrp/templates/home.html b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/testrp/templates/home.html new file mode 100644 index 0000000000000000000000000000000000000000..0b07cc8c9ec7d6e92d3bed40928d6d5111d46074 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/testrp/templates/home.html @@ -0,0 +1,22 @@ +<html> + <body> + <div> + Welcome to testrp! + </div> + <div> + {% if request.user.is_authenticated %} + <p>Current user: {{ user.email }}</p> + <div> + <form action="/oidc/logout/" method="POST"> + {% csrf_token %} + <input type="submit" value="Logout"/> + </form> + </div> + {% else %} + <a href="{% url 'oidc_authentication_init' %}"> + Login + </a> + {% endif %} + </div> + </body> +</html> diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/testrp/urls.py b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/testrp/urls.py new file mode 100644 index 0000000000000000000000000000000000000000..beaf5a5920817232dc4e9e3b36fb25c9b48c0c39 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/testrp/urls.py @@ -0,0 +1,10 @@ +from django.conf.urls import include, url + +from .views import HomePageView, TestAPIView + + +urlpatterns = [ + url(r'^oidc/', include('mozilla_django_oidc.urls')), + url(r'^api/$', TestAPIView.as_view(), name='api'), + url(r'^$', HomePageView.as_view(), name='home') +] diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/testrp/views.py b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/testrp/views.py new file mode 100644 index 0000000000000000000000000000000000000000..47b860cce32ef0b7be8f307f0ea352cb16ce486c --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/testrp/views.py @@ -0,0 +1,17 @@ +from django.views.generic.base import TemplateView +from mozilla_django_oidc.utils import is_authenticated +from rest_framework.response import Response +from rest_framework.views import APIView + + +class HomePageView(TemplateView): + + template_name = "home.html" + + +class TestAPIView(APIView): + + def get(self, request): + return Response({ + 'is_authenticated': is_authenticated(request.user) + }) diff --git a/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/testrp/wsgi.py b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/testrp/wsgi.py new file mode 100644 index 0000000000000000000000000000000000000000..ea4648b82c599721ede45f39c98263c3fac19d73 --- /dev/null +++ b/SAS/TMSS/test/oidc/docker-test-mozilla-django-oidc/testrp/testrp/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for testrp project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testrp.settings") + +application = get_wsgi_application() diff --git a/SAS/TMSS/test/oidc/example/__pycache__/__init__.cpython-34.pyc b/SAS/TMSS/test/oidc/example/__pycache__/__init__.cpython-34.pyc new file mode 100644 index 0000000000000000000000000000000000000000..819d68a23dababb1257d69f3b39b35a9d08a0ef0 Binary files /dev/null and b/SAS/TMSS/test/oidc/example/__pycache__/__init__.cpython-34.pyc differ diff --git a/SAS/TMSS/test/oidc/example/__pycache__/app.cpython-34.pyc b/SAS/TMSS/test/oidc/example/__pycache__/app.cpython-34.pyc new file mode 100644 index 0000000000000000000000000000000000000000..004bd471eec2552f614d26573477e473b8be185d Binary files /dev/null and b/SAS/TMSS/test/oidc/example/__pycache__/app.cpython-34.pyc differ diff --git a/SAS/TMSS/test/oidc/example/__pycache__/views.cpython-34.pyc b/SAS/TMSS/test/oidc/example/__pycache__/views.cpython-34.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0f4d528467e3f5573f883a850f931ff5a4c697dc Binary files /dev/null and b/SAS/TMSS/test/oidc/example/__pycache__/views.cpython-34.pyc differ diff --git a/SAS/TMSS/test/oidc/example/__pycache__/wsgi.cpython-34.pyc b/SAS/TMSS/test/oidc/example/__pycache__/wsgi.cpython-34.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4d49e3aecb16e15abd0ed70fdceb8eb407a468ec Binary files /dev/null and b/SAS/TMSS/test/oidc/example/__pycache__/wsgi.cpython-34.pyc differ diff --git a/SAS/TMSS/test/oidc/keycloak/create-keycloak-user.sh b/SAS/TMSS/test/oidc/keycloak/create-keycloak-user.sh new file mode 100644 index 0000000000000000000000000000000000000000..1ede32adf3d5e7ab72f078c46fa8c438ae1464d0 --- /dev/null +++ b/SAS/TMSS/test/oidc/keycloak/create-keycloak-user.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +cd keycloak/bin +./kcadm.sh config credentials --server http://localhost:8080/auth --realm master --user admin --password admin + +USERID=$(./kcadm.sh create users -r demo -s username=monitoring-user -s enabled=true -o --fields id | jq '.id' | tr -d '"') +echo $USERID +./kcadm.sh update users/$USERID/reset-password -r demo -s type=password -s value=default -s temporary=false -n +./kcadm.sh add-roles --uusername monitoring-user --rolename monitoring -r demo + diff --git a/SAS/TMSS/test/oidc/keycloak/realm-export.json b/SAS/TMSS/test/oidc/keycloak/realm-export.json new file mode 100644 index 0000000000000000000000000000000000000000..5fa0d5bae6b1d0cf4faf618579693af9ce2c39e7 --- /dev/null +++ b/SAS/TMSS/test/oidc/keycloak/realm-export.json @@ -0,0 +1,1808 @@ + + "id": "demo", + "realm": "demo", + "notBefore": 0, + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 300, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "enabled": true, + "sslRequired": "external", + "registrationAllowed": false, + "registrationEmailAsUsername": false, + "rememberMe": false, + "verifyEmail": false, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": false, + "editUsernameAllowed": false, + "bruteForceProtected": false, + "permanentLockout": false, + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "roles": { + "realm": [ + { + "id": "9cdbfeb1-7dea-442b-a798-0845a15b3fef", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "demo", + "attributes": {} + }, + { + "id": "5c42617f-2d8c-422d-8d15-b7630067990e", + "name": "demo-administrator", + "composite": false, + "clientRole": false, + "containerId": "demo", + "attributes": {} + }, + { + "id": "46b3080a-2957-4bd6-9d06-da15dac503e4", + "name": "promoter", + "composite": false, + "clientRole": false, + "containerId": "demo", + "attributes": {} + }, + { + "id": "16a657ca-7a97-4d27-b1d1-8a65087a1f19", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "demo", + "attributes": {} + }, + { + "id": "cecacd7e-1775-4ac1-ba99-93d9020ead83", + "name": "monitoring", + "composite": false, + "clientRole": false, + "containerId": "demo", + "attributes": {} + } + ], + "client": { + "realm-management": [ + { + "id": "e441b81d-6ae3-4cf7-bfbf-ed4215eb2f47", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + }, + { + "id": "8c7cd27d-dfc5-4f83-80bf-373255b888d2", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + }, + { + "id": "ed027a01-9172-4e2c-a3c5-959de3d24c22", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-users", + "query-groups" + ] + } + }, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + }, + { + "id": "bf27552e-da67-4780-8d14-c795bc9f3407", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + }, + { + "id": "d6beb376-5920-411d-93fc-b90c091d3d2f", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + }, + { + "id": "3c5e7a53-7ead-4726-940f-d4190b0ec5c7", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + }, + { + "id": "031098a6-8e77-4e01-912b-e50a1f9e7749", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + }, + { + "id": "9fdf5253-30a4-4b3d-8ca7-2044396d9ccb", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + }, + { + "id": "d43dc9bd-5d06-4eae-9708-95f7e835fbfd", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-clients" + ] + } + }, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + }, + { + "id": "693555e2-14e1-461e-98a1-c8cab8137f8f", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + }, + { + "id": "6b90a2d2-f366-457d-9469-c5da38f990a6", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + }, + { + "id": "c073af53-414a-41f0-b093-0b68c0f1ecba", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + }, + { + "id": "1283a4ff-5217-449c-8c85-ddff72ed73fd", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + }, + { + "id": "57a640d0-f017-46f8-a23e-d3fc7f8e7de8", + "name": "realm-admin", + "description": "${role_realm-admin}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "manage-realm", + "create-client", + "view-users", + "query-clients", + "manage-events", + "manage-authorization", + "manage-users", + "query-groups", + "view-realm", + "view-clients", + "query-realms", + "impersonation", + "query-users", + "manage-clients", + "view-authorization", + "view-events", + "view-identity-providers", + "manage-identity-providers" + ] + } + }, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + }, + { + "id": "5d4108b8-c2bc-44f2-9038-ea18bf3164ef", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + }, + { + "id": "7ee7d0f4-d61f-4e01-ac37-86a7d42e30a0", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + }, + { + "id": "9d6dd55e-2d70-4b35-9ae7-43b59ff84cd5", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + }, + { + "id": "e2b85d94-2efb-458f-ae69-84e04d0975e4", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + }, + { + "id": "466294e7-feb8-4d2f-ae45-6807160553ae", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "0c80e92e-024a-4324-b516-cf814f7e09df", + "attributes": {} + } + ], + "demo-frontend": [], + "security-admin-console": [], + "admin-cli": [], + "demo-api": [], + "broker": [ + { + "id": "b375956d-b283-45b7-aa0b-76e19d3c9b2f", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "d165281c-4c36-4185-bfbd-589c8a52945f", + "attributes": {} + } + ], + "account": [ + { + "id": "aada5867-9268-4e37-b206-491041cd3360", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "f5c24837-4fc7-4994-9c1e-bd70f2cbeed6", + "attributes": {} + }, + { + "id": "39893eb7-65a6-4d5e-9704-f59952deaeab", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": [ + "manage-account-links" + ] + } + }, + "clientRole": true, + "containerId": "f5c24837-4fc7-4994-9c1e-bd70f2cbeed6", + "attributes": {} + }, + { + "id": "193f4d1a-4c4a-4029-9092-1aa44df23b42", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "f5c24837-4fc7-4994-9c1e-bd70f2cbeed6", + "attributes": {} + } + ] + } + }, + "groups": [ + { + "id": "62909b3a-eb39-4916-a640-f401d0592a47", + "name": "administrator", + "path": "/administrator", + "attributes": {}, + "realmRoles": [ + "demo-administrator" + ], + "clientRoles": {}, + "subGroups": [] + }, + { + "id": "3e007c9c-297e-4403-8ad0-1888e05211ad", + "name": "monitoring", + "path": "/monitoring", + "attributes": {}, + "realmRoles": [ + "monitoring" + ], + "clientRoles": {}, + "subGroups": [] + }, + { + "id": "9ca100d3-c97c-495e-9e28-828bfe7e2405", + "name": "promoter", + "path": "/promoter", + "attributes": {}, + "realmRoles": [ + "promoter" + ], + "clientRoles": {}, + "subGroups": [] + } + ], + "requiredCredentials": [ + "password" + ], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpSupportedApplications": [ + "FreeOTP", + "Google Authenticator" + ], + "clients": [ + { + "id": "1f279ab9-a6b9-4d19-b9f3-f881ff2257eb", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "role_list", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "f5c24837-4fc7-4994-9c1e-bd70f2cbeed6", + "clientId": "account", + "name": "${client_account}", + "baseUrl": "/auth/realms/demo/account", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [ + "/auth/realms/demo/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "role_list", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "0c80e92e-024a-4324-b516-cf814f7e09df", + "clientId": "realm-management", + "name": "${client_realm-management}", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "role_list", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "3bcece73-8800-42d4-82fe-7c0012be3780", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "baseUrl": "/auth/admin/demo/console/index.html", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [ + "/auth/admin/demo/console/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "e70c7d3c-dd18-4084-81c8-c57a31a31cb9", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "role_list", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "2e0fa909-b029-4d69-ac0e-ff3e593d57e6", + "clientId": "demo-frontend", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [ + "http://localhost:9002/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "saml.assertion.signature": "false", + "saml.force.post.binding": "false", + "saml.multivalued.roles": "false", + "saml.encrypt": "false", + "saml.server.signature": "false", + "saml.server.signature.keyinfo.ext": "false", + "exclude.session.state.from.auth.response": "false", + "saml_force_name_id_format": "false", + "saml.client.signature": "false", + "tls.client.certificate.bound.access.tokens": "false", + "saml.authnstatement": "false", + "display.on.consent.screen": "false", + "saml.onetimeuse.condition": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "role_list", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "d165281c-4c36-4185-bfbd-589c8a52945f", + "clientId": "broker", + "name": "${client_broker}", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "role_list", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "79e1f43b-283a-40d9-a953-c60e9686d329", + "clientId": "demo-api", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "saml.assertion.signature": "false", + "saml.force.post.binding": "false", + "saml.multivalued.roles": "false", + "saml.encrypt": "false", + "saml.server.signature": "false", + "saml.server.signature.keyinfo.ext": "false", + "exclude.session.state.from.auth.response": "false", + "saml_force_name_id_format": "false", + "saml.client.signature": "false", + "tls.client.certificate.bound.access.tokens": "false", + "saml.authnstatement": "false", + "display.on.consent.screen": "false", + "saml.onetimeuse.condition": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "role_list", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + } + ], + "clientScopes": [ + { + "id": "90b602f0-d9a0-4781-9e9b-2dd5f7d28665", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${addressScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "45f8b45d-72bb-47dc-ab28-2a5c83b81cf8", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + }, + { + "id": "10c965ec-c1af-4f24-9945-9d94fb7ee037", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${emailScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "c31c85b3-9641-4656-b19a-eb399567522e", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + }, + { + "id": "33354d4c-bb3b-4410-9238-f5e8448dc955", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "1338f8cd-1cc1-4446-9f54-4e7db3e319d1", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "id": "0c36241e-ca1f-415d-b218-4da0ef9fc57b", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${phoneScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "9b8380cc-5aaf-4bf7-89b4-f29c7dba6a0c", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String" + } + }, + { + "id": "d2bdd3f1-3293-4c59-92c5-a64967a49ec7", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "9ba88b22-dfd9-4544-966e-ab2e07e02283", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${profileScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "abc6a671-5996-48ec-aac3-5d970b85e9a6", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String" + } + }, + { + "id": "7a6e6867-8767-4782-8400-e8cba29588e2", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "String" + } + }, + { + "id": "a45c0185-4e57-4d73-a55c-de4e30886c84", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String" + } + }, + { + "id": "8786b25f-17e7-4187-8d7d-d2aa61c6dcd8", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String" + } + }, + { + "id": "95ece622-b3cc-49f5-b848-a9b8a5407ef4", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String" + } + }, + { + "id": "59189670-aa93-4933-a796-53dab6a23e45", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + }, + { + "id": "addccb2b-468f-404c-9e80-de9d344f6b94", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String" + } + }, + { + "id": "cd2fe8d9-f253-477f-94fd-29942d56849c", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String" + } + }, + { + "id": "450e97fc-e780-4262-8f26-0cf8ac903aa3", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + }, + { + "id": "4b40a0f9-44a1-4a01-b0c5-bfb8be5bccb6", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "id": "07343c50-155a-430c-8ebb-c68a931a0c80", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String" + } + }, + { + "id": "8076d3ce-1d9f-4779-93c3-9b6a06e8bdac", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String" + } + }, + { + "id": "d26abee7-b8a7-4ca5-9755-38e18cc539d6", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String" + } + }, + { + "id": "83344728-39e4-4600-9c5b-b9d69da3c4f0", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "289f7853-fa6e-4f17-a01d-6c409bddc25a", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "c0d2acb4-d20f-48de-94c7-ec6ac1c964e1", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "6820c5fc-b7db-4a1d-b71a-8dbd0c7cf98c", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "true", + "consent.screen.text": "${rolesScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "1cb77c0d-6397-4b3d-acef-8ae1d4089944", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "multivalued": "true", + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String" + } + }, + { + "id": "0cf6603d-891d-4f42-8da0-d187f0816a6d", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + }, + { + "id": "9e8111be-4598-4145-96da-a9a0fcda8169", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "multivalued": "true", + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "ba84e265-6519-45db-88fc-f86ec057f28c", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false", + "consent.screen.text": "" + }, + "protocolMappers": [ + { + "id": "3d010883-cafc-4e4a-9246-3669d767f409", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": {} + } + ] + } + ], + "defaultDefaultClientScopes": [ + "role_list", + "profile", + "email", + "roles", + "web-origins" + ], + "defaultOptionalClientScopes": [ + "offline_access", + "address", + "phone" + ], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "xXSSProtection": "1; mode=block", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" + }, + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": [ + "jboss-logging" + ], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "5d3fa6d3-b34b-4996-b19c-4b57c49968c0", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "eee392b9-35d5-4166-90b3-87b8e7fe7102", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "5d4439dc-fae2-41ff-b1a9-36f70dc0ca79", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": [ + "true" + ], + "client-uris-must-match": [ + "true" + ] + } + }, + { + "id": "c1ba9983-f538-417e-8c7c-a4569946ac98", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-full-name-mapper", + "oidc-usermodel-attribute-mapper", + "oidc-usermodel-property-mapper", + "oidc-address-mapper", + "saml-user-attribute-mapper", + "saml-user-property-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-role-list-mapper" + ] + } + }, + { + "id": "506d7fe8-a747-4ad2-89be-6c467cd9820d", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": [ + "200" + ] + } + }, + { + "id": "bdb7e39e-b1dd-4d19-826f-dcf0b1e8b505", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-user-attribute-mapper", + "oidc-full-name-mapper", + "saml-role-list-mapper", + "saml-user-property-mapper", + "oidc-usermodel-attribute-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-usermodel-property-mapper", + "oidc-address-mapper" + ] + } + }, + { + "id": "4d541fe3-f769-4457-817d-5ca7af5705a0", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "d1b29f0d-4c6b-4c03-95bf-e27c23ef3a2c", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "5ca0e66f-c953-4088-842a-f65f1cfce006", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "004fea62-f268-4580-aafd-0b59b82740f2", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "b9531509-0e75-48dd-8860-7dbec1431d09", + "name": "hmac-generated", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS256" + ] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "e18853d2-04f1-4abd-a397-6d204a640c0d", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "idp-email-verification", + "requirement": "ALTERNATIVE", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "ALTERNATIVE", + "priority": 30, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "1fea2aeb-619c-41fc-b8cc-d5b4529a500d", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-otp-form", + "requirement": "OPTIONAL", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "382ebfeb-0fd2-4612-890b-6351a44fe1c1", + "alias": "browser", + "description": "browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "requirement": "ALTERNATIVE", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-spnego", + "requirement": "DISABLED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "identity-provider-redirector", + "requirement": "ALTERNATIVE", + "priority": 25, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "ALTERNATIVE", + "priority": 30, + "flowAlias": "forms", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "34a5ff88-ffd5-4f60-9d65-99ddc6d9c41a", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "requirement": "ALTERNATIVE", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "client-jwt", + "requirement": "ALTERNATIVE", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "client-secret-jwt", + "requirement": "ALTERNATIVE", + "priority": 30, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "client-x509", + "requirement": "ALTERNATIVE", + "priority": 40, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "3d8c95b8-49a5-416b-823b-5533e089e1a7", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "direct-grant-validate-password", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "direct-grant-validate-otp", + "requirement": "OPTIONAL", + "priority": 30, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "0ae57c67-dfd8-4264-b6ce-6731f71c3237", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "272cb097-3372-45c6-b0cc-d920a1cc6bd6", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "requirement": "ALTERNATIVE", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "ALTERNATIVE", + "priority": 30, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "ab046190-a8d4-4d52-9503-35325498a15f", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-otp-form", + "requirement": "OPTIONAL", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "21f7be44-8819-4ba0-95cb-01a336745cd0", + "alias": "http challenge", + "description": "An authentication flow based on challenge-response HTTP Authentication Schemes", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "no-cookie-redirect", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "basic-auth", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "basic-auth-otp", + "requirement": "DISABLED", + "priority": 30, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-spnego", + "requirement": "DISABLED", + "priority": 40, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "e2f99e58-44fb-4776-aaa4-ffc809294c15", + "alias": "registration", + "description": "registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "requirement": "REQUIRED", + "priority": 10, + "flowAlias": "registration form", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "6b1f9993-fd6b-4cf5-b218-99914899154b", + "alias": "registration form", + "description": "registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "registration-profile-action", + "requirement": "REQUIRED", + "priority": 40, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "registration-password-action", + "requirement": "REQUIRED", + "priority": 50, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "registration-recaptcha-action", + "requirement": "DISABLED", + "priority": 60, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "2ac061c4-101e-453d-9b00-ecced9adf98a", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "reset-credential-email", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "reset-password", + "requirement": "REQUIRED", + "priority": 30, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "reset-otp", + "requirement": "OPTIONAL", + "priority": 40, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "d5cb10f4-333b-4b2e-85ef-533e16d25029", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "9181f4be-676d-4639-8883-e8b3bd99dc9c", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "580e9d0d-3439-44cb-8be7-852cdf9de45a", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": true, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "terms_and_conditions", + "name": "Terms and Conditions", + "providerId": "terms_and_conditions", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": true, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 50, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "attributes": { + "_browser_header.xXSSProtection": "1; mode=block", + "_browser_header.xFrameOptions": "SAMEORIGIN", + "_browser_header.strictTransportSecurity": "max-age=31536000; includeSubDomains", + "permanentLockout": "false", + "quickLoginCheckMilliSeconds": "1000", + "_browser_header.xRobotsTag": "none", + "maxFailureWaitSeconds": "900", + "minimumQuickLoginWaitSeconds": "60", + "failureFactor": "30", + "actionTokenGeneratedByUserLifespan": "300", + "maxDeltaTimeSeconds": "43200", + "_browser_header.xContentTypeOptions": "nosniff", + "offlineSessionMaxLifespan": "5184000", + "actionTokenGeneratedByAdminLifespan": "43200", + "_browser_header.contentSecurityPolicyReportOnly": "", + "bruteForceProtected": "false", + "_browser_header.contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "waitIncrementSeconds": "60", + "offlineSessionMaxLifespanEnabled": "false" + }, + "keycloakVersion": "4.6.0.Final", + "userManagedAccessAllowed": false +} diff --git a/SAS/TMSS/test/oidc/keycloak/tmss_keycloak_Dockerfile b/SAS/TMSS/test/oidc/keycloak/tmss_keycloak_Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..40af052fa688ac67a90b5fff8eb358237900aa19 --- /dev/null +++ b/SAS/TMSS/test/oidc/keycloak/tmss_keycloak_Dockerfile @@ -0,0 +1,10 @@ +FROM jboss/keycloak:4.6.0.Final + +ENV KEYCLOAK_USER=admin +ENV KEYCLOAK_PASSWORD=admin +ENV KEYCLOAK_IMPORT=/tmp/realm-export.json + +ADD realm-export.json /tmp/realm-export.json +ADD create-keycloak-user.sh /opt/jboss/create-keycloak-user.sh + + diff --git a/SAS/TMSS/test/oidc/pyop_example/README.md b/SAS/TMSS/test/oidc/pyop_example/README.md new file mode 100644 index 0000000000000000000000000000000000000000..eaff811bdcd0e7e41fdf8d56691fa96a3981133e --- /dev/null +++ b/SAS/TMSS/test/oidc/pyop_example/README.md @@ -0,0 +1,8 @@ +# pyOP example application +To run the example application, execute the following commands: + +```bash +cd example/ +pip install -r requirements.txt # install the dependencies +gunicorn wsgi:app -b :9090 --certfile https.crt --keyfile https.key # run the application +``` \ No newline at end of file diff --git a/SAS/TMSS/test/oidc/pyop_example/__init__.py b/SAS/TMSS/test/oidc/pyop_example/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/SAS/TMSS/test/oidc/pyop_example/app.py b/SAS/TMSS/test/oidc/pyop_example/app.py new file mode 100644 index 0000000000000000000000000000000000000000..806dc4cab84103ad5ab3396b4a59cbc7b7032d4d --- /dev/null +++ b/SAS/TMSS/test/oidc/pyop_example/app.py @@ -0,0 +1,60 @@ +from flask.app import Flask +from flask.helpers import url_for +from jwkest.jwk import RSAKey, rsa_load + +from pyop.authz_state import AuthorizationState +from pyop.provider import Provider +from pyop.subject_identifier import HashBasedSubjectIdentifierFactory +from pyop.userinfo import Userinfo + + +def init_oidc_provider(app): + with app.app_context(): + issuer = url_for('oidc_provider.index')[:-1] + authentication_endpoint = url_for('oidc_provider.authentication_endpoint') + jwks_uri = url_for('oidc_provider.jwks_uri') + token_endpoint = url_for('oidc_provider.token_endpoint') + userinfo_endpoint = url_for('oidc_provider.userinfo_endpoint') + registration_endpoint = url_for('oidc_provider.registration_endpoint') + end_session_endpoint = url_for('oidc_provider.end_session_endpoint') + + configuration_information = { + 'issuer': issuer, + 'authorization_endpoint': authentication_endpoint, + 'jwks_uri': jwks_uri, + 'token_endpoint': token_endpoint, + 'userinfo_endpoint': userinfo_endpoint, + 'registration_endpoint': registration_endpoint, + 'end_session_endpoint': end_session_endpoint, + 'scopes_supported': ['openid', 'profile'], + 'response_types_supported': ['code', 'code id_token', 'code token', 'code id_token token'], # code and hybrid + 'response_modes_supported': ['query', 'fragment'], + 'grant_types_supported': ['authorization_code', 'implicit'], + 'subject_types_supported': ['pairwise'], + 'token_endpoint_auth_methods_supported': ['client_secret_basic'], + 'claims_parameter_supported': True + } + + userinfo_db = Userinfo(app.users) + signing_key = RSAKey(key=rsa_load('signing_key.pem'), alg='RS256') + provider = Provider(signing_key, configuration_information, + AuthorizationState(HashBasedSubjectIdentifierFactory(app.config['SUBJECT_ID_HASH_SALT'])), + {}, userinfo_db) + + return provider + + +def oidc_provider_init_app(name=None): + name = name or __name__ + app = Flask(name) + app.config.from_pyfile('application.cfg') + + app.users = {'test_user': {'name': 'Testing Name'}} + + from .views import oidc_provider_views + app.register_blueprint(oidc_provider_views) + + # Initialize the oidc_provider after views to be able to set correct urls + app.provider = init_oidc_provider(app) + + return app diff --git a/SAS/TMSS/test/oidc/pyop_example/application.cfg b/SAS/TMSS/test/oidc/pyop_example/application.cfg new file mode 100644 index 0000000000000000000000000000000000000000..36a1da6723269c362ec85862a1ef2c25f9aade8d --- /dev/null +++ b/SAS/TMSS/test/oidc/pyop_example/application.cfg @@ -0,0 +1,5 @@ +SERVER_NAME = 'localhost:9090' +SECRET_KEY = 'secret_key' +SESSION_COOKIE_NAME='pyop_session' +SUBJECT_ID_HASH_SALT = 'salt' +PREFERRED_URL_SCHEME = 'https' \ No newline at end of file diff --git a/SAS/TMSS/test/oidc/pyop_example/https.crt b/SAS/TMSS/test/oidc/pyop_example/https.crt new file mode 100644 index 0000000000000000000000000000000000000000..20a202d8992f026f63a09dea769fe8abadabafb8 --- /dev/null +++ b/SAS/TMSS/test/oidc/pyop_example/https.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEBjCCAu6gAwIBAgIJAIybVu7kfIK0MA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNV +BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQxGDAWBgNVBAMTD2xva2kuaXRzLnVtdS5zZTAeFw0xNTEy +MTAxNDQyMDFaFw0yNTEyMDcxNDQyMDFaMF8xCzAJBgNVBAYTAkFVMRMwEQYDVQQI +EwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQx +GDAWBgNVBAMTD2xva2kuaXRzLnVtdS5zZTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBALiLDBwIteIobC+7JHoNeQRrTIbws9BghN4UUzyLo7+xeP9YwHaS +tq6HqYK4cVLyx8k06Siw/4PwqMPNj9/B4f/ZXhEkXgbBP5TP36UgKrUIk4zInRFb +Rjy+DcqjSZdgW1CKBKWJstXjSYen5rPm+voM/0msi164NPcfDMQIZmcQWh0MmEfG +qlvdwTvjdaAQt8p7CGsxIdu4gPfhubknbTQKu+BVq5/RCVP7VU830PSr1RYhthX8 +Gt8ir32jEdDdjIrfA/zFx6PChyLkQFXtg/9WymnIM1j2ngNreL2nppwnqMYRnI9i +C/y7MY4al3WeL9IETrtgh1jzXUNpgpJ03B0CAwEAAaOBxDCBwTAdBgNVHQ4EFgQU +cTNphzIIRpQBQ2VT0Vx9xQYzNN0wgZEGA1UdIwSBiTCBhoAUcTNphzIIRpQBQ2VT +0Vx9xQYzNN2hY6RhMF8xCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRl +MSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxGDAWBgNVBAMTD2xv +a2kuaXRzLnVtdS5zZYIJAIybVu7kfIK0MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN +AQEFBQADggEBAJYJfUqOPTyZ+tflKoN4l+scIXpBxqtQbjX+MYli6VHpl+M8y163 +KsCglXPddL7Z58KBrUDx1m6f7dFQ3PMYn/S2dUcRrNOdfaDKZ5QgyYj/iVr8HSOh +6i1OtMFaBqW5WyqA5YgvUz63hZ2kDOBHZcEfSn2+roylBUiueV9gFNKDWneNMLo2 +PMZxcGWZ3wIQbu9ahakbJUvTigFStKeLoY1A2ZSTH7W4elB5DDxYOKZSzd/KZpfn +/o/Pc7YbbEUYgIyf3QNusdH+t2pw9ZkrlKMhiv9ZAmjAWMDY7O/i3r7u7AkODu7z +OHbH3rJqkbaiS8/q0cMZG6AMUzPRglzsTc4= +-----END CERTIFICATE----- diff --git a/SAS/TMSS/test/oidc/pyop_example/https.key b/SAS/TMSS/test/oidc/pyop_example/https.key new file mode 100644 index 0000000000000000000000000000000000000000..2abb725087feda493114a731026b866396c07797 --- /dev/null +++ b/SAS/TMSS/test/oidc/pyop_example/https.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAuIsMHAi14ihsL7skeg15BGtMhvCz0GCE3hRTPIujv7F4/1jA +dpK2roepgrhxUvLHyTTpKLD/g/Cow82P38Hh/9leESReBsE/lM/fpSAqtQiTjMid +EVtGPL4NyqNJl2BbUIoEpYmy1eNJh6fms+b6+gz/SayLXrg09x8MxAhmZxBaHQyY +R8aqW93BO+N1oBC3ynsIazEh27iA9+G5uSdtNAq74FWrn9EJU/tVTzfQ9KvVFiG2 +Ffwa3yKvfaMR0N2Mit8D/MXHo8KHIuRAVe2D/1bKacgzWPaeA2t4vaemnCeoxhGc +j2IL/LsxjhqXdZ4v0gROu2CHWPNdQ2mCknTcHQIDAQABAoIBAQCooAWUqDDqUl1o +z+voyt7FtvXaZ58mzMsb0h6suDwMMTKKwKI8tprOp4+wrrB+RvFfXUWftPwFp6XO +JMtOfm7vxcM6jqyMJ5DdfYSx8c6UVR3eCoHbFjf70P3xJ3tbIuTNlw/f4w7Sejj6 +B+W6hVjXm4C55TwEdPWQyYJ0rehESxITn7DDjDNXxxwDqwAv8yPTYf8m7mb7qh3V +EBnvZPIWpgEIVqV2crQSfHJwg29KhS7cnExJBYEPppBQ4aoUGyMqJN0EyBL4DrRo +Ds6hPttLaXEmB+ACm/OQzhEeFKduob5OIKRSyp9Z8t6/B9uHiIKCENRU4O4zux57 +jZ8MIypRAoGBAO0anHYHlniyP5f/8u4kvTnW3wbDtRJ3L3zVSKN8shQmQnjNWmsI +LhLWLU2OTRsXlJB7oYqNBojUBdeGimYot9kmjx4XkxELB6XAaYDG6pDvM7axC5qH +iuC4jVHdEsIfy9dP6wZ/b+A+JOWWpS1vdAizfvgWI32JLGDPkjjUlzNvAoGBAMdA +F5KZZLZFYsZM470/bb20qFMURDRI+5yz0VUHTNUQEr/xhMcYFske6ox14A7gXzwd +SHAvTDkV8DsGu/FzSWzZmVhNc1EtdM3Cbe3Y7WJoIQoupuxBDEvrBE9riyOjW61q +dYIO2ymfJfc2Vx6d7LAK9itXdqa3RIo7ZPK7EbMzAoGAAR1C5vsaJe8QhXJafewG +R6NO4QVCcJfGzVtjQAFyBM45OcAdUKt1K/l9tQOaMSpnNFagZ7pJ8ZKthFnJhLlk +Q8z+lzGdK1NV8d15oXVN3OiC4bTrTQqeCHhVkbDsSaVEm/pwLFOk/vTLz5hpplED +xpaxXhEckZZ3cu0GzuWQ4FkCgYAb34tspqjAFtTKiNcTElx3vV4OwTcJWWxZb45J +JsxIwgbdcxvv/h6x4/FL1PGTIzAvaKlJiFRRaBBDMZ35GPeckpQxFiSbppBAeIKI +U2Bh888rbXtMcY0W0bm4ooLEaYXZrJrjptBh8jGNc7ycO9twhRgK2CFxERI1hDmK ++0BuoQKBgHLRFdJYFkNKB+j56vTlB5AFTXcjs6x0dZ4j0SDAqVYgIHErpd2bhgOz +s698rfdadwbYN4UEqvV/2NhDLx/jag4BvCermK71HaXvYnvqKw3UHGAG8K/dCCFR +eSuZnxTSoWAPjMLi64hRzbWVT+oeZuy83lG6qDygbI1z1nlYWdo3 +-----END RSA PRIVATE KEY----- diff --git a/SAS/TMSS/test/oidc/pyop_example/requirements.txt b/SAS/TMSS/test/oidc/pyop_example/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..e6b8e9f26cf02724603d4cdd5f621db2588e3b04 --- /dev/null +++ b/SAS/TMSS/test/oidc/pyop_example/requirements.txt @@ -0,0 +1,3 @@ +pyop +Flask +gunicorn \ No newline at end of file diff --git a/SAS/TMSS/test/oidc/pyop_example/signing_key.pem b/SAS/TMSS/test/oidc/pyop_example/signing_key.pem new file mode 100644 index 0000000000000000000000000000000000000000..74fe00d413e958c55ff2c8894c78ce47fc36ddcd --- /dev/null +++ b/SAS/TMSS/test/oidc/pyop_example/signing_key.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCi7nye2Ye1MrUD/sZAplfkpMkXHYduydvfvv/+Ihx1ClxKS/KG +/1EhqyBVVvhHLRs9pimKMyLm2pBE51rGOt//XKhsoFAa37VID2iz7DQuV6DGgyBS +FaKgaYBpinEQy2WcjU4eABnABV2r+K2UmGkqVJheqHqOqHUKasT4gy/6kQIDAQAB +AoGAf7u+YX6ioNCvDwHHBVojn/H8YK3axmVkhiYkZWTysGM99VVTPridL2sMfzse +jBZ1u8Av4tOyMg/5eLtz8+KmRjljpeAEFfsA1htWE8vESXnvDFwKldXD9Vi/kppb +CYqASGCBUX3i1LPYffvjUxIgD+Tjx4k56c5EN5G331flDV0CQQDP8fWraegLJ+K1 +iXGNQzpaqG3EI3vf35Yb2bJpmD39QIXFIcJJ5MZHVW+1TyvgiavM4hS2+LGA8kGh +OvMWfbYTAkEAyJWGBUmAW9mooo1Vw4tJjEWAHjHvzcQ4dqIju+WN8Xy5JTWkDD6Z +VgKGtgLt2HfpSsgej14+Rh5mrjo4SbYxSwJAKG0syq9jOk/9xjc7STBJtvhJprkT +SxnHsBBpnBfJ7WNO3l1KzVzZo2Kbvg7vQ87gBIvrZQsCT0RJuBOi0LuN2wJAAInm +Qj1gSt7axRT8FfpZyDankW0w56yPOkJVNjv3lZ5wINl0B1RjtQdstTBs0xf/WGQR +MPFf2XBbdjxRymDi4QJBAM3MUYPOlUk1UVCSQKyCkBwL3zMaPjBjD5LXkhGJzxsb +T74NznwmCib/r0Rl/KmD7/bAq7R4aheOS/OMaZyhbkk= +-----END RSA PRIVATE KEY----- diff --git a/SAS/TMSS/test/oidc/pyop_example/templates/logout.jinja2 b/SAS/TMSS/test/oidc/pyop_example/templates/logout.jinja2 new file mode 100644 index 0000000000000000000000000000000000000000..4322588f2197e9b8579819a9084f7c95c17e1d27 --- /dev/null +++ b/SAS/TMSS/test/oidc/pyop_example/templates/logout.jinja2 @@ -0,0 +1,8 @@ +<!doctype html> +<title>Logout</title> + +Do you really want to logout? +<form method="POST"> + <button type="submit" name="logout" value="logout">Yes, logout</button> + <button type="submit" name="no_logout" value="no_logout">No, cancel logout</button> +</form> \ No newline at end of file diff --git a/SAS/TMSS/test/oidc/pyop_example/views.py b/SAS/TMSS/test/oidc/pyop_example/views.py new file mode 100644 index 0000000000000000000000000000000000000000..7d7335bb224c667973519d56203f73799d0af70c --- /dev/null +++ b/SAS/TMSS/test/oidc/pyop_example/views.py @@ -0,0 +1,124 @@ +from urllib.parse import urlencode, parse_qs + +import flask +from flask import Blueprint, redirect +from flask import current_app +from flask import jsonify +from flask.helpers import make_response +from flask.templating import render_template +from oic.oic.message import TokenErrorResponse, UserInfoErrorResponse, EndSessionRequest + +from pyop.access_token import AccessToken, BearerTokenError +from pyop.exceptions import InvalidAuthenticationRequest, InvalidAccessToken, InvalidClientAuthentication, OAuthError, \ + InvalidSubjectIdentifier, InvalidClientRegistrationRequest +from pyop.util import should_fragment_encode + +oidc_provider_views = Blueprint('oidc_provider', __name__, url_prefix='') + + +@oidc_provider_views.route('/') +def index(): + return 'Hello world!' + + +@oidc_provider_views.route('/registration', methods=['POST']) +def registration_endpoint(): + try: + response = current_app.provider.handle_client_registration_request(flask.request.get_data().decode('utf-8')) + return make_response(jsonify(response.to_dict()), 201) + except InvalidClientRegistrationRequest as e: + return make_response(jsonify(e.to_dict()), status=400) + + +@oidc_provider_views.route('/authentication', methods=['GET']) +def authentication_endpoint(): + # parse authentication request + try: + auth_req = current_app.provider.parse_authentication_request(urlencode(flask.request.args), + flask.request.headers) + except InvalidAuthenticationRequest as e: + current_app.logger.debug('received invalid authn request', exc_info=True) + error_url = e.to_error_url() + if error_url: + return redirect(error_url, 303) + else: + # show error to user + return make_response('Something went wrong: {}'.format(str(e)), 400) + + # automagic authentication + authn_response = current_app.provider.authorize(auth_req, 'test_user') + response_url = authn_response.request(auth_req['redirect_uri'], should_fragment_encode(auth_req)) + return redirect(response_url, 303) + + +@oidc_provider_views.route('/.well-known/openid-configuration') +def provider_configuration(): + return jsonify(current_app.provider.provider_configuration.to_dict()) + + +@oidc_provider_views.route('/jwks') +def jwks_uri(): + return jsonify(current_app.provider.jwks) + + +@oidc_provider_views.route('/token', methods=['POST']) +def token_endpoint(): + try: + token_response = current_app.provider.handle_token_request(flask.request.get_data().decode('utf-8'), + flask.request.headers) + return jsonify(token_response.to_dict()) + except InvalidClientAuthentication as e: + current_app.logger.debug('invalid client authentication at token endpoint', exc_info=True) + error_resp = TokenErrorResponse(error='invalid_client', error_description=str(e)) + response = make_response(error_resp.to_json(), 401) + response.headers['Content-Type'] = 'application/json' + response.headers['WWW-Authenticate'] = 'Basic' + return response + except OAuthError as e: + current_app.logger.debug('invalid request: %s', str(e), exc_info=True) + error_resp = TokenErrorResponse(error=e.oauth_error, error_description=str(e)) + response = make_response(error_resp.to_json(), 400) + response.headers['Content-Type'] = 'application/json' + return response + + +@oidc_provider_views.route('/userinfo', methods=['GET', 'POST']) +def userinfo_endpoint(): + try: + response = current_app.provider.handle_userinfo_request(flask.request.get_data().decode('utf-8'), + flask.request.headers) + return jsonify(response.to_dict()) + except (BearerTokenError, InvalidAccessToken) as e: + error_resp = UserInfoErrorResponse(error='invalid_token', error_description=str(e)) + response = make_response(error_resp.to_json(), 401) + response.headers['WWW-Authenticate'] = AccessToken.BEARER_TOKEN_TYPE + response.headers['Content-Type'] = 'application/json' + return response + + +def do_logout(end_session_request): + try: + current_app.provider.logout_user(end_session_request=end_session_request) + except InvalidSubjectIdentifier as e: + return make_response('Logout unsuccessful!', 400) + + redirect_url = current_app.provider.do_post_logout_redirect(end_session_request) + if redirect_url: + return redirect(redirect_url, 303) + + return make_response('Logout successful!') + + +@oidc_provider_views.route('/logout', methods=['GET', 'POST']) +def end_session_endpoint(): + if flask.request.method == 'GET': + # redirect from RP + end_session_request = EndSessionRequest().deserialize(urlencode(flask.request.args)) + flask.session['end_session_request'] = end_session_request.to_dict() + return render_template('logout.jinja2') + else: + form = parse_qs(flask.request.get_data().decode('utf-8')) + if 'logout' in form: + return do_logout(EndSessionRequest().from_dict(flask.session['end_session_request'])) + else: + return make_response('You chose not to logout') diff --git a/SAS/TMSS/test/oidc/pyop_example/wsgi.py b/SAS/TMSS/test/oidc/pyop_example/wsgi.py new file mode 100644 index 0000000000000000000000000000000000000000..f98a0a821882982289dddc1606622dee3b0084b8 --- /dev/null +++ b/SAS/TMSS/test/oidc/pyop_example/wsgi.py @@ -0,0 +1,7 @@ +import logging + +from example.app import oidc_provider_init_app + +name = 'oidc_provider' +app = oidc_provider_init_app(name) +logging.basicConfig(level=logging.DEBUG) diff --git a/SAS/TMSS/test/oidc/readme.txt b/SAS/TMSS/test/oidc/readme.txt new file mode 100644 index 0000000000000000000000000000000000000000..435abc6cc6049c56de632a53f556786241eb7eaf --- /dev/null +++ b/SAS/TMSS/test/oidc/readme.txt @@ -0,0 +1,31 @@ +This directory contains a few different OpenID Connect Identity Provider implementations to test against. +This has not yet been tested/integrated with the web frontend POC behind nginx, but at least the Mozilla test container +works against the Django dev server. + +- Test Mozilla Django OIDC: This is currently the only working solution. It is a docker setup that the developers of + the Django plugin that we use have created for their own testing. The docker compose file + currently pulls things externally, so this is the vanilla setup. The downside of this is + that due to how OpenID works, the identity provider needs to know the callback URIs of the + services that use it and that is hardcoded. So either we set up our test deployment to use + same container/host names, or we have to patch things the way we need it. I chose the latter + and adapted the fixtures to have test client on localhost and also add a test user. + So building and running the oidc_tesprovider should provide an OpenID Identity Provider on + port 8080, which is comfortable to talk to Django on http://localhost:8000. + You should be able to logon on http://localhost:8000/oidc/authenticate as 'paulus'/'pauluspass' +- PYOP: pyop is a Python-based identity provider that can be simply installed via pip. It seems to be more of a library + than a mature and ready-to-deploy product. The project's repository contains an example implementation, which + looked good at first, since it's quite a simple flask-based setup without much overhead or tons of dependencies. + I almost got it to work, and there is useful logging once you managed to make Django actually talk to it, but + I did not continue on getting this to work. See below for some guidance: + A caveat of pyop is that there don't seem to be fixtures for preconfiguring clients, so before being able to + talk to it, you have to register as a client with the callback URL you want to use or it will complain, e.g.: + curl -k -X POST -d '{"redirect_uris": ["http://localhost:8000/oidc/callback/"] }' https://localhost:9090/registration + That will return a json with client_id and client_secret that have to be placed in the settings.py of Django, + or even better in environment variables before tmss is started (we could/should automize that for testing). + Pyop then accepts the request but chokes on it because it does not support the client authentication method + that Django uses for its request. (Must be client_secret_basic, but apparently is not.) This could also be an + issue of the Mozilla Django Plugin we use or configurable (OIDC_TOKEN_USE_BASIC_AUTH=True?)...? +- Keycloak: This seems to be a full blown and quite mature identity provider implementation in Java. + I found a nice docker solution that supposedly sets up a test provider with fixtures and all, + but unfortunately it does not build currently (Docker image seems unmaintained, so maybe not + the best choice anyway).