diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ swh-*/ +!docker/services/swh-*/ packages/* snippets/ !packages/README diff --git a/docker/conf/keycloak/swh-realm.json b/docker/conf/keycloak/swh-realm.json new file mode 100644 --- /dev/null +++ b/docker/conf/keycloak/swh-realm.json @@ -0,0 +1,1982 @@ +{ + "id": "SoftwareHeritage", + "realm": "SoftwareHeritage", + "notBefore": 0, + "defaultSignatureAlgorithm": "RS256", + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 600, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": true, + "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": "7b3f4e43-9452-43e9-a0cd-79a3407f1322", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "SoftwareHeritage", + "attributes": {} + }, + { + "id": "a76bd910-e61e-4b33-8944-55eb9e572690", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "SoftwareHeritage", + "attributes": {} + } + ], + "client": { + "realm-management": [ + { + "id": "df0f7bb3-7f49-420a-b70c-6591bb145c40", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-users", + "query-groups" + ] + } + }, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + }, + { + "id": "f988dca6-fa3b-49d3-ae17-05dd3a8e536c", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + }, + { + "id": "546717d8-685e-4bc2-86d7-9ed3b4bb18fb", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + }, + { + "id": "ff405dc7-990e-4128-87ad-d03d1f84ab69", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + }, + { + "id": "a498b566-5b8f-409c-8319-d99bae34f790", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + }, + { + "id": "67f8f2b0-dfe9-4bbe-bcc6-d8d8b4935d0d", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + }, + { + "id": "ae6feccb-194a-4eb4-96b4-75bee2a1815f", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + }, + { + "id": "19161555-ecb6-4f61-8863-bcdacf8db90a", + "name": "realm-admin", + "description": "${role_realm-admin}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "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" + ] + } + }, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + }, + { + "id": "0d59cfea-87e0-48b6-9163-b46aae33a5d0", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + }, + { + "id": "3f46938c-7f8a-4b76-9e8c-4dd60e753d8d", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-clients" + ] + } + }, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + }, + { + "id": "ff5dec7d-9b84-4ccb-acb6-083babe1e7fc", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + }, + { + "id": "3dad9fcf-71ad-429d-bb5b-aaa4b31485e3", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + }, + { + "id": "25d4c2f4-5163-496e-901d-15c668ced462", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + }, + { + "id": "4340a075-f781-4455-9a1b-784f49f3c6ba", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + }, + { + "id": "d52c6616-a65b-4628-9d1f-96309c0cf7c8", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + }, + { + "id": "63f18b95-2024-45c6-931c-bfb4dddfed60", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + }, + { + "id": "dc004eef-6ead-45f1-9fc7-91c38465ce6f", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + }, + { + "id": "a6d09a9b-5536-4cd9-8e2a-0eb9b0a23925", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + }, + { + "id": "6ea5f00b-f508-4fa4-979e-2dbb69b7793f", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "attributes": {} + } + ], + "security-admin-console": [], + "swh-web": [], + "admin-cli": [], + "broker": [ + { + "id": "a01885da-7396-40b7-8f7b-1efdcee2d8be", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "7ed32ab4-f567-411a-8c94-3dec90cbb404", + "attributes": {} + } + ], + "account": [ + { + "id": "b146afd2-65f6-4dc1-bea9-fc79d2dbeba1", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "8c5474f0-dab5-488a-aa28-68e7e877283c", + "attributes": {} + }, + { + "id": "65a5a0e1-25c7-445b-a7f5-e7174d01e4cf", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "8c5474f0-dab5-488a-aa28-68e7e877283c", + "attributes": {} + }, + { + "id": "0f598cad-1841-4a1d-96fe-4fac7d7acfee", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": [ + "manage-account-links" + ] + } + }, + "clientRole": true, + "containerId": "8c5474f0-dab5-488a-aa28-68e7e877283c", + "attributes": {} + } + ] + } + }, + "groups": [ + { + "id": "738da969-689b-4c2f-98ba-e47444f66341", + "name": "staff", + "path": "/staff", + "attributes": {}, + "realmRoles": [], + "clientRoles": {}, + "subGroups": [] + } + ], + "defaultRoles": [ + "offline_access", + "uma_authorization" + ], + "requiredCredentials": [ + "password" + ], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpSupportedApplications": [ + "FreeOTP", + "Google Authenticator" + ], + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": [ + "offline_access" + ] + } + ], + "clients": [ + { + "id": "8c5474f0-dab5-488a-aa28-68e7e877283c", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/SoftwareHeritage/account/", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "defaultRoles": [ + "manage-account", + "view-profile" + ], + "redirectUris": [ + "/realms/SoftwareHeritage/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", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "1a6ecc53-9a1a-48e1-89c4-7f4cd410e9e8", + "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", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "7ed32ab4-f567-411a-8c94-3dec90cbb404", + "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", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "dab29929-cf51-4dc8-932b-0a4b83754dab", + "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", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "1ce67379-b869-4394-9c63-6662a3a888b3", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/SoftwareHeritage/console/", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [ + "/admin/SoftwareHeritage/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": "0055821a-5bfc-4f7d-b1f2-8f82c062b189", + "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", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "86d7ba1e-a4ca-4fe0-8769-b6e10fd255ed", + "clientId": "swh-web", + "baseUrl": "http://localhost:5004/", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [ + "http://localhost:5004/*" + ], + "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, + "protocolMappers": [ + { + "id": "c1b07079-1020-4919-af16-4cf1e39701af", + "name": "swh-web audience mapper", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-mapper", + "consentRequired": false, + "config": { + "included.client.audience": "swh-web", + "id.token.claim": "false", + "access.token.claim": "true" + } + }, + { + "id": "1fc70caa-f614-4b9c-b1f9-7431029c0eba", + "name": "swh-web group mapper", + "protocol": "openid-connect", + "protocolMapper": "oidc-group-membership-mapper", + "consentRequired": false, + "config": { + "full.path": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "userinfo.token.claim": "true" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + } + ], + "clientScopes": [ + { + "id": "4ad2f987-fd9c-4bf6-b2c9-ca34434dc057", + "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": "65233398-740b-4091-b840-5deddb6b30f7", + "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": "c87e6c1e-fe96-4451-be91-40fdd871a3c1", + "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": "f2f43c09-0e4f-4791-ace7-97ee695c400c", + "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": "d5c9d023-8d19-4b9b-9dc0-cdd488263f5f", + "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": "bbc50e66-2fbe-4110-9843-d61204f260c3", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "40c84407-47d1-44cb-b727-83c091a1b007", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "multivalued": "true", + "user.attribute": "foo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + }, + { + "id": "f74aa38d-3aee-45ed-88b1-dd9e8f0dc28b", + "name": "upn", + "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": "upn", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "84225fc7-34eb-420f-95fc-482eb050d762", + "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": "08bae679-8ad2-4a10-be18-6c239a1ecd98", + "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": "02affbbf-f851-465f-851a-527bb8916380", + "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": "9e71d2c2-14e5-41ee-8b60-69e7eeb27d94", + "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": "2e611756-8ebc-418b-9b50-ec490a658eb9", + "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": "88066d20-1ef6-479c-b3fc-7dd9fbd1d7b8", + "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": "945ff2e8-ad43-4575-8d0b-08b03b7ef7c1", + "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": "e0dcfe90-1322-4f3f-a410-275eb60c690b", + "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": "f553480d-c2e2-440c-b784-085d1c347be9", + "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": "c123e90b-f038-42b2-9dfe-32b8f200dfdd", + "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": "0ee2e925-1a73-43a2-a740-3a344b1b3f12", + "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": "30221378-13ee-40cf-adc3-649682ae0572", + "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": "d8e3f1f2-2919-4b64-8e9c-e3c10d4c8041", + "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": "f1cd4ffc-55ad-4919-9196-5d3e3f5b05a2", + "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": "824a0d08-f996-4dcd-8fdc-75064319e510", + "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": "e83e6fee-d8c7-4873-80b0-7cd9dffc8e2e", + "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": "eae328bd-1f10-4931-b39d-cd2a6098d77f", + "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": "f6f76ec1-77fb-44ef-9d99-1d908b2d2f43", + "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": "2c477c75-bdc3-4a0e-94c8-fa8018f69de9", + "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": "71528047-b2ea-417b-b81f-28d9c4b164d8", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "6b07e80f-113a-4de9-8bff-fd7212721642", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "dc8c85c2-a83c-461b-9d0c-7dad516669ea", + "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": "58bf5529-4eea-4ec3-aa91-356faa154ed0", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "a3b77a34-4515-40e7-9fc3-dedc17b5e1b4", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "86bbc202-449d-4eff-9f38-e0584eacd76a", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "c92a5a7a-d86f-4ccd-960f-7893897c1c49", + "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": "9a939cc3-3354-4327-a044-c1e7b3f2ae7d", + "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", + "microprofile-jwt" + ], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection": "1; mode=block", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" + }, + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": [ + "jboss-logging" + ], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "1b44ba62-65f0-4771-bd11-bfc87edfbf90", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "629ba995-9b62-4c2a-80fe-1d24337f1713", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": [ + "true" + ], + "client-uris-must-match": [ + "true" + ] + } + }, + { + "id": "4265e539-998d-4471-ad80-adfea944b266", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-user-property-mapper", + "saml-user-attribute-mapper", + "saml-role-list-mapper", + "oidc-address-mapper", + "oidc-full-name-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-usermodel-property-mapper", + "oidc-usermodel-attribute-mapper" + ] + } + }, + { + "id": "1a5085dc-f8d6-4ac7-a678-c3345621441b", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": [ + "200" + ] + } + }, + { + "id": "0ea2b95a-b92b-42db-8755-7e0da93bc70e", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "798e9a8c-518d-41cf-99f9-be4d7a3f4e14", + "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", + "oidc-usermodel-attribute-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-user-property-mapper", + "oidc-usermodel-property-mapper", + "oidc-address-mapper", + "saml-role-list-mapper" + ] + } + }, + { + "id": "8e39a271-4bf2-4b80-a8c6-5376a9ccd18f", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "867310a6-d5db-44f1-829e-c27b0ac94408", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "cb0b2cdf-9dfe-4777-a419-3180276426bf", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "f8a88205-b0e7-4961-a175-cb49c9e8c53f", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "5a7bd524-75ae-4570-afa4-a337e4337bf4", + "name": "hmac-generated", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS256" + ] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "8067b515-ed76-41a4-863b-e92318722109", + "alias": "Account verification options", + "description": "Method with which to verity the existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "requirement": "ALTERNATIVE", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "ALTERNATIVE", + "priority": 20, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "6fe995cb-7b39-4648-a197-88e360feb4d7", + "alias": "Authentication Options", + "description": "Authentication options.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "basic-auth", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "basic-auth-otp", + "requirement": "DISABLED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-spnego", + "requirement": "DISABLED", + "priority": 30, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "b18b5875-6286-4aa2-a8ce-bd58efb333e3", + "alias": "Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-otp-form", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "26811473-1d51-41b8-ba6d-e861dd6d5fec", + "alias": "Direct Grant - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "direct-grant-validate-otp", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "3633ad47-e0d7-45bd-b69b-734e4395a803", + "alias": "First broker login - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-otp-form", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "e027af83-e35d-4d54-8c95-95043d99d050", + "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 + }, + { + "requirement": "REQUIRED", + "priority": 20, + "flowAlias": "Account verification options", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "96a2ea5c-88d7-44a6-a325-88c8ebb516b7", + "alias": "Reset - Conditional OTP", + "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "reset-otp", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "5bb86bb8-4fd4-4516-9850-256321640b07", + "alias": "User creation or linking", + "description": "Flow for the existing/non-existing user alternatives", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "requirement": "ALTERNATIVE", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "ALTERNATIVE", + "priority": 20, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "acbe1221-b040-4947-8cb7-18659f26928d", + "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 + }, + { + "requirement": "CONDITIONAL", + "priority": 20, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "3d711aff-7168-4eee-94f1-e568f24ea2ff", + "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": "76550edf-9644-473d-b258-553fdc8e1a60", + "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": "21708ba3-a5df-476f-b2d3-4b9983c11b18", + "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 + }, + { + "requirement": "CONDITIONAL", + "priority": 30, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "42df77b5-080a-4e05-8cdd-6c666730eabe", + "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": "d9a52b01-6f9f-440f-a267-8b378bdc180d", + "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 + }, + { + "requirement": "REQUIRED", + "priority": 20, + "flowAlias": "User creation or linking", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "bbd9bff5-6123-41a3-bf16-1072a10faba6", + "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 + }, + { + "requirement": "CONDITIONAL", + "priority": 20, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "95d2ebd6-a09a-4458-afa1-2536cc7da001", + "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 + }, + { + "requirement": "REQUIRED", + "priority": 20, + "flowAlias": "Authentication Options", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "cb053229-3b3a-4d0d-a442-052f3b917f5f", + "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": "b9cd6dda-82e3-4b5b-a1dc-faa0859bf616", + "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": "db7f6b3c-2cf5-4640-9722-9087b3f8eb41", + "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 + }, + { + "requirement": "CONDITIONAL", + "priority": 40, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "80b86ef2-d008-44ae-9536-c9a0e39d4c92", + "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": "817e440b-0132-4644-a9d1-5cd99afbe36a", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "d7434a41-24b0-41c1-bfff-7d0784265915", + "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": { + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "_browser_header.xRobotsTag": "none", + "webAuthnPolicyRpEntityName": "keycloak", + "failureFactor": "30", + "actionTokenGeneratedByUserLifespan": "300", + "maxDeltaTimeSeconds": "43200", + "webAuthnPolicySignatureAlgorithms": "ES256", + "frontendUrl": "http://localhost:5080/keycloak/auth/", + "offlineSessionMaxLifespan": "5184000", + "_browser_header.contentSecurityPolicyReportOnly": "", + "bruteForceProtected": "false", + "_browser_header.contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "_browser_header.xXSSProtection": "1; mode=block", + "_browser_header.xFrameOptions": "SAMEORIGIN", + "_browser_header.strictTransportSecurity": "max-age=31536000; includeSubDomains", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "permanentLockout": "false", + "quickLoginCheckMilliSeconds": "1000", + "webAuthnPolicyCreateTimeout": "0", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "maxFailureWaitSeconds": "900", + "minimumQuickLoginWaitSeconds": "60", + "defaultSignatureAlgorithm": "RS256", + "webAuthnPolicyAvoidSameAuthenticatorRegister": "false", + "_browser_header.xContentTypeOptions": "nosniff", + "actionTokenGeneratedByAdminLifespan": "43200", + "waitIncrementSeconds": "60", + "offlineSessionMaxLifespanEnabled": "true" + }, + "keycloakVersion": "8.0.1", + "userManagedAccessAllowed": false +} \ No newline at end of file diff --git a/docker/conf/nginx.conf b/docker/conf/nginx.conf --- a/docker/conf/nginx.conf +++ b/docker/conf/nginx.conf @@ -105,5 +105,16 @@ set $upstream "http://swh-web:5004"; proxy_pass $upstream; } + location /keycloak { + set $upstream "http://keycloak:8080"; + proxy_pass $upstream; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Server $host; + proxy_set_header X-Forwarded-Port $server_port; + proxy_set_header X-Forwarded-Proto $scheme; + } } } diff --git a/docker/conf/web.yml b/docker/conf/web.yml --- a/docker/conf/web.yml +++ b/docker/conf/web.yml @@ -69,3 +69,7 @@ - 0.0.0.0/0 search: {} + +keycloak: + server_url: http://keycloak:8080/keycloak/auth/ + realm_name: SoftwareHeritage diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -82,6 +82,25 @@ ports: - 5080:5080 + keycloak-db: + image: postgres:11 + env_file: + - ./env/keycloak-db.env + environment: + # unset PGHOST as db service crashes otherwise + PGHOST: + + keycloak: + build: services/keycloak + env_file: + - ./env/keycloak.env + volumes: + - "./conf/keycloak/swh-realm.json:/etc/keycloak/swh-realm.json:ro" + expose: + - "8080" + depends_on: + - keycloak-db + # Scheduler swh-scheduler-db: @@ -234,6 +253,7 @@ - swh-objstorage - swh-storage - swh-idx-storage + - keycloak env_file: - ./env/common_python.env environment: @@ -244,6 +264,7 @@ volumes: - "./conf/web.yml:/web.yml:ro" - "./services/swh-web/entrypoint.sh:/entrypoint.sh:ro" + - "./services/swh-web/keycloak_create_test_users.py:/keycloak_create_test_users.py:ro" swh-deposit-db: image: postgres:11 diff --git a/docker/env/keycloak-db.env b/docker/env/keycloak-db.env new file mode 100644 --- /dev/null +++ b/docker/env/keycloak-db.env @@ -0,0 +1,4 @@ +PGHOST=keycloak-db +POSTGRES_USER=keycloak +POSTGRES_PASSWORD=testpassword +POSTGRES_DB=keycloak \ No newline at end of file diff --git a/docker/env/keycloak.env b/docker/env/keycloak.env new file mode 100644 --- /dev/null +++ b/docker/env/keycloak.env @@ -0,0 +1,10 @@ +DB_VENDOR=POSTGRES +DB_ADDR=keycloak-db +DB_DATABASE=keycloak +DB_USER=keycloak +DB_SCHEMA=public +DB_PASSWORD=testpassword +KEYCLOAK_USER=admin +KEYCLOAK_PASSWORD=admin +PROXY_ADDRESS_FORWARDING=true +JAVA_TOOL_OPTIONS=-Dkeycloak.profile=preview -Dkeycloak.profile.feature.token_exchange=enabled -Dkeycloak.migration.action=import -Dkeycloak.migration.provider=singleFile -Dkeycloak.migration.file=/etc/keycloak/swh-realm.json -Dkeycloak.migration.strategy=OVERWRITE_EXISTING diff --git a/docker/services/keycloak/Dockerfile b/docker/services/keycloak/Dockerfile new file mode 100644 --- /dev/null +++ b/docker/services/keycloak/Dockerfile @@ -0,0 +1,7 @@ +FROM jboss/keycloak +USER jboss +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/swh-web/entrypoint.sh b/docker/services/swh-web/entrypoint.sh --- a/docker/services/swh-web/entrypoint.sh +++ b/docker/services/swh-web/entrypoint.sh @@ -29,7 +29,10 @@ echo "Migrating db using ${DJANGO_SETTINGS_MODULE}" django-admin migrate --settings=${DJANGO_SETTINGS_MODULE} - echo "Creating admin user" + echo "Creating some test users in Keycloak" + python3 /keycloak_create_test_users.py + + echo "Creating Django admin user" echo "$create_admin_script" | python3 -m swh.web.manage shell echo "starting the swh-web server" diff --git a/docker/services/swh-web/keycloak_create_test_users.py b/docker/services/swh-web/keycloak_create_test_users.py new file mode 100644 --- /dev/null +++ b/docker/services/swh-web/keycloak_create_test_users.py @@ -0,0 +1,161 @@ +# 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 swh.web.config import get_config +from keycloak import KeycloakAdmin + + +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) + + +admin = { + 'username': 'admin', + 'password': 'admin' +} + +keycloak_config = get_config()['keycloak'] +client_id = 'swh-web' + +# login as admin in master realm +keycloak_admin = KeycloakAdmin(keycloak_config['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' +) + +# set swh realm name in order to create users in it +keycloak_admin.realm_name = keycloak_config['realm_name'] + +# update swh realm clients base urls as we use a reverse proxy +assign_client_base_url( + keycloak_admin, + 'account', + '/keycloak/auth/realms/SoftwareHeritage/account' +) + +assign_client_base_url( + keycloak_admin, + 'security-admin-console', + '/keycloak/auth/admin/SoftwareHeritage/console/index.html' +) + +# create an admin user in the swh realm +user_data = { + 'email': 'admin@swhrealm.org', + 'username': admin['username'], + 'firstName': admin['username'], + 'lastName': admin['username'], + 'credentials': [{ + 'value': admin['username'], + 'type': admin['password'], + 'temporary': False + }], + 'enabled': True, + 'emailVerified': False, +} +keycloak_admin.create_user(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(keycloak_config['server_url'], + admin['username'], + admin['password'], + keycloak_config['realm_name']) + +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, +} +keycloak_admin.create_user(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, +} +keycloak_admin.create_user(user_data)