diff --git a/docker/services/keycloak/Dockerfile b/docker/services/keycloak/Dockerfile index 717085d..db05ef9 100644 --- a/docker/services/keycloak/Dockerfile +++ b/docker/services/keycloak/Dockerfile @@ -1,19 +1,21 @@ FROM jboss/keycloak USER root +# install git to get custom keycloak theme in service entrypoint +RUN microdnf install -y git # install python3 and python-keycloak, this is needed to execute a # custom config script after keycloak server is up RUN microdnf install -y python3 && microdnf clean all RUN pip3 install python-keycloak # install wait-for-it script RUN curl https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh > /wait-for-it.sh RUN chmod +x /wait-for-it.sh USER jboss # Modify some config files for keycloak to work properly behind a reverse proxy # https://stackoverflow.com/questions/44624844/configure-reverse-proxy-for-keycloak-docker-with-custom-base-url RUN sed -i -e 's/auth<\/web-context>/keycloak\/auth<\/web-context>/' $JBOSS_HOME/standalone/configuration/standalone.xml RUN sed -i -e 's/auth<\/web-context>/keycloak\/auth<\/web-context>/' $JBOSS_HOME/standalone/configuration/standalone-ha.xml RUN sed -i -e 's/name="\/"/name="\/keycloak\/"/' $JBOSS_HOME/standalone/configuration/standalone.xml RUN sed -i -e 's/name="\/"/name="\/keycloak\/"/' $JBOSS_HOME/standalone/configuration/standalone-ha.xml RUN sed -i -e 's/\/auth/\/keycloak\/auth"/' $JBOSS_HOME/welcome-content/index.html diff --git a/docker/services/keycloak/entrypoint.sh b/docker/services/keycloak/entrypoint.sh index 5ccea4c..25d6118 100755 --- a/docker/services/keycloak/entrypoint.sh +++ b/docker/services/keycloak/entrypoint.sh @@ -1,14 +1,21 @@ #!/bin/bash # turn on bash's job control set -m +cd +if [ ! -d swh-keycloak-theme ] +then + git clone https://forge.softwareheritage.org/source/swh-keycloak-theme.git + ln -s /opt/jboss/swh-keycloak-theme/swh/ /opt/jboss/keycloak/themes/swh +fi + echo "Starting Keycloak" /opt/jboss/tools/docker-entrypoint.sh -b 0.0.0.0& echo "Waiting for Keycloak server to be up" /wait-for-it.sh localhost:8080 -s --timeout=0 echo "Configuring Keycloak to be used in docker environment" echo "and creating some test users in the SoftwareHeritage realm" /keycloak_swh_setup.py fg %1 diff --git a/docker/services/keycloak/keycloak_swh_setup.py b/docker/services/keycloak/keycloak_swh_setup.py index dac1acf..60e9b24 100755 --- a/docker/services/keycloak/keycloak_swh_setup.py +++ b/docker/services/keycloak/keycloak_swh_setup.py @@ -1,235 +1,244 @@ #!/usr/bin/env python3 # Copyright (C) 2020 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU Affero General Public License version 3, or any later version # See top-level LICENSE file for more information from keycloak import KeycloakAdmin server_url = 'http://localhost:8080/keycloak/auth/' realm_name = 'SoftwareHeritage' admin = { 'username': 'admin', 'password': 'admin' } def assign_client_base_url(keycloak_admin, client_name, base_url): client_data = { 'baseUrl': base_url, 'clientId': client_name } client_id = keycloak_admin.get_client_id(client_name) keycloak_admin.update_client(client_id, client_data) def assign_client_role_to_user(keycloak_admin, client_name, client_role, username): client_id = keycloak_admin.get_client_id(client_name) staff_user_role = keycloak_admin.get_client_role(client_id, client_role) user_id = keycloak_admin.get_user_id(username) keycloak_admin.assign_client_role(user_id, client_id, staff_user_role) def assign_client_roles_to_user(keycloak_admin, client_name, client_roles, username): for client_role in client_roles: assign_client_role_to_user(keycloak_admin, client_name, client_role, username) def create_user(keycloak_admin, user_data): try: keycloak_admin.create_user(user_data) except Exception: # user already created pass # login as admin in master realm keycloak_admin = KeycloakAdmin(server_url, admin['username'], admin['password']) # update master realm clients base urls as we use a reverse proxy assign_client_base_url( keycloak_admin, 'account', '/keycloak/auth/realms/master/account' ) assign_client_base_url( keycloak_admin, 'security-admin-console', '/keycloak/auth/admin/master/console/index.html' ) +keycloak_admin.update_realm('master', payload={ + 'loginTheme': 'swh', + 'accountTheme': 'swh', + 'adminTheme': 'swh', +}) + # create swh realm keycloak_admin.create_realm(payload={ 'realm': realm_name, 'rememberMe': True, 'attributes': { 'frontendUrl': 'http://localhost:5080/keycloak/auth/' }, 'enabled': True, + 'loginTheme': 'swh', + 'accountTheme': 'swh', + 'adminTheme': 'swh', }, skip_exists=True) # set swh realm name in order to create users in it keycloak_admin.realm_name = realm_name # update swh realm clients base urls as we use a reverse proxy assign_client_base_url( keycloak_admin, 'account', f'/keycloak/auth/realms/{realm_name}/account' ) assign_client_base_url( keycloak_admin, 'security-admin-console', f'/keycloak/auth/admin/{realm_name}/console/index.html' ) # create an admin user in the swh realm user_data = { 'email': 'admin@example.org', 'username': admin['username'], 'firstName': admin['username'], 'lastName': admin['username'], 'credentials': [{ 'value': admin['username'], 'type': admin['password'], 'temporary': False }], 'enabled': True, 'emailVerified': False, } create_user(keycloak_admin, user_data) # assign realm admin roles to created user realm_management_roles = [ 'view-users', 'view-events', 'view-identity-providers', 'manage-identity-providers', 'create-client', 'query-clients', 'query-realms', 'manage-events', 'view-clients', 'manage-realm', 'impersonation', 'manage-clients', 'view-authorization', 'query-users', 'view-realm', 'manage-authorization', 'manage-users', 'query-groups' ] assign_client_roles_to_user(keycloak_admin, 'realm-management', realm_management_roles, admin['username']) # login as admin in swh realm keycloak_admin = KeycloakAdmin(server_url, admin['username'], admin['password'], realm_name) # create swh-web public client keycloak_admin.create_client(payload={ 'id': 'swh-web', 'clientId': 'swh-web', 'surrogateAuthRequired': False, 'enabled': True, 'redirectUris': [ 'http://localhost:5004/*', ], 'bearerOnly': False, 'consentRequired': False, 'standardFlowEnabled': True, 'implicitFlowEnabled': False, 'directAccessGrantsEnabled': True, 'serviceAccountsEnabled': False, 'publicClient': True, 'frontchannelLogout': False, 'protocol': 'openid-connect', 'fullScopeAllowed': True, 'protocolMappers': [ { 'name': 'user groups', 'protocol': 'openid-connect', 'protocolMapper': 'oidc-group-membership-mapper', 'consentRequired': False, 'config': { 'full.path': True, 'userinfo.token.claim': True, 'id.token.claim': True, 'access.token.claim': True, 'claim.name': 'groups', 'jsonType.label': 'String' } }, { 'name': 'audience', 'protocol': 'openid-connect', 'protocolMapper': 'oidc-audience-mapper', 'consentRequired': False, 'config': { 'included.client.audience': 'swh-web', 'id.token.claim': True, 'access.token.claim': True } } ], }, skip_exists=True) # create staff group keycloak_admin.create_group(payload={ 'name': 'staff', }, skip_exists=True) groups = keycloak_admin.get_groups() admin_user_id = keycloak_admin.get_user_id(username=admin['username']) for group in groups: if group['name'] == 'staff': keycloak_admin.group_user_add(admin_user_id, group['id']) break # create some test users user_data = { 'email': 'john.doe@example.org', 'username': 'johndoe', 'firstName': 'John', 'lastName': 'Doe', 'credentials': [{ 'value': 'johndoe-swh', 'type': 'password', 'temporary': False }], 'enabled': True, 'emailVerified': False, } create_user(keycloak_admin, user_data) user_data = { 'email': 'jane.doe@example.org', 'username': 'janedoe', 'firstName': 'Jane', 'lastName': 'Doe', 'credentials': [{ 'value': 'janedoe-swh', 'type': 'password', 'temporary': False }], 'enabled': True, 'emailVerified': False, } create_user(keycloak_admin, user_data)