diff --git a/.github/debug-in-docker.run.xml b/.github/debug-in-docker.run.xml deleted file mode 100644 index 0dbf6dc..0000000 --- a/.github/debug-in-docker.run.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.github/docs/config-auth-flow-override.png b/.github/docs/config-auth-flow-override.png new file mode 100644 index 0000000..4a4dd7a Binary files /dev/null and b/.github/docs/config-auth-flow-override.png differ diff --git a/.github/docs/config-authentication.png b/.github/docs/config-authentication.png new file mode 100644 index 0000000..9f45ec7 Binary files /dev/null and b/.github/docs/config-authentication.png differ diff --git a/.github/docs/config-client-login-theme.png b/.github/docs/config-client-login-theme.png new file mode 100644 index 0000000..e4880f5 Binary files /dev/null and b/.github/docs/config-client-login-theme.png differ diff --git a/.github/docs/config-execution.png b/.github/docs/config-execution.png new file mode 100644 index 0000000..b989384 Binary files /dev/null and b/.github/docs/config-execution.png differ diff --git a/.github/docs/login-form-error.png b/.github/docs/login-form-error.png new file mode 100644 index 0000000..60dfe6c Binary files /dev/null and b/.github/docs/login-form-error.png differ diff --git a/.github/docs/login-form.png b/.github/docs/login-form.png new file mode 100644 index 0000000..8b170f4 Binary files /dev/null and b/.github/docs/login-form.png differ diff --git a/.github/img/example-client-config.png b/.github/img/example-client-config.png deleted file mode 100644 index 5776291..0000000 Binary files a/.github/img/example-client-config.png and /dev/null differ diff --git a/.github/img/foot-size-execution-config-tooltip.png b/.github/img/foot-size-execution-config-tooltip.png deleted file mode 100644 index fd4e54b..0000000 Binary files a/.github/img/foot-size-execution-config-tooltip.png and /dev/null differ diff --git a/.github/img/foot-size-form-config.png b/.github/img/foot-size-form-config.png deleted file mode 100644 index 0e08d76..0000000 Binary files a/.github/img/foot-size-form-config.png and /dev/null differ diff --git a/.github/img/foot-size-form-error.png b/.github/img/foot-size-form-error.png deleted file mode 100644 index 99ac9c2..0000000 Binary files a/.github/img/foot-size-form-error.png and /dev/null differ diff --git a/.github/img/foot-size-form.png b/.github/img/foot-size-form.png deleted file mode 100644 index b5be397..0000000 Binary files a/.github/img/foot-size-form.png and /dev/null differ diff --git a/.github/img/new-authenticator-execution.png b/.github/img/new-authenticator-execution.png deleted file mode 100644 index f9efc9b..0000000 Binary files a/.github/img/new-authenticator-execution.png and /dev/null differ diff --git a/.github/workflows/automation-tests.yml b/.github/workflows/automation-tests.yml deleted file mode 100644 index 2da8ef7..0000000 --- a/.github/workflows/automation-tests.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: automation tests - -on: - push: - branches: [ main, development, ci ] - pull_request: - branches: [ main, development, ci ] - -jobs: - automation-tests: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Set up JDK 11 - uses: actions/setup-java@v2 - with: - java-version: '11' - distribution: 'adopt' - - - name: Set version from git commit SHA - run: mvn -B -ntp versions:set -DgenerateBackupPoms=false -DnewVersion="${GITHUB_SHA::7}" - - - name: Build authenticator jar file - run: mvn -B -ntp package - - - name: Build test Docker container - run: docker-compose build --build-arg VERSION="${GITHUB_SHA::7}" - - - name: Run automation tests - run: mvn -B -ntp test -P automation-tests -D selenide.headless=true diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 0000000..4d6a40f --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,21 @@ +name: main +on: + push: + branches: [ main, development ] + pull_request: + branches: [ main ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Maven + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'adopt' + + - name: Build with Maven + run: mvn -B -ntp package --file pom.xml \ No newline at end of file diff --git a/.github/workflows/release-github-tag.yml b/.github/workflows/release-github-tag.yml index 0c30bcc..0158b40 100644 --- a/.github/workflows/release-github-tag.yml +++ b/.github/workflows/release-github-tag.yml @@ -8,13 +8,12 @@ jobs: release-github-tag: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - - name: Set up Maven Central Repository - uses: actions/setup-java@v2 + - uses: actions/setup-java@v4 with: - java-version: '11' distribution: 'adopt' + java-version: '17' server-id: ossrh server-username: MAVEN_USERNAME server-password: MAVEN_PASSWORD @@ -28,23 +27,6 @@ jobs: - name: Set version from git tag run: mvn -B -ntp versions:set -DgenerateBackupPoms=false -DnewVersion="$TAG" - - name: Import GPG key - run: | - cat <(echo -e "${{ secrets.OSSRH_GPG_SECRET_KEY }}") | gpg --batch --import - gpg --list-secret-keys --keyid-format LONG - - - name: Publish maven package - run: | - mvn \ - --no-transfer-progress \ - --batch-mode \ - -D gpg.passphrase=${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} \ - -P ossrh \ - clean deploy - env: - MAVEN_USERNAME: kilmajster - MAVEN_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} - - name: Add jar to Github Release uses: svenstaro/upload-release-action@v2 continue-on-error: true @@ -53,24 +35,3 @@ jobs: file: target/keycloak-username-password-attribute-authenticator-${{ env.TAG }}.jar asset_name: keycloak-username-password-attribute-authenticator-${{ env.TAG }}.jar tag: ${{ github.ref }} - - - name: Build Docker init container - run: | - docker build \ - --build-arg VERSION="$TAG" \ - -f src/main/docker/initContainer.Dockerfile \ - -t kilmajster/keycloak-username-password-attribute-authenticator:"$TAG" \ - -t kilmajster/keycloak-username-password-attribute-authenticator:latest \ - . - - - name: Log into Docker Hub - uses: docker/login-action@v1 - with: - username: kilmajster - password: ${{ secrets.DOCKER_HUB_TOKEN }} - - - name: Push tagged Docker image - run: docker push kilmajster/keycloak-username-password-attribute-authenticator:"$TAG" - - - name: Push latest Docker image - run: docker push kilmajster/keycloak-username-password-attribute-authenticator:latest \ No newline at end of file diff --git a/README.md b/README.md index a7dc167..b620b2c 100644 --- a/README.md +++ b/README.md @@ -1,181 +1,132 @@ # Keycloak username password attribute authenticator -[![automation tests](https://github.com/kilmajster/keycloak-username-password-attribute-authenticator/actions/workflows/automation-tests.yml/badge.svg)](https://github.com/kilmajster/keycloak-username-password-attribute-authenticator/actions/workflows/automation-tests.yml) -![Maven Central](https://img.shields.io/maven-central/v/io.github.kilmajster/keycloak-username-password-attribute-authenticator) -![Docker Image Version (latest by date)](https://img.shields.io/docker/v/kilmajster/keycloak-username-password-attribute-authenticator?label=docker%20hub) -![Docker Pulls](https://img.shields.io/docker/pulls/kilmajster/keycloak-username-password-attribute-authenticator) +[![main](https://github.com/kilmajster/keycloak-username-password-attribute-authenticator/actions/workflows/maven.yml/badge.svg)](https://github.com/kilmajster/keycloak-username-password-attribute-authenticator/actions/workflows/maven.yml) ![GitHub](https://img.shields.io/github/license/kilmajster/keycloak-username-password-attribute-authenticator) -[![compatible with Keycloak - 16.1.1](https://img.shields.io/badge/compatible_with_Keycloak-16.1.1-2ea44f)](https://) + +#### Supported Keycloak versions +| compatible with Keycloak - 16.1.1 | [`keycloak-username-password-attribute-authenticator:0.3.0`](https://github.com/kilmajster/keycloak-username-password-attribute-authenticator/tree/0.3.0) | +|-------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------| +| compatible with Keycloak - 24.0.1 | [`keycloak-username-password-attribute-authenticator:1.0.0`](https://github.com/kilmajster/keycloak-username-password-attribute-authenticator/tree/main) | + ## Description Keycloak default login form with additional user attribute validation. Example:

- Login form preview + Login form preview     - Form error message preview + Form error message preview

## Usage -To use this authenticator, it should be bundled together with Keycloak, here are two ways how to do that: - -### Deploying jar file -To deploy custom Keycloak extension it needs to be placed in `{$KEYCLOAK_PATH}/standalone/deployments/`. -Latest authenticator jar file can be downloaded from -[Github Releases](https://github.com/kilmajster/keycloak-username-password-attribute-authenticator/releases/latest) page or -[Maven Central Repository](https://mvnrepository.com/artifact/io.github.kilmajster/keycloak-username-password-attribute-authenticator/latest). - -### Using Docker init container -If you want to use this authenticator in cloud environment, here is ready [init container](https://hub.docker.com/r/kilmajster/keycloak-username-password-attribute-authenticator). -Jar file is placed in `/opt/jboss/keycloak/standalone/deployments`, so same location as target one. -According to official Keycloak [example](https://github.com/codecentric/helm-charts/blob/master/charts/keycloak/README.md#providing-a-custom-theme), -Helm chart could look like following: -```yaml -extraInitContainers: | - - name: attribute-authenticator-provider - image: kilmajster/keycloak-username-password-attribute-authenticator:latest - imagePullPolicy: IfNotPresent - command: - - sh - args: - - -c - - | - echo "Copying attribute authenticator..." - cp -R /opt/jboss/keycloak/standalone/deployments/*.jar /attribute-authenticator - volumeMounts: - - name: attribute-authenticator - mountPath: /attribute-authenticator - -extraVolumeMounts: | - - name: attribute-authenticator - mountPath: /opt/jboss/keycloak/standalone/deployments - -extraVolumes: | - - name: attribute-authenticator - emptyDir: {} -``` - -## Configuration +To use this authenticator, it should be bundled together with Keycloak, here's how do that: + +### Deploying jar +Build your Keycloak image like below: +```Dockerfile +FROM quay.io/keycloak/keycloak:24.0.1 + +RUN curl -s -L -o /opt/keycloak/providers/keycloak-username-password-attribute-authenticator-1.0.0.jar https://github.com/kilmajster/keycloak-username-password-attribute-authenticator/releases/download/1.0.0/keycloak-username-password-attribute-authenticator-1.0.0.jar +RUN /opt/keycloak/bin/kc.sh build + +ENTRYPOINT ["/opt/keycloak/bin/kc.sh", "start"] +``` + +## Authentication configuration Following steps shows how to create authentication flow that uses authenticator with user attribute validation. -1. In Keycloak admin console, go to _Authentication_ section, select authentication type of _Browser_ and click _Copy_. +1. In Keycloak admin console, go to _Authentication_ section, select authentication type of _Browser_ and click +_Duplicate_ action. 2. Set name for new authentication flow eg. `Browser with user attribute` and click _Ok_. 3. In newly created authentication flow remove _Username Password Form_ execution. 4. On _Browser With User Attribute Forms_ level, click _Actions_ > _Add execution_ and select provider of type - _Username Password Attribute Form_, then save. -

- New authentication execution -

- + _Username Password Attribute Form_, set _Requirement_ to `required`, then save. 5. Then move _Username Password Attribute Form_ on a previous position of _Username Password Form_, so in the end authentication flow should look like following: -

- Form config tooltip -

- -6. On _Username Password Attribute Form_ level, click _Actions_ > _Config_. -

- Authenticator configuration -

+

+ New authentication execution +

+6. On _Username Password Attribute Form_ level, click _Actions_ > _Settings_. +

+ Authenticator configuration +

### Minimal configuration - - ##### `User attribute` - Attribute used to validate login form. +- ##### `User attribute` + Attribute used to validate login form. ### Advanced configuration - - ##### `Generate label` (default true) - If enabled, label for login form will be generated based on attribute name, so attribute with name: - - `foot_size` will be labeled as _Foot size_ - - `REALLY_custom.user-Attribute` will be translated to _Really custom user attribute_, etc. - - By default, set to `true`. If `User attribute form label` - is configured, label is taken form configuration and generation is skipped. - - ##### `Clear user on validation fail` (default true) - If enabled, user is not stored in session context in case username and password were valid but user attribute was not. - - ##### `User attribute form label` - Message which will be displayed as user attribute input label. If value is a valid message key, then proper translation will be used. - - ##### `Validation error message` - Message which will be displayed as user attribute validation error. If value is a valid message key, then proper translation will be used. - -#### Configuration via environment variables -Configuration could be also provided as environment variables. -If such config exists, then configuration from Keycloak admin UI is ignored. Available properties: -- LOGIN_FORM_GENERATE_LABEL -- LOGIN_FORM_ATTRIBUTE_LABEL -- LOGIN_FORM_ERROR_MESSAGE -- CLEAR_USER_ON_ATTRIBUTE_VALIDATION_FAIL - -### Theme configuration +- ##### `Generate label` (default true) + If enabled, label for login form will be generated based on attribute name, so attribute with name: + - `favorite_number` will be labeled as _Favorite number_ + - `REALLY_custom.user-Attribute` will be translated to _Really custom user attribute_, etc. + By default, set to `true`. If `User attribute form label` + is configured, label is taken form configuration and generation is skipped. +- ##### `User attribute form label` + Message which will be displayed as user attribute input label. If value is a valid message key, then proper translation will be used. +- ##### `Invalid user attribute error message` + Message which will be displayed as user attribute validation error. If value is a valid message key, then proper translation will be used. + +## Theme configuration Theme configuration is handled in clients section, in following example Keycloak default `account-console` client will be used. -#### Using bundled default Keycloak theme +### Using bundled default Keycloak theme In Keycloak admin panel, go to _Clients_ and select client you want to authenticate with user attribute form. As _Login Theme_ set `base-with-attribute` -and in _Authentication Flow Overrides_ for _Browser Flow_, choose authentication that contain previously configured login form, -so for example `Browser with user attribute`, like below:

- Example client configuration + Example client configuration +

+Then in advance section > _Authentication Flow Overrides_ for _Browser Flow_, choose authentication that contain previously configured login form, +so for example `Browser with user attribute`. +

+ Example client configuration

-#### Extending own theme + +### Extending own theme If you have your own theme, then in `.your-theme/login/login.ftl` add following below `
` responsible for a password stuff or anywhere you want. How it was done with _Keycloak base_ theme, you can check [here](/src/main/resources/theme/base-with-attribute/login/login.ftl). ```html -... -
- + <#if usernameHidden?? && messagesPerField.existsError('username','password')> + + ${kcSanitize(messagesPerField.getFirstError('username','password'))?no_esc} + + -
- +
- - - + +
+ + +
+ <#if usernameHidden?? && messagesPerField.existsError('username','password', 'user_attribute')> + + ${kcSanitize(messagesPerField.getFirstError('username','password'))?no_esc} + +
- +
-... +
+ <#if realm.rememberMe && !usernameHidden??> +
``` ------------------ ### Testing & development #### Build the project ```shell $ mvn package ``` - -#### Run Keycloak with authenticator in docker-compose -After building a project, do following to start Keycloak with bundled authenticator jar and dummy configuration ([`dev-realm.json`](src/test/resources/dev-realm.json)). -```shell -$ docker-compose up --build -``` -Open browser and go to http://localhost:8081/auth/realms/dev-realm/account -use _Username or email_ = `test`, _Password_ = `test` and _Foot size_ = `46` to login. - -##### Debug in docker with IntelliJ -`.github/debug-in-docker.run.xml` - -#### Automation tests -##### Build test docker image +#### Run Keycloak with authenticator in docker compose +After building a project, do following to start Keycloak with bundled authenticator jar and dummy configuration ([`dev-realm.json`](dev-realm.json)). ```shell -$ docker-compose build +$ docker compose up ``` - -##### Running tests with chrome -```shell -$ mvn test -P automation-tests -``` - -##### Running tests in docker -```shell -$ mvn test -P automation-tests -D selenide.headless=true -``` \ No newline at end of file +Open browser and go to http://localhost:8080/realms/dev-realm/account +use _Username or email_ = `test`, _Password_ = `test` and _Favorite number_ = `46` to login. diff --git a/dev-realm.json b/dev-realm.json new file mode 100644 index 0000000..4f75efb --- /dev/null +++ b/dev-realm.json @@ -0,0 +1,1882 @@ +{ + "id": "834073ca-9a3c-4e36-aa47-f8866b247935", + "realm": "dev-realm", + "notBefore": 0, + "defaultSignatureAlgorithm": "RS256", + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 300, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "clientSessionIdleTimeout": 0, + "clientSessionMaxLifespan": 0, + "clientOfflineSessionIdleTimeout": 0, + "clientOfflineSessionMaxLifespan": 0, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "oauth2DeviceCodeLifespan": 600, + "oauth2DevicePollingInterval": 5, + "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, + "defaultRole": { + "id": "2fe40b1b-b89a-402a-8ce6-566a78268bc4", + "name": "default-roles-dev-realm", + "description": "${role_default-roles}", + "composite": true, + "clientRole": false, + "containerId": "834073ca-9a3c-4e36-aa47-f8866b247935" + }, + "requiredCredentials": [ + "password" + ], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpPolicyCodeReusable": false, + "otpSupportedApplications": [ + "totpAppMicrosoftAuthenticatorName", + "totpAppFreeOTPName", + "totpAppGoogleName" + ], + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "webAuthnPolicyPasswordlessRpEntityName": "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyPasswordlessRpId": "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", + "webAuthnPolicyPasswordlessCreateTimeout": 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyPasswordlessAcceptableAaguids": [], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": [ + "offline_access" + ] + } + ], + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": [ + "manage-account", + "view-groups" + ] + } + ] + }, + "clients": [ + { + "id": "6c84289f-d0ea-4651-b6a9-dc9cb06ce9a8", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/dev-realm/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/dev-realm/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "1a60274d-756d-4351-8c5e-a41769834c49", + "clientId": "account-console", + "name": "${client_account-console}", + "description": "", + "rootUrl": "${authBaseUrl}", + "adminUrl": "", + "baseUrl": "/realms/dev-realm/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/dev-realm/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "login_theme": "base-with-attribute", + "post.logout.redirect.uris": "+", + "oauth2.device.authorization.grant.enabled": "false", + "backchannel.logout.revoke.offline.tokens": "false", + "use.refresh.tokens": "true", + "oidc.ciba.grant.enabled": "false", + "backchannel.logout.session.required": "true", + "client_credentials.use_refresh_token": "false", + "tls.client.certificate.bound.access.tokens": "false", + "require.pushed.authorization.requests": "false", + "acr.loa.map": "{}", + "display.on.consent.screen": "false", + "pkce.code.challenge.method": "S256", + "token.response.type.bearer.lower-case": "false" + }, + "authenticationFlowBindingOverrides": { + "browser": "f67cafc8-d118-4824-9cc5-a704f6e53d32" + }, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "c248feec-49a5-49ab-b2c1-c513cc55731c", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "ca55cdf2-5e24-473d-9ed3-7d3415638d65", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-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", + "acr", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "a52ee408-0952-4913-b572-d8a343e1684b", + "clientId": "broker", + "name": "${client_broker}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-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", + "acr", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "4db9b7d3-fb96-4b14-a8cf-b2f75525f5c1", + "clientId": "realm-management", + "name": "${client_realm-management}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-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", + "acr", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "6037cb4f-e522-4916-b2ef-18bbe37398cf", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/dev-realm/console/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/admin/dev-realm/console/*" + ], + "webOrigins": [ + "+" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "22ba440a-238f-4786-9f14-d0243b093365", + "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", + "acr", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + } + ], + "clientScopes": [ + { + "id": "e1340e1d-18db-4b28-8d95-01b0efe85648", + "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": "731ebd0c-60fd-4334-82f5-c6b655bea46a", + "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": "8fff12dd-e855-4bdb-96c5-fa22d1f3c4b1", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-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": "fa673ddd-a855-4590-8d4f-ab13f7e247af", + "name": "acr", + "description": "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "f7e82b99-268a-4c4c-a7eb-bb62e578081d", + "name": "acr loa level", + "protocol": "openid-connect", + "protocolMapper": "oidc-acr-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "id": "dd2cc4ab-9ad3-40f5-b874-6e3c9e0caefa", + "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": "7df1b49b-7640-4e1e-85b6-370557dc7b16", + "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": "5419107b-28fd-442a-a4da-42f3a6ffdc54", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "5fe1d7c5-25c4-49a0-8821-ba0408f17570", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "27824e4d-de85-48d1-a942-d427a7c6584b", + "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": "dccadfa1-3772-492f-b365-1992efc50273", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "c82c6fcb-a954-4f73-8fea-9c882f26f8a1", + "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": "5d2bc3ff-cb61-4df7-bef3-542fc524e84e", + "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": "066eab59-34cb-466d-84ef-ace79cf38d53", + "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": "c56590c7-8045-4f64-83d3-13eee3067892", + "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": "a4d1d6ec-51ca-4bf1-b15b-53ad31b968d3", + "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": "94f73528-55ee-42e4-b62d-665ea7d8f637", + "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": "64d400e9-4ca9-48c2-b3b7-98048be0ca08", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + }, + { + "id": "869f0374-0349-43c8-82a1-7fccb90e0027", + "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": "c1e4540f-6360-4f6f-8cf5-f227c82e2347", + "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": "f65c9ad2-d1dd-4e4a-befb-10805f26f331", + "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": "dbc22bba-3e86-4558-9179-06929f870065", + "name": "upn", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-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": "e31c4c42-d263-44ad-b999-41578169c0dc", + "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": "68c442cd-ad18-46f9-9d1b-5a58606b6bdf", + "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": "4e60bf75-e2fb-43ed-ad9c-a90e4a58f6a0", + "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": "47a09725-3bf9-427a-8196-adfe4e3d3551", + "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": "9a6f2d9c-9ead-488b-91db-8766e4e7d7d0", + "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": "e2092e09-72a9-4b6d-8a5d-d81b24524d04", + "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": "01814e18-7d30-4420-9efe-dd7b403e6e8c", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-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": "9fff3b34-cee7-400c-9282-507262a9ac0e", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-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": "c668358d-6b1b-433e-a1fe-1da138aac267", + "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": "0e5d8488-9799-4370-8176-0b7c6883f408", + "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": "912efed6-058b-4873-a7e0-b051976f0610", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-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": "4237436e-cab0-4e23-8cf3-197809517d29", + "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": "763004da-39cd-4fe1-a739-027366e5c24e", + "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": "fdc6c54b-8b7a-496d-9292-14cf8a24aa66", + "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": "0bab3185-3fe0-4efe-b29f-26acebe4b08a", + "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": "long" + } + } + ] + } + ], + "defaultDefaultClientScopes": [ + "role_list", + "profile", + "email", + "roles", + "web-origins", + "acr" + ], + "defaultOptionalClientScopes": [ + "offline_access", + "address", + "phone", + "microprofile-jwt" + ], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "referrerPolicy": "no-referrer", + "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, + "identityProviders": [], + "identityProviderMappers": [], + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "48899fd6-2798-4155-87dd-7ac2c6c2f72f", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "77dfaff3-bc24-489a-8485-c9528dca999c", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-role-list-mapper", + "saml-user-property-mapper", + "oidc-full-name-mapper", + "oidc-address-mapper", + "oidc-usermodel-attribute-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-usermodel-property-mapper", + "saml-user-attribute-mapper" + ] + } + }, + { + "id": "ba87f7eb-9c2f-4f75-8f8c-db11fdb74eaa", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "981d1165-bd59-421e-9589-b6dc81d6f87b", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "1d3f4d16-ad48-4de9-8957-574575a487b6", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": [ + "200" + ] + } + }, + { + "id": "ffb888eb-e9d0-4549-9c15-a9cfe5ee8ce3", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "47984ad9-3db9-4d8d-8c99-e8569bfb113c", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-user-attribute-mapper", + "oidc-usermodel-property-mapper", + "saml-role-list-mapper", + "oidc-full-name-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-usermodel-attribute-mapper", + "oidc-address-mapper", + "saml-user-property-mapper" + ] + } + }, + { + "id": "8e240cdb-a355-4fa5-91c4-7ec5cd515d69", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": [ + "true" + ], + "client-uris-must-match": [ + "true" + ] + } + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "0d10601a-b4d4-4583-bd68-225207abc244", + "name": "hmac-generated", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS256" + ] + } + }, + { + "id": "3cb34b93-0d5f-48c3-89f6-23c6db611073", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "d708af13-78e3-4ca8-960f-dee9b13ad8f1", + "name": "rsa-enc-generated", + "providerId": "rsa-enc-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "RSA-OAEP" + ] + } + }, + { + "id": "96aeefca-ccb4-40f5-bdae-6c21c41f64c0", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "88635639-b59c-4f3f-b8d8-49a67faa2a85", + "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", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false + } + ] + }, + { + "id": "c2c32425-5fdc-418f-bcf2-49c8e4723bb1", + "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", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "f67cafc8-d118-4824-9cc5-a704f6e53d32", + "alias": "Browser with user attribute", + "description": "browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": false, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "identity-provider-redirector", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 25, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "Browser with user attribute forms", + "userSetupAllowed": false + } + ] + }, + { + "id": "4810d943-bba2-4796-8883-b4347fcd5fe9", + "alias": "Browser with user attribute Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": false, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "be489eea-ff3b-4970-bd95-e01edfdcf6ca", + "alias": "Browser with user attribute forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": false, + "authenticationExecutions": [ + { + "authenticatorConfig": "username password favorite number form config", + "authenticator": "auth-username-password-attr-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 21, + "autheticatorFlow": true, + "flowAlias": "Browser with user attribute Browser - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "f1c208f3-c3fa-4237-be78-774e698b379d", + "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", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "f1e9aeac-46b2-4ed2-b362-5f4a651d522b", + "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", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "891b8796-4a38-4189-b462-d4976b7347b4", + "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", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Account verification options", + "userSetupAllowed": false + } + ] + }, + { + "id": "684a0d69-07f6-4cc2-9e40-38b283fa1093", + "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", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "fd028343-56cb-455c-9325-a363909edf5d", + "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", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false + } + ] + }, + { + "id": "100d0271-3c54-4ba1-9a37-b0078a82470c", + "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", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "05e49cca-3eab-48db-b282-414ed61e37f9", + "alias": "browser", + "description": "browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "identity-provider-redirector", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 25, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "forms", + "userSetupAllowed": false + } + ] + }, + { + "id": "999d9553-e82b-4c06-918c-e82b4544e829", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-secret-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-x509", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "7c4c1b16-5c7f-49d8-9603-4c277cdab76a", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "b8db3d11-2123-4a26-add1-bc9ea269998d", + "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", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "5d1329c6-23d2-4e14-83fb-bf5c98046a7a", + "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", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "User creation or linking", + "userSetupAllowed": false + } + ] + }, + { + "id": "f28eceb4-1666-439c-b3f7-a4b27d66156d", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "a1983ca1-0bd5-455f-9213-d4adfdc7be36", + "alias": "registration", + "description": "registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "registration form", + "userSetupAllowed": false + } + ] + }, + { + "id": "ed976ba1-2643-4a0d-9459-02a4ea707535", + "alias": "registration form", + "description": "registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-profile-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-password-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 50, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-recaptcha-action", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 60, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "1c016b4a-acdf-41a8-a02b-124e5bb83768", + "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", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-credential-email", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 40, + "autheticatorFlow": true, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "eb3a81e5-2e3d-490c-8898-9cca7d387cd4", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "6d7f7e83-1ec2-4ddb-a8c3-55c5f27a96d5", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "fb542612-8bc7-43dd-8cc0-b74493100e67", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + }, + { + "id": "7eb11994-09b3-4df2-807b-e1b1b5ce9cea", + "alias": "username password favorite number form config", + "config": { + "user_attribute": "favorite_number", + "generate_label": "true", + "user_attribute_label": "" + } + } + ], + "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": {} + }, + { + "alias": "delete_account", + "name": "Delete Account", + "providerId": "delete_account", + "enabled": false, + "defaultAction": false, + "priority": 60, + "config": {} + }, + { + "alias": "webauthn-register", + "name": "Webauthn Register", + "providerId": "webauthn-register", + "enabled": true, + "defaultAction": false, + "priority": 70, + "config": {} + }, + { + "alias": "webauthn-register-passwordless", + "name": "Webauthn Register Passwordless", + "providerId": "webauthn-register-passwordless", + "enabled": true, + "defaultAction": false, + "priority": 80, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "attributes": { + "cibaBackchannelTokenDeliveryMode": "poll", + "cibaExpiresIn": "120", + "cibaAuthRequestedUserHint": "login_hint", + "oauth2DeviceCodeLifespan": "600", + "oauth2DevicePollingInterval": "5", + "parRequestUriLifespan": "60", + "cibaInterval": "5", + "realmReusableOtpCode": "false" + }, + "keycloakVersion": "22.0.3", + "userManagedAccessAllowed": false, + "clientProfiles": { + "profiles": [] + }, + "clientPolicies": { + "policies": [] + }, + "users" : [ { + "id" : "462c7cb4-e444-4eac-8d68-0686c30eb245", + "createdTimestamp" : 1621784842260, + "username" : "test", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "attributes" : { + "favorite_number" : [ "46" ] + }, + "credentials" : [ { + "id" : "a0f53e85-a522-4ab4-85cb-95224dec8d35", + "type" : "password", + "createdDate" : 1621784863307, + "secretData" : "{\"value\":\"MFcHPyUSTiRqMhJum6z9KSIZbwJZAUswqq1zoVjoA6Cse8iylnjw9fOkEO72IWgS+PIj3RW7WB/CUp2deW8Swg==\",\"salt\":\"WztZBrFIbqNmEMGkQer7eQ==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "requiredActions" : [ ], + "realmRoles" : [ "default-roles-dev-realm" ], + "notBefore" : 0, + "groups" : [ ] + } ] +} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index e63ea03..5becee6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,19 +2,23 @@ version: '3' services: keycloak: - image: kilmajster/keycloak-with-authenticator:test - container_name: keycloak-dev - build: - context: . - dockerfile: src/main/docker/dev.Dockerfile - ports: - - 8081:8080 - - 8787:8787 - volumes: - - ./src/test/resources/dev-realm.json:/tmp/dev-realm.json + container_name: keycloak + image: quay.io/keycloak/keycloak:24.0.1 + entrypoint: [ "/opt/keycloak/bin/kc.sh", "--verbose", "start-dev", "--import-realm" ] environment: DEBUG: 'true' DEBUG_PORT: '*:8787' - KEYCLOAK_USER: admin - KEYCLOAK_PASSWORD: admin - KEYCLOAK_IMPORT: /tmp/dev-realm.json + KC_PROXY: edge + KC_HTTP_PORT: 8080 + KEYCLOAK_ADMIN: admin + KEYCLOAK_ADMIN_PASSWORD: admin + volumes: + - type: bind + source: ./target + target: /opt/keycloak/providers + - type: bind + source: ./dev-realm.json + target: /opt/keycloak/data/import/dev-realm.json + ports: + - '8080:8080' + - '8787:8787' diff --git a/pom.xml b/pom.xml index 92c8a72..b747ff7 100644 --- a/pom.xml +++ b/pom.xml @@ -12,15 +12,10 @@ jar - Default Keycloak login form with additional user attribute validation️ + Default Keycloak login form with additional user attribute validation https://github.com/kilmajster/keycloak-username-password-attribute-authenticator 2021 - - github - https://github.com/kilmajster/keycloak-username-password-attribute-authenticator/issues - - MIT @@ -29,71 +24,21 @@ - - - Łukasz Włódarczyk - lukasz.createam@gmail.com - 🇵🇱 - - - - - Github - https://github.com/kilmajster/keycloak-username-password-attribute-authenticator/actions - - - - scm:git:git://github.com/kilmajster/keycloak-username-password-attribute-authenticator.git - scm:git:ssh://github.com:kilmajster/keycloak-username-password-attribute-authenticator.git - http://github.com/kilmajster/keycloak-username-password-attribute-authenticator - - - - - ossrh - Central Repository OSSRH - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - UTF-8 + 17 + 17 - 11 - 11 - - 16.1.1 - - - 3.19.0 - 6.10.4 - 4.13.2 - 3.141.59 - 5.21.0 - 1.15.3 - 1.7.0 + 24.0.1 - - 3.8.1 - 3.0.1 - 3.2.0 - 3.3.0 - 3.2.1 - 2.22.2 + 3.12.1 + 3.1.0 + 3.3.0 + 3.6.3 + 3.3.0 + 3.2.5 - - - - org.keycloak - keycloak-parent - ${keycloak.version} - pom - import - - - - org.keycloak @@ -113,162 +58,6 @@ ${keycloak.version} provided - - - - - junit - junit - ${junit.version} - test - - - org.assertj - assertj-core - ${assertj.version} - test - - - org.testcontainers - testcontainers - ${testcontainers.version} - test - - - org.testcontainers - selenium - ${testcontainers.version} - test - - - com.github.dasniko - testcontainers-keycloak - ${testcontainers-keycloak.version} - test - - - com.codeborne - selenide - ${selenide.version} - test - - - org.seleniumhq.selenium - selenium-chrome-driver - ${selenium-chrome-driver.version} - test - - - io.cucumber - cucumber-java - ${cucumber.version} - test - - - io.cucumber - cucumber-junit - ${cucumber.version} - test - - - - - org.apache.maven.plugins - maven-jar-plugin - ${maven-jar-plugin.version} - - - - - - - - - - - - - - - automation-tests - - - - maven-surefire-plugin - ${maven-surefire-plugin.version} - - **/CucumberConfig.java - - - - - - - ossrh - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin.version} - - ${maven.compiler.source} - ${maven.compiler.target} - - - - org.apache.maven.plugins - maven-javadoc-plugin - ${maven-javadoc-plugin.version} - - src/main/java - - - - attach-javadocs - - jar - - - - - - org.apache.maven.plugins - maven-source-plugin - ${maven-source-plugin.version} - - - attach-sources - - jar-no-fork - - - - - - org.apache.maven.plugins - maven-gpg-plugin - ${maven-gpg-plugin.version} - - - --pinentry-mode - loopback - - - - - sign-artifacts - verify - - sign - - - - - - - - \ No newline at end of file diff --git a/src/main/docker/dev.Dockerfile b/src/main/docker/dev.Dockerfile deleted file mode 100644 index 7ddebec..0000000 --- a/src/main/docker/dev.Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM jboss/keycloak:16.1.1 - -ARG VERSION=SNAPSHOT - -ADD target/keycloak-username-password-attribute-authenticator-${VERSION}.jar /opt/jboss/keycloak/standalone/deployments \ No newline at end of file diff --git a/src/main/docker/initContainer.Dockerfile b/src/main/docker/initContainer.Dockerfile deleted file mode 100644 index b16771d..0000000 --- a/src/main/docker/initContainer.Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM busybox - -ARG VERSION - -COPY target/keycloak-username-password-attribute-authenticator-${VERSION}.jar /opt/jboss/keycloak/standalone/deployments/ \ No newline at end of file diff --git a/src/main/java/io/github/kilmajster/keycloak/UsernamePasswordAttributeForm.java b/src/main/java/io/github/kilmajster/keycloak/UsernamePasswordAttributeForm.java index 08f04ef..25da0b3 100644 --- a/src/main/java/io/github/kilmajster/keycloak/UsernamePasswordAttributeForm.java +++ b/src/main/java/io/github/kilmajster/keycloak/UsernamePasswordAttributeForm.java @@ -1,28 +1,20 @@ package io.github.kilmajster.keycloak; -import io.github.kilmajster.keycloak.ui.UserAttributeLabelGenerator; -import org.jboss.resteasy.specimpl.MultivaluedMapImpl; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.core.Response; import org.keycloak.authentication.AuthenticationFlowContext; import org.keycloak.authentication.AuthenticationFlowError; import org.keycloak.authentication.Authenticator; -import org.keycloak.authentication.authenticators.browser.AbstractUsernameFormAuthenticator; import org.keycloak.authentication.authenticators.browser.UsernamePasswordForm; import org.keycloak.events.Details; import org.keycloak.events.Errors; import org.keycloak.forms.login.LoginFormsProvider; -import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.UserModel; import org.keycloak.models.utils.FormMessage; -import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.services.ServicesLogger; -import org.keycloak.services.managers.AuthenticationManager; -import org.keycloak.services.messages.Messages; -import org.keycloak.services.validation.Validation; - -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; import static io.github.kilmajster.keycloak.UsernamePasswordAttributeFormConfiguration.*; +import static org.keycloak.services.validation.Validation.FIELD_PASSWORD; public class UsernamePasswordAttributeForm extends UsernamePasswordForm implements Authenticator { @@ -30,61 +22,40 @@ public class UsernamePasswordAttributeForm extends UsernamePasswordForm implemen @Override protected Response challenge(AuthenticationFlowContext context, String error, String field) { - LoginFormsProvider form = context.form().setExecution(context.getExecution().getId()); - if (error != null) { - if (field != null) { - form.addError(new FormMessage(field, error)); - } else { - form.setError(error, new Object[0]); - } - } - - configureUserAttributeLabel(context); + setUserAttributeFormLabel(context); + setUserAttributeFormErrorMessage(context); - return createLoginForm(form); + return super.challenge(context, null, null); } @Override protected Response challenge(AuthenticationFlowContext context, MultivaluedMap formData) { - LoginFormsProvider forms = context.form(); - if (formData.size() > 0) { - forms.setFormData(formData); - } + setUserAttributeFormLabel(context); - configureUserAttributeLabel(context); - - return forms.createLoginUsernamePassword(); + return super.challenge(context, formData); } @Override - public void authenticate(AuthenticationFlowContext context) { - MultivaluedMap formData = new MultivaluedMapImpl(); - String loginHint = context.getAuthenticationSession().getClientNote("login_hint"); - String rememberMeUsername = AuthenticationManager.getRememberMeUsername(context.getRealm(), context.getHttpRequest().getHttpHeaders()); - if (loginHint != null || rememberMeUsername != null) { - if (loginHint != null) { - formData.add("username", loginHint); - } else { - formData.add("username", rememberMeUsername); - formData.add("rememberMe", "on"); - } - } - - Response challengeResponse = challenge(context, formData); - context.challenge(challengeResponse); + protected boolean validateForm(AuthenticationFlowContext context, MultivaluedMap formData) { + return super.validateForm(context, formData) + && isUserAttributeValid(context, formData.getFirst(USER_ATTRIBUTE)); } - private void configureUserAttributeLabel(AuthenticationFlowContext context) { - final String userAttributeLabel = configPropertyOf(context, LOGIN_FORM_ATTRIBUTE_LABEL); + private void setUserAttributeFormLabel(AuthenticationFlowContext context) { + String userAttributeLabel = configPropertyOf(context, USER_ATTRIBUTE_LABEL); + + // label if (userAttributeLabel != null) { - context.form().setAttribute(LOGIN_FORM_ATTRIBUTE_LABEL, userAttributeLabel); + context.form().setAttribute(USER_ATTRIBUTE_LABEL, userAttributeLabel); } else { - final String userAttributeName = configPropertyOf(context, LOGIN_FORM_USER_ATTRIBUTE); + String userAttributeName = configPropertyOf(context, USER_ATTRIBUTE); if (userAttributeName != null && !userAttributeName.isEmpty()) { - context.form().setAttribute(LOGIN_FORM_ATTRIBUTE_LABEL, + context.form().setAttribute( + USER_ATTRIBUTE_LABEL, isGenerateLabelEnabled(context) - ? UserAttributeLabelGenerator.generateLabel(userAttributeName) - : userAttributeName); + ? generateLabel(userAttributeName, true) + : userAttributeName + ); } else { log.warn("Configuration of keycloak-user-attribute-authenticator is incomplete! " + "At least user_attribute property needs to be set!"); @@ -92,124 +63,70 @@ private void configureUserAttributeLabel(AuthenticationFlowContext context) { } } - @Override - protected boolean validateForm(AuthenticationFlowContext context, MultivaluedMap formData) { - context.clearUser(); - UserModel user = getUser(context, formData); - return user != null - && validatePassword(context, user, formData) && validateUser(context, user, formData) - && validateUserAttribute(context, user, formData); - } + private void setUserAttributeFormErrorMessage(AuthenticationFlowContext context) { + String userAttributeName = configPropertyOf(context, USER_ATTRIBUTE); + String userAttributeErrorMessage = configPropertyOf(context, USER_ATTRIBUTE_ERROR_MESSAGE); - private boolean validateUserAttribute(AuthenticationFlowContext context, UserModel user, MultivaluedMap formData) { - final String providedAttribute = formData.getFirst(LOGIN_FORM_USER_ATTRIBUTE); - if (providedAttribute == null || providedAttribute.isEmpty()) { - return invalidUserAttributeHandler(context, user, true); - } - - if (isProvidedAttributeValid(context, user, providedAttribute)) { - return true; + if (userAttributeErrorMessage != null) { + context.form().addError( + new FormMessage(FIELD_PASSWORD, userAttributeErrorMessage, userAttributeName) + ); } else { - return invalidUserAttributeHandler(context, user, false); + if (userAttributeName != null && !userAttributeName.isEmpty()) { + context.form().addError( + new FormMessage( + FIELD_PASSWORD, + "invalidUsernamePasswordOrAttributeMessage", + isGenerateLabelEnabled(context) + ? generateLabel(userAttributeName, false) + : userAttributeName + ) + ); + } else { + log.warn("Configuration of keycloak-user-attribute-authenticator is incomplete! " + + "At least user_attribute property needs to be set!"); + } } } - private boolean isProvidedAttributeValid(AuthenticationFlowContext context, UserModel user, String providedUserAttribute) { - String userAttributeName = context.getAuthenticatorConfig().getConfig().get(LOGIN_FORM_USER_ATTRIBUTE); - return user.getAttributeStream(userAttributeName) - .anyMatch(attr -> attr.equals(providedUserAttribute)); + private boolean isUserAttributeValid(AuthenticationFlowContext context, String providedAttribute) { + String attributeName = context.getAuthenticatorConfig().getConfig().get(USER_ATTRIBUTE); + UserModel user = context.getUser(); + boolean attributeValid = user != null + && user.getAttributeStream(attributeName).anyMatch(attr -> attr.equals(providedAttribute)); + + return attributeValid || badAttributeHandler(context, user); } - // Set up AuthenticationFlowContext error. - private boolean invalidUserAttributeHandler(AuthenticationFlowContext context, UserModel user, boolean isAttributeEmpty) { + private boolean badAttributeHandler(AuthenticationFlowContext context, UserModel user) { context.getEvent().user(user); context.getEvent().error(Errors.INVALID_USER_CREDENTIALS); + context.getEvent().detail(Details.REASON, "Invalid user attribute was provided"); - String errorText; - final String configuredErrorMessage = configPropertyOf(context, LOGIN_FORM_ERROR_MESSAGE); - if (configuredErrorMessage != null && !configuredErrorMessage.isBlank()) { - // error text directly from error label propertyModelException - errorText = configuredErrorMessage; - } else { - final String userAttributeLabel = configPropertyOf(context, LOGIN_FORM_ATTRIBUTE_LABEL); - if (userAttributeLabel != null && !userAttributeLabel.isBlank()) { - // get message from message.properties in case USER_ATTRIBUTE_LABEL is a message key - final String message = context.form().getMessage(userAttributeLabel); - // generating error message based on provided user attribute label - errorText = UserAttributeLabelGenerator.generateErrorText(message != null ? message : userAttributeLabel); - } else { - // user attribute label not provided so generating text based on attribute name - errorText = isGenerateLabelEnabled(context) // generate pretty error if property is not disabled - ? UserAttributeLabelGenerator.generateErrorText(configPropertyOf(context, LOGIN_FORM_USER_ATTRIBUTE)) - : "Invalid ".concat(configPropertyOf(context, LOGIN_FORM_USER_ATTRIBUTE)); // use raw attribute name - } - } - - if (isClearUserOnFailedAttributeValidationEnabled(context)) { - context.clearUser(); - } - - Response challengeResponse = challenge(context, errorText, LOGIN_FORM_USER_ATTRIBUTE); - - if (isAttributeEmpty) { - context.forceChallenge(challengeResponse); - } else { - context.failureChallenge(AuthenticationFlowError.INVALID_CREDENTIALS, challengeResponse); + if (isUserAlreadySetBeforeUsernamePasswordAuth(context)) { + LoginFormsProvider form = context.form(); + form.setAttribute(LoginFormsProvider.USERNAME_HIDDEN, true); + form.setAttribute(LoginFormsProvider.REGISTRATION_DISABLED, true); } + Response challengeResponse = challenge(context, getDefaultChallengeMessage(context), FIELD_PASSWORD); + context.failureChallenge(AuthenticationFlowError.INVALID_CREDENTIALS, challengeResponse); context.clearUser(); return false; } + private String generateLabel(final String attributeName, boolean capitalize) { + final String lowercaseWithSpaces = attributeName + .toLowerCase() + .replace(".", " ") + .replace("_", " ") + .replace("-", " "); - private UserModel getUser(AuthenticationFlowContext context, MultivaluedMap formData) { - String username = formData.getFirst(AuthenticationManager.FORM_USERNAME); - if (username == null) { - context.getEvent().error(Errors.USER_NOT_FOUND); - Response challengeResponse = challenge(context, getDefaultChallengeMessage(context), Validation.FIELD_USERNAME); - context.failureChallenge(AuthenticationFlowError.INVALID_USER, challengeResponse); - return null; - } - - // remove leading and trailing whitespace - username = username.trim(); - - context.getEvent().detail(Details.USERNAME, username); - context.getAuthenticationSession().setAuthNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME, username); - - UserModel user = null; - try { - user = KeycloakModelUtils.findUserByNameOrEmail(context.getSession(), context.getRealm(), username); - } catch (ModelDuplicateException mde) { - ServicesLogger.LOGGER.modelDuplicateException(mde); - - // Could happen during federation import - if (mde.getDuplicateFieldName() != null && mde.getDuplicateFieldName().equals(UserModel.EMAIL)) { - setDuplicateUserChallenge(context, Errors.EMAIL_IN_USE, Messages.EMAIL_EXISTS, AuthenticationFlowError.INVALID_USER); - } else { - setDuplicateUserChallenge(context, Errors.USERNAME_IN_USE, Messages.USERNAME_EXISTS, AuthenticationFlowError.INVALID_USER); - } - return user; - } - - testInvalidUser(context, user); - return user; + return capitalize ? capitalize(lowercaseWithSpaces) : lowercaseWithSpaces; } - private boolean validateUser(AuthenticationFlowContext context, UserModel user, MultivaluedMap inputData) { - if (!enabledUser(context, user)) { - return false; - } - String rememberMe = inputData.getFirst("rememberMe"); - boolean remember = rememberMe != null && rememberMe.equalsIgnoreCase("on"); - if (remember) { - context.getAuthenticationSession().setAuthNote(Details.REMEMBER_ME, "true"); - context.getEvent().detail(Details.REMEMBER_ME, "true"); - } else { - context.getAuthenticationSession().removeAuthNote(Details.REMEMBER_ME); - } - context.setUser(user); - return true; + private String capitalize(final String toCapitalize) { + return toCapitalize.substring(0, 1).toUpperCase() + toCapitalize.substring(1).toLowerCase(); } } \ No newline at end of file diff --git a/src/main/java/io/github/kilmajster/keycloak/UsernamePasswordAttributeFormConfiguration.java b/src/main/java/io/github/kilmajster/keycloak/UsernamePasswordAttributeFormConfiguration.java index b322c55..5b5761e 100644 --- a/src/main/java/io/github/kilmajster/keycloak/UsernamePasswordAttributeFormConfiguration.java +++ b/src/main/java/io/github/kilmajster/keycloak/UsernamePasswordAttributeFormConfiguration.java @@ -9,52 +9,43 @@ public interface UsernamePasswordAttributeFormConfiguration { - String LOGIN_FORM_USER_ATTRIBUTE = "login_form_user_attribute"; - String LOGIN_FORM_GENERATE_LABEL = "login_form_generate_label"; - String LOGIN_FORM_ATTRIBUTE_LABEL = "login_form_attribute_label"; - String LOGIN_FORM_ERROR_MESSAGE = "login_form_error_message"; - String CLEAR_USER_ON_ATTRIBUTE_VALIDATION_FAIL = "clear_user_on_attribute_validation_fail"; + String USER_ATTRIBUTE = "user_attribute"; + String GENERATE_LABEL = "generate_label"; + String USER_ATTRIBUTE_LABEL = "user_attribute_label"; + String USER_ATTRIBUTE_ERROR_MESSAGE = "user_attribute_error_message"; List PROPS = ProviderConfigurationBuilder.create() .property() - .name(LOGIN_FORM_USER_ATTRIBUTE) + .name(USER_ATTRIBUTE) .type(ProviderConfigProperty.STRING_TYPE) .label("User attribute") .helpText("Attribute used to validate login form.") .add() .property() - .name(LOGIN_FORM_GENERATE_LABEL) + .name(GENERATE_LABEL) .type(ProviderConfigProperty.BOOLEAN_TYPE) .label("Generate label") .defaultValue("true") // only string value is accepted .helpText("If enabled, label for login form will be generated based on attribute name, so attribute with name:" + - " \"foot_size\" will be labeled as \"Foot size\", \"REALLY_custom.user-Attribute\" will be translated " + + " \"favorite_number\" will be labeled as \"Favorite number\", \"REALLY_custom.user-Attribute\" will be translated " + "to \"Really custom user attribute\", etc. By default, set to true. If User attribute form label " + "is configured, label is taken form configuration and generation is skipped.") .add() .property() - .name(CLEAR_USER_ON_ATTRIBUTE_VALIDATION_FAIL) - .type(ProviderConfigProperty.BOOLEAN_TYPE) - .label("Clear user on validation fail") - .defaultValue("true") // only string value is accepted - .helpText("If enabled, user is not stored in session context in case username and password were valid but user attribute was not.") - .add() - - .property() - .name(LOGIN_FORM_ATTRIBUTE_LABEL) + .name(USER_ATTRIBUTE_LABEL) .type(ProviderConfigProperty.STRING_TYPE) .label("User attribute form label") .helpText("Message which will be displayed as user attribute input label. If value is a valid message key, then proper translation will be used.") .add() .property() - .name(LOGIN_FORM_ERROR_MESSAGE) + .name(USER_ATTRIBUTE_ERROR_MESSAGE) .type(ProviderConfigProperty.STRING_TYPE) - .label("Validation error message") - .helpText("Message which will be displayed as user attribute validation error. If value is a valid message key, then proper translation will be used.") + .label("Invalid user attribute error message") + .helpText("Message which will be displayed for invalid user attribute error message. If value is a valid message key, then proper translation will be used.") .add() .build(); @@ -65,10 +56,6 @@ static String configPropertyOf(final AuthenticationFlowContext context, final St } static boolean isGenerateLabelEnabled(final AuthenticationFlowContext context) { - return Boolean.parseBoolean(configPropertyOf(context, LOGIN_FORM_GENERATE_LABEL)); - } - - static boolean isClearUserOnFailedAttributeValidationEnabled(final AuthenticationFlowContext context) { - return Boolean.parseBoolean(configPropertyOf(context, CLEAR_USER_ON_ATTRIBUTE_VALIDATION_FAIL)); + return Boolean.parseBoolean(configPropertyOf(context, GENERATE_LABEL)); } } \ No newline at end of file diff --git a/src/main/java/io/github/kilmajster/keycloak/UsernamePasswordAttributeFormFactory.java b/src/main/java/io/github/kilmajster/keycloak/UsernamePasswordAttributeFormFactory.java index d7df8d0..c2c4bda 100644 --- a/src/main/java/io/github/kilmajster/keycloak/UsernamePasswordAttributeFormFactory.java +++ b/src/main/java/io/github/kilmajster/keycloak/UsernamePasswordAttributeFormFactory.java @@ -1,11 +1,8 @@ package io.github.kilmajster.keycloak; import org.keycloak.Config; -import org.keycloak.OAuth2Constants; import org.keycloak.authentication.Authenticator; import org.keycloak.authentication.AuthenticatorFactory; -import org.keycloak.authentication.DisplayTypeAuthenticatorFactory; -import org.keycloak.authentication.authenticators.console.ConsoleUsernamePasswordAuthenticator; import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSessionFactory; @@ -14,7 +11,7 @@ import java.util.List; -public class UsernamePasswordAttributeFormFactory implements AuthenticatorFactory, DisplayTypeAuthenticatorFactory { +public class UsernamePasswordAttributeFormFactory implements AuthenticatorFactory { public static final String PROVIDER_ID = "auth-username-password-attr-form"; public static final UsernamePasswordAttributeForm SINGLETON = new UsernamePasswordAttributeForm(); @@ -29,13 +26,6 @@ public List getConfigProperties() { return UsernamePasswordAttributeFormConfiguration.PROPS; } - @Override - public Authenticator createDisplay(KeycloakSession session, String displayType) { - if (displayType == null) return SINGLETON; - if (!OAuth2Constants.DISPLAY_CONSOLE.equalsIgnoreCase(displayType)) return null; - return ConsoleUsernamePasswordAuthenticator.SINGLETON; - } - @Override public void init(Config.Scope config) { @@ -67,7 +57,8 @@ public boolean isConfigurable() { } public static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = { - AuthenticationExecutionModel.Requirement.REQUIRED + AuthenticationExecutionModel.Requirement.REQUIRED, + AuthenticationExecutionModel.Requirement.DISABLED, }; @Override diff --git a/src/main/java/io/github/kilmajster/keycloak/ui/UserAttributeLabelGenerator.java b/src/main/java/io/github/kilmajster/keycloak/ui/UserAttributeLabelGenerator.java deleted file mode 100644 index 4f60c73..0000000 --- a/src/main/java/io/github/kilmajster/keycloak/ui/UserAttributeLabelGenerator.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.github.kilmajster.keycloak.ui; - -public final class UserAttributeLabelGenerator { - - public static String generateLabel(final String attributeName) { - final String lowercaseWithSpaces = attributeName - .toLowerCase() - .replace(".", " ") - .replace("_", " ") - .replace("-", " "); - - return capitalizeFirstChar(lowercaseWithSpaces); - } - - public static String generateErrorText(final String attributeName) { - return "Invalid " + generateLabel(attributeName).toLowerCase() + "."; - } - - private static String capitalizeFirstChar(final String lowercaseWithSpaces) { - return lowercaseWithSpaces.substring(0,1).toUpperCase() + lowercaseWithSpaces.substring(1).toLowerCase(); - } -} diff --git a/src/main/resources/theme/base-with-attribute/login/login.ftl b/src/main/resources/theme/base-with-attribute/login/login.ftl index 4a7b1ae..e20147d 100644 --- a/src/main/resources/theme/base-with-attribute/login/login.ftl +++ b/src/main/resources/theme/base-with-attribute/login/login.ftl @@ -3,114 +3,135 @@ <#if section = "header"> ${msg("loginAccountTitle")} <#elseif section = "form"> -
-
- <#if realm.password> -
-
- +
+
+ <#if realm.password> + + <#if !usernameHidden??> +
+ - <#if usernameEditDisabled??> - - <#else> - + - <#if messagesPerField.existsError('username','password')> - - ${kcSanitize(messagesPerField.getFirstError('username','password'))?no_esc} - - + <#if messagesPerField.existsError('username','password')> + + ${kcSanitize(messagesPerField.getFirstError('username','password'))?no_esc} + + + +
-
-
- +
+ - -
+
+ + +
- -
- - -
- +
-
-
- <#if realm.rememberMe && !usernameEditDisabled??> -
- -
- + +
+ +
+ +
-
- <#if realm.resetPasswordAllowed> - ${msg("doForgotPassword")} + <#if usernameHidden?? && messagesPerField.existsError('username','password', 'user_attribute')> + + ${kcSanitize(messagesPerField.getFirstError('username','password'))?no_esc} + + +
+ + +
+
+ <#if realm.rememberMe && !usernameHidden??> +
+ +
-
+
+
+ <#if realm.resetPasswordAllowed> + ${msg("doForgotPassword")} + +
-
+
-
- value="${auth.selectedCredential}"/> - -
- - +
+ value="${auth.selectedCredential}"/> + +
+ + +
- + + <#elseif section = "info" > + <#if realm.password && realm.registrationAllowed && !registrationDisabled??> +
+
+ ${msg("noAccount")} ${msg("doRegister")} +
+
+ + <#elseif section = "socialProviders" > <#if realm.password && social.providers??> - -
- <#elseif section = "info" > - <#if realm.password && realm.registrationAllowed && !registrationDisabled??> -
-
- ${msg("noAccount")} ${msg("doRegister")} -
-
- - + \ No newline at end of file diff --git a/src/main/resources/theme/base-with-attribute/login/messages/messages_en.properties b/src/main/resources/theme/base-with-attribute/login/messages/messages_en.properties index b025587..82fa051 100644 --- a/src/main/resources/theme/base-with-attribute/login/messages/messages_en.properties +++ b/src/main/resources/theme/base-with-attribute/login/messages/messages_en.properties @@ -1 +1,4 @@ -login_form_attribute_label_default=User attribute \ No newline at end of file +defaultUserAttributeLabel=User attribute +showUserAttribute=Show attribute +hideUserAttribute=Hide attribute +invalidUsernamePasswordOrAttributeMessage=Invalid username, password or {0}. \ No newline at end of file diff --git a/src/test/java/io/github/kilmajster/keycloak/CucumberConfig.java b/src/test/java/io/github/kilmajster/keycloak/CucumberConfig.java deleted file mode 100644 index 4b2cc87..0000000 --- a/src/test/java/io/github/kilmajster/keycloak/CucumberConfig.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.github.kilmajster.keycloak; - -import io.cucumber.junit.Cucumber; -import io.cucumber.junit.CucumberOptions; -import org.junit.runner.RunWith; - -@RunWith(Cucumber.class) -@CucumberOptions(features = "src/test/resources/cucumber") -public class CucumberConfig { -} \ No newline at end of file diff --git a/src/test/java/io/github/kilmajster/keycloak/KeycloakSteps.java b/src/test/java/io/github/kilmajster/keycloak/KeycloakSteps.java deleted file mode 100644 index c5e6019..0000000 --- a/src/test/java/io/github/kilmajster/keycloak/KeycloakSteps.java +++ /dev/null @@ -1,135 +0,0 @@ -package io.github.kilmajster.keycloak; - -import com.codeborne.selenide.SelenideElement; -import dasniko.testcontainers.keycloak.KeycloakContainer; -import io.cucumber.java.en.And; -import io.cucumber.java.en.Given; -import io.cucumber.java.en.Then; -import io.cucumber.java.en.When; -import org.openqa.selenium.By; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testcontainers.containers.output.Slf4jLogConsumer; - -import static com.codeborne.selenide.Condition.exactText; -import static com.codeborne.selenide.Condition.text; -import static com.codeborne.selenide.Selenide.$; -import static com.codeborne.selenide.Selenide.open; -import static io.github.kilmajster.keycloak.TestConstants.*; -import static org.assertj.core.api.Assertions.assertThat; - -public final class KeycloakSteps { - - private static final Logger log = LoggerFactory.getLogger(KeycloakSteps.class); - - private final KeycloakContainer keycloak = new KeycloakContainer(KEYCLOAK_DEV_DOCKER_IMAGE) - .withRealmImportFile("dev-realm.json") - .withLogConsumer(new Slf4jLogConsumer(log)); - - @Given("keycloak is running with default setup") - public void keycloak_is_running_with_default_setup() { - if (!keycloak.isRunning()) { - log.info("Starting keycloak container..."); - keycloak.start(); - } - } - - @Given("keycloak is running with {} = {}") - public void keycloak_is_running_with_env(final String envKey, final String envValue) { - keycloak.addEnv(envKey, envValue); - if (!keycloak.isRunning()) { - log.info("Starting keycloak container with " + envKey + " = " + envValue); - keycloak.start(); - } - } - - @When("user goes to the account console page") - public void go_to_keycloak_account_page() { - final String keycloakUrl = TestConstants.KEYCLOAK_LOCAL_URL_PREFIX + keycloak.getFirstMappedPort(); - - log.info("go_to_keycloak_account_page() :: keycloakUrl = " + keycloakUrl); - - open(keycloakUrl + "/auth/realms/dev-realm/account"); - } - - @Then("user should be not logged in") - public void user_should_be_not_logged_in() { - log.info("user_should_be_not_logged_in()"); - - final String loggedInUser = $(By.id("landingLoggedInUser")).val(); - assertThat(loggedInUser).isNullOrEmpty(); - } - - @When("user clicks a sign in button") - public void click_sign_in_button() { - log.info("click_sign_in_button()"); - - $(By.id("landingSignInButton")).click(); - } - - @When("user navigates to login page") - public void user_navigates_to_login_page() { - log.info("user_navigates_to_login_page()"); - - go_to_keycloak_account_page(); - user_should_be_not_logged_in(); - click_sign_in_button(); - } - - @Then("login form with attribute input labeled as {string} should be shown") - public void verify_login_form_is_displayed_with_user_attribute_label(final String label) { - log.info("verify_login_form_is_displayed_with_user_attribute_label( label = " + label + " )"); - - assertThat($(By.id("kc-form-login")).isDisplayed()).isTrue(); - userAttributeFormLabel().shouldHave(text(label)); - } - - @When("user log into account console with a valid credentials and user attribute equal {string}") - public void log_into_account_console(final String attribute) { - log.info("log_into_account_console()"); - - $(By.id("username")).val(TEST_USERNAME); - $(By.id("password")).val(TEST_PASSWORD); - $(By.id("login_form_user_attribute")).val(attribute); - $(By.id("kc-login")).click(); - } - - @Then("user should be logged into account console") - public void verify_that_user_is_logged_in() { - log.info("verify_that_user_is_logged_in()"); - - $(By.id("landingLoggedInUser")).shouldHave(text("test")); - } - - @Then("form error with message {string} is present") - public void form_error_with_message_is_present(final String errorMessage) { - log.info("form_error_with_message_is_present( " + errorMessage + " )"); - - $(By.className("alert-error")).shouldHave(text(errorMessage)); - } - - @And("attempted username is cleared") - public void attempted_username_is_cleared() { - log.info("attempted_username_is_cleared()"); - - assertThat($(By.id("kc-attempted-username")).exists()).isFalse(); - } - - @And("attempted username is set to {string}") - public void attempted_username_is_set_to(final String attemptedUsername) { - log.info("attempted_username_is_set_to( " + attemptedUsername + " )"); - - $(By.id("kc-attempted-username")).shouldHave(exactText(attemptedUsername)); - } - - @And("restart login link is visible") - public void restart_login_link_is_visible() { - log.info("restart_login_link_is_visible()"); - - assertThat($(By.className("kc-tooltip-text")).getOwnText()).isEqualTo("Restart login"); - } - - private SelenideElement userAttributeFormLabel() { - return $(By.xpath("//input[@id='login_form_user_attribute']/preceding-sibling::label")); - } -} \ No newline at end of file diff --git a/src/test/java/io/github/kilmajster/keycloak/TestConstants.java b/src/test/java/io/github/kilmajster/keycloak/TestConstants.java deleted file mode 100644 index 6d0c7ba..0000000 --- a/src/test/java/io/github/kilmajster/keycloak/TestConstants.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.github.kilmajster.keycloak; - -public interface TestConstants { - String KEYCLOAK_DEV_DOCKER_IMAGE = "kilmajster/keycloak-with-authenticator:test"; - String KEYCLOAK_LOCAL_URL_PREFIX = "http://localhost:"; - - String TEST_USERNAME = "test"; - String TEST_PASSWORD = "test"; -} \ No newline at end of file diff --git a/src/test/java/io/github/kilmajster/keycloak/ui/UserAttributeLabelGeneratorTest.java b/src/test/java/io/github/kilmajster/keycloak/ui/UserAttributeLabelGeneratorTest.java deleted file mode 100644 index 6998365..0000000 --- a/src/test/java/io/github/kilmajster/keycloak/ui/UserAttributeLabelGeneratorTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.github.kilmajster.keycloak.ui; - - -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - - -public class UserAttributeLabelGeneratorTest { - - @Test - public void shouldPrettifyString() { - final String attribute = "TEST_ATTRIBUTE-NAME.bLah"; - - final String label = UserAttributeLabelGenerator.generateLabel(attribute); - - assertThat(label).isEqualTo("Test attribute name blah"); - } -} \ No newline at end of file diff --git a/src/test/resources/cucumber.properties b/src/test/resources/cucumber.properties deleted file mode 100644 index aa51b35..0000000 --- a/src/test/resources/cucumber.properties +++ /dev/null @@ -1 +0,0 @@ -cucumber.publish.quiet=true \ No newline at end of file diff --git a/src/test/resources/cucumber/login-form-env-var-config.feature b/src/test/resources/cucumber/login-form-env-var-config.feature deleted file mode 100644 index 0d9a237..0000000 --- a/src/test/resources/cucumber/login-form-env-var-config.feature +++ /dev/null @@ -1,50 +0,0 @@ -Feature: Login form with user attribute and environment variable based configuration - - Scenario: label and error message are generated from attribute name when environment variable configuration is empty - Given keycloak is running with default setup - When user navigates to login page - Then login form with attribute input labeled as "Foot size" should be shown - When user log into account console with a valid credentials and user attribute equal "invalid-user-attribute" - Then form error with message "Invalid foot size." is present - And attempted username is cleared - - Scenario: attempted username is not cleared when clearing is disabled via environment variable - Given keycloak is running with CLEAR_USER_ON_ATTRIBUTE_VALIDATION_FAIL = false - When user navigates to login page - Then login form with attribute input labeled as "Foot size" should be shown - When user log into account console with a valid credentials and user attribute equal "invalid-user-attribute" - Then form error with message "Invalid foot size." is present - And attempted username is set to "test" - And restart login link is visible - - Scenario: label and error message are generated from attribute name when attribute is taken from environment variable - Given keycloak is running with LOGIN_FORM_USER_ATTRIBUTE = VERY_custom-uSeR.ATTRIBUTE - When user navigates to login page - Then login form with attribute input labeled as "Very custom user attribute" should be shown - When user log into account console with a valid credentials and user attribute equal "invalid-user-attribute" - Then form error with message "Invalid very custom user attribute." is present - And attempted username is cleared - - Scenario: label and error message are taken from attribute name without prettify - Given keycloak is running with LOGIN_FORM_GENERATE_LABEL = false - When user navigates to login page - Then login form with attribute input labeled as "foot_size" should be shown - When user log into account console with a valid credentials and user attribute equal "invalid-user-attribute" - Then form error with message "Invalid foot_size" is present - And attempted username is cleared - - Scenario: label and error message are taken from environment variable - Given keycloak is running with LOGIN_FORM_ATTRIBUTE_LABEL = Custom user attribute - When user navigates to login page - Then login form with attribute input labeled as "Custom user attribute" should be shown - When user log into account console with a valid credentials and user attribute equal "invalid-user-attribute" - Then form error with message "Invalid custom user attribute." is present - And attempted username is cleared - - Scenario: label and error message are taken from message resolved from environment variable - Given keycloak is running with LOGIN_FORM_ATTRIBUTE_LABEL = login_form_attribute_label_default - When user navigates to login page - Then login form with attribute input labeled as "User attribute" should be shown - When user log into account console with a valid credentials and user attribute equal "invalid-user-attribute" - Then form error with message "Invalid user attribute." is present - And attempted username is cleared \ No newline at end of file diff --git a/src/test/resources/cucumber/login-form.feature b/src/test/resources/cucumber/login-form.feature deleted file mode 100644 index ced7c68..0000000 --- a/src/test/resources/cucumber/login-form.feature +++ /dev/null @@ -1,10 +0,0 @@ -Feature: Login form with user attribute - - Scenario: user can log into account console - Given keycloak is running with default setup - When user goes to the account console page - Then user should be not logged in - When user clicks a sign in button - Then login form with attribute input labeled as "Foot size" should be shown - When user log into account console with a valid credentials and user attribute equal "46" - Then user should be logged into account console \ No newline at end of file diff --git a/src/test/resources/dev-realm.json b/src/test/resources/dev-realm.json deleted file mode 100644 index 95fcc07..0000000 --- a/src/test/resources/dev-realm.json +++ /dev/null @@ -1,1804 +0,0 @@ -{ - "id" : "dev-realm", - "realm" : "dev-realm", - "notBefore" : 0, - "defaultSignatureAlgorithm" : "RS256", - "revokeRefreshToken" : false, - "refreshTokenMaxReuse" : 0, - "accessTokenLifespan" : 300, - "accessTokenLifespanForImplicitFlow" : 900, - "ssoSessionIdleTimeout" : 1800, - "ssoSessionMaxLifespan" : 36000, - "ssoSessionIdleTimeoutRememberMe" : 0, - "ssoSessionMaxLifespanRememberMe" : 0, - "offlineSessionIdleTimeout" : 2592000, - "offlineSessionMaxLifespanEnabled" : false, - "offlineSessionMaxLifespan" : 5184000, - "clientSessionIdleTimeout" : 0, - "clientSessionMaxLifespan" : 0, - "clientOfflineSessionIdleTimeout" : 0, - "clientOfflineSessionMaxLifespan" : 0, - "accessCodeLifespan" : 60, - "accessCodeLifespanUserAction" : 300, - "accessCodeLifespanLogin" : 1800, - "actionTokenGeneratedByAdminLifespan" : 43200, - "actionTokenGeneratedByUserLifespan" : 300, - "oauth2DeviceCodeLifespan" : 600, - "oauth2DevicePollingInterval" : 5, - "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" : "8e635ebd-2b27-40ee-80f8-0573e5088379", - "name" : "offline_access", - "description" : "${role_offline-access}", - "composite" : false, - "clientRole" : false, - "containerId" : "dev-realm", - "attributes" : { } - }, { - "id" : "dbd7344a-2875-45ff-bc22-7619647079b8", - "name" : "uma_authorization", - "description" : "${role_uma_authorization}", - "composite" : false, - "clientRole" : false, - "containerId" : "dev-realm", - "attributes" : { } - }, { - "id" : "d33af3a2-ff09-4831-acfa-4a261228b781", - "name" : "default-roles-dev-realm", - "description" : "${role_default-roles}", - "composite" : true, - "composites" : { - "realm" : [ "offline_access", "uma_authorization" ] - }, - "clientRole" : false, - "containerId" : "dev-realm", - "attributes" : { } - } ], - "client" : { - "realm-management" : [ { - "id" : "d33c6b48-f69c-47d1-8c97-d40004e8a862", - "name" : "query-realms", - "description" : "${role_query-realms}", - "composite" : false, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - }, { - "id" : "8a9be796-7360-481e-b244-c0164b0bc2d9", - "name" : "view-realm", - "description" : "${role_view-realm}", - "composite" : false, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - }, { - "id" : "26aeaf1f-65ee-43c1-92a1-39a767b7d2bb", - "name" : "manage-realm", - "description" : "${role_manage-realm}", - "composite" : false, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - }, { - "id" : "ac3ffc40-74da-4cfe-b11c-034c7b618df1", - "name" : "impersonation", - "description" : "${role_impersonation}", - "composite" : false, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - }, { - "id" : "926f38cb-556e-4264-8362-cbaffbccaf82", - "name" : "manage-clients", - "description" : "${role_manage-clients}", - "composite" : false, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - }, { - "id" : "a9bb170d-4ec7-41af-81ee-9d51c2763327", - "name" : "manage-events", - "description" : "${role_manage-events}", - "composite" : false, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - }, { - "id" : "26e0ce44-d7fb-4e00-9a79-3ee16f84230c", - "name" : "manage-users", - "description" : "${role_manage-users}", - "composite" : false, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - }, { - "id" : "1d9b924b-5475-470d-92aa-451734720d61", - "name" : "query-clients", - "description" : "${role_query-clients}", - "composite" : false, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - }, { - "id" : "6877c7cd-4ef6-453d-b777-889770293d99", - "name" : "manage-authorization", - "description" : "${role_manage-authorization}", - "composite" : false, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - }, { - "id" : "bf6ce84e-7f54-4b7d-9be6-02dc6228aec2", - "name" : "manage-identity-providers", - "description" : "${role_manage-identity-providers}", - "composite" : false, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - }, { - "id" : "23b8cedb-8476-442a-9441-2f75f39c7587", - "name" : "view-authorization", - "description" : "${role_view-authorization}", - "composite" : false, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - }, { - "id" : "139c8800-050e-4891-9e66-08af29a21603", - "name" : "view-identity-providers", - "description" : "${role_view-identity-providers}", - "composite" : false, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - }, { - "id" : "962b1eb7-a0f0-4c8f-8d05-c000bcfa3ec1", - "name" : "query-users", - "description" : "${role_query-users}", - "composite" : false, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - }, { - "id" : "e3b06968-1dac-4550-8c50-4d7a4fe5e828", - "name" : "view-clients", - "description" : "${role_view-clients}", - "composite" : true, - "composites" : { - "client" : { - "realm-management" : [ "query-clients" ] - } - }, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - }, { - "id" : "0a50db9b-c7e7-4b12-bc05-97858589619c", - "name" : "create-client", - "description" : "${role_create-client}", - "composite" : false, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - }, { - "id" : "1e4901f6-c10b-4127-845d-593ef765274b", - "name" : "realm-admin", - "description" : "${role_realm-admin}", - "composite" : true, - "composites" : { - "client" : { - "realm-management" : [ "query-realms", "view-realm", "manage-realm", "impersonation", "manage-clients", "manage-events", "query-clients", "manage-users", "manage-authorization", "manage-identity-providers", "view-authorization", "view-identity-providers", "query-users", "view-clients", "create-client", "query-groups", "view-users", "view-events" ] - } - }, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - }, { - "id" : "e8cb7818-f0d5-4d90-a066-35f9e30443aa", - "name" : "query-groups", - "description" : "${role_query-groups}", - "composite" : false, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - }, { - "id" : "277351bd-d091-4f9c-b7f2-474d627852c3", - "name" : "view-users", - "description" : "${role_view-users}", - "composite" : true, - "composites" : { - "client" : { - "realm-management" : [ "query-users", "query-groups" ] - } - }, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - }, { - "id" : "e0d6dd5a-b7db-4819-a4dc-15358a39ee62", - "name" : "view-events", - "description" : "${role_view-events}", - "composite" : false, - "clientRole" : true, - "containerId" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "attributes" : { } - } ], - "security-admin-console" : [ ], - "admin-cli" : [ ], - "account-console" : [ ], - "broker" : [ ], - "account" : [ { - "id" : "61c7dd94-3036-48b6-9407-0e1aeccb2669", - "name" : "delete-account", - "description" : "${role_delete-account}", - "composite" : false, - "clientRole" : true, - "containerId" : "c5a139bc-a5f2-400a-81ef-94b7ea45d9fb", - "attributes" : { } - }, { - "id" : "4c4fec3c-9457-4c19-a3f6-3cf4cc29d57d", - "name" : "manage-account", - "composite" : false, - "clientRole" : true, - "containerId" : "c5a139bc-a5f2-400a-81ef-94b7ea45d9fb", - "attributes" : { } - } ] - } - }, - "groups" : [ ], - "defaultRole" : { - "id" : "d33af3a2-ff09-4831-acfa-4a261228b781", - "name" : "default-roles-dev-realm", - "description" : "${role_default-roles}", - "composite" : true, - "clientRole" : false, - "containerId" : "dev-realm" - }, - "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" : [ ], - "webAuthnPolicyPasswordlessRpEntityName" : "keycloak", - "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256" ], - "webAuthnPolicyPasswordlessRpId" : "", - "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified", - "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified", - "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified", - "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified", - "webAuthnPolicyPasswordlessCreateTimeout" : 0, - "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false, - "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ], - "clientProfiles" : { - "profiles" : [ ] - }, - "clientPolicies" : { - "policies" : [ { - "name" : "builtin-default-policy", - "builtin" : true, - "enable" : false - } ] - }, - "users" : [ { - "id" : "462c7cb4-e444-4eac-8d68-0686c30eb245", - "createdTimestamp" : 1621784842260, - "username" : "test", - "enabled" : true, - "totp" : false, - "emailVerified" : false, - "attributes" : { - "foot_size" : [ "46" ] - }, - "credentials" : [ { - "id" : "a0f53e85-a522-4ab4-85cb-95224dec8d35", - "type" : "password", - "createdDate" : 1621784863307, - "secretData" : "{\"value\":\"MFcHPyUSTiRqMhJum6z9KSIZbwJZAUswqq1zoVjoA6Cse8iylnjw9fOkEO72IWgS+PIj3RW7WB/CUp2deW8Swg==\",\"salt\":\"WztZBrFIbqNmEMGkQer7eQ==\",\"additionalParameters\":{}}", - "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" - } ], - "disableableCredentialTypes" : [ ], - "requiredActions" : [ ], - "realmRoles" : [ "default-roles-dev-realm" ], - "notBefore" : 0, - "groups" : [ ] - } ], - "scopeMappings" : [ { - "clientScope" : "offline_access", - "roles" : [ "offline_access" ] - } ], - "clientScopeMappings" : { - "account" : [ { - "client" : "account-console", - "roles" : [ "manage-account" ] - } ] - }, - "clients" : [ { - "id" : "c5a139bc-a5f2-400a-81ef-94b7ea45d9fb", - "clientId" : "account", - "name" : "${client_account}", - "rootUrl" : "${authBaseUrl}", - "baseUrl" : "/realms/dev-realm/account/", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ "/realms/dev-realm/account/*" ], - "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, - "defaultClientScopes" : [ "web-origins", "roles", "profile", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] - }, { - "id" : "23848e89-7cd9-4145-8b12-da948009dcec", - "clientId" : "account-console", - "name" : "${client_account-console}", - "rootUrl" : "${authBaseUrl}", - "baseUrl" : "/realms/dev-realm/account/", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ "/realms/dev-realm/account/*" ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "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", - "login_theme" : "base-with-attribute", - "oauth2.device.authorization.grant.enabled" : "false", - "backchannel.logout.revoke.offline.tokens" : "false", - "saml.server.signature" : "false", - "saml.server.signature.keyinfo.ext" : "false", - "use.refresh.tokens" : "true", - "exclude.session.state.from.auth.response" : "false", - "oidc.ciba.grant.enabled" : "false", - "saml.artifact.binding" : "false", - "backchannel.logout.session.required" : "false", - "client_credentials.use_refresh_token" : "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", - "pkce.code.challenge.method" : "S256", - "saml.onetimeuse.condition" : "false" - }, - "authenticationFlowBindingOverrides" : { - "browser" : "5821e943-ed1d-4586-94eb-94737cfcb70a" - }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "protocolMappers" : [ { - "id" : "8847fe0f-7c80-46c0-a2be-d0194e8e9ae6", - "name" : "audience resolve", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-audience-resolve-mapper", - "consentRequired" : false, - "config" : { } - } ], - "defaultClientScopes" : [ "web-origins", "roles", "profile", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] - }, { - "id" : "e296987a-d12f-4e16-aa9d-2c6d8aa067dd", - "clientId" : "admin-cli", - "name" : "${client_admin-cli}", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-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", "roles", "profile", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] - }, { - "id" : "da82315c-af54-44e3-9a69-2523f246fbd5", - "clientId" : "broker", - "name" : "${client_broker}", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-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", "roles", "profile", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] - }, { - "id" : "92ab54ba-6e9b-4f66-b9bc-04c301092a1c", - "clientId" : "realm-management", - "name" : "${client_realm-management}", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-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", "roles", "profile", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] - }, { - "id" : "db704871-3d30-4d0e-8165-2e663dd64186", - "clientId" : "security-admin-console", - "name" : "${client_security-admin-console}", - "rootUrl" : "${authAdminUrl}", - "baseUrl" : "/admin/dev-realm/console/", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ "/admin/dev-realm/console/*" ], - "webOrigins" : [ "+" ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "pkce.code.challenge.method" : "S256" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "protocolMappers" : [ { - "id" : "2d526497-1ec0-4fc6-a6f7-e1c31cf40af7", - "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", "roles", "profile", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] - } ], - "clientScopes" : [ { - "id" : "1927365e-4a18-4ea6-a5b3-c1eb54e47fa6", - "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" : "275f5bce-38f4-49f6-855e-0cd8aaf83341", - "name" : "audience resolve", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-audience-resolve-mapper", - "consentRequired" : false, - "config" : { } - }, { - "id" : "bacb9f81-8f41-4c6e-86e8-3fd7e2e71723", - "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" : "571e6a47-897f-4bfd-92e5-2906c7bda7df", - "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" : "650aafa4-593d-47fc-8737-94132ae90035", - "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" : "a71419d5-5543-4200-b705-f6a182e122ad", - "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" : "3e2d3747-d064-4ba2-933a-736a6dc744d8", - "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" : "068c5ecf-18c0-4a71-8b77-10e4dc08eb79", - "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" : "34421bdd-d1ad-4962-943e-8d91ed7ab325", - "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" : "23ce6e65-f224-4e83-bfb5-4824216698aa", - "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" : "04817158-8e73-4189-8077-40b3cbacace0", - "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" : "31994540-b641-4aba-9c66-f4d73cf39769", - "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" : "4f71ad31-82a2-4815-a44f-ead64e4e7fb7", - "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" : "c237abf3-dec7-439e-a827-7ff73ebcd59e", - "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" : "d59240cf-5e68-40ee-a7a3-e3beb207ba03", - "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" : "88fb8961-a2a9-482a-8422-3047563e7de8", - "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" : "cbd02e6b-e84f-48e1-b123-25042cfe2255", - "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" : "796be53b-e63e-4298-9dbd-70e8a76e20a7", - "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" : "610dd39f-1f61-48a9-b18d-81cea649c639", - "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" : "5b2ac6ba-a3e3-4aad-8c62-1a8cd055e338", - "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" : "1b1574dd-f03e-4ace-bad8-7671403ff256", - "name" : "role_list", - "description" : "SAML role list", - "protocol" : "saml", - "attributes" : { - "consent.screen.text" : "${samlRoleListScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "f72a4d61-7436-4587-8c32-b8663d7c6416", - "name" : "role list", - "protocol" : "saml", - "protocolMapper" : "saml-role-list-mapper", - "consentRequired" : false, - "config" : { - "single" : "false", - "attribute.nameformat" : "Basic", - "attribute.name" : "Role" - } - } ] - }, { - "id" : "8eb2c6cc-0e7e-481c-9006-4fa06cded9da", - "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" : "46535a43-f3e7-46a9-bcfd-366e52ef15ff", - "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" : "df757b8b-f560-401e-b551-7707250c9a85", - "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" : "142f3d21-2d60-49fb-a700-df53b1d0f36f", - "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" : "bee4ba92-87d5-4c88-b2fd-344fe227eb54", - "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" : "1c1982ad-1a06-4933-bcd7-65d233fac997", - "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" : "a3826fa8-8c00-4bc7-88e1-fb4a0ab0ca49", - "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" : "62e3c7db-2d1c-4288-964e-f436bb494bac", - "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" : "81b885a9-c0f9-475e-9c2c-c4c5d97dc8d1", - "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" : "caf5e82c-ecde-4efb-9989-13dca4aa31a8", - "name" : "groups", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-realm-role-mapper", - "consentRequired" : false, - "config" : { - "multivalued" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "foo", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "groups", - "jsonType.label" : "String" - } - }, { - "id" : "16ffd04f-6b57-495e-8c7a-5f59064ebb20", - "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" : "c50ad084-c5a3-4ec5-b814-3498926bf8d6", - "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" : "0fabd591-642a-4b8f-a5ca-315beef0a29d", - "name" : "allowed web origins", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-allowed-origins-mapper", - "consentRequired" : false, - "config" : { } - } ] - } ], - "defaultDefaultClientScopes" : [ "roles", "role_list", "email", "profile", "web-origins" ], - "defaultOptionalClientScopes" : [ "address", "offline_access", "microprofile-jwt", "phone" ], - "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, - "identityProviders" : [ ], - "identityProviderMappers" : [ ], - "components" : { - "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ { - "id" : "b05e8de3-397b-4d32-af84-9966a616fade", - "name" : "Allowed Protocol Mapper Types", - "providerId" : "allowed-protocol-mappers", - "subType" : "authenticated", - "subComponents" : { }, - "config" : { - "allowed-protocol-mapper-types" : [ "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-attribute-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-address-mapper", "saml-user-attribute-mapper" ] - } - }, { - "id" : "fb52ec50-4670-4c93-ba6f-8f788cc66c37", - "name" : "Allowed Protocol Mapper Types", - "providerId" : "allowed-protocol-mappers", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "saml-user-attribute-mapper", "oidc-usermodel-attribute-mapper", "oidc-full-name-mapper", "oidc-usermodel-property-mapper", "oidc-address-mapper", "saml-user-property-mapper", "saml-role-list-mapper" ] - } - }, { - "id" : "7a56d293-e0d5-4abd-9c7d-2c26357d8df9", - "name" : "Allowed Client Scopes", - "providerId" : "allowed-client-templates", - "subType" : "authenticated", - "subComponents" : { }, - "config" : { - "allow-default-scopes" : [ "true" ] - } - }, { - "id" : "c11baf0b-198f-4e62-a0b8-7c3105feaa68", - "name" : "Allowed Client Scopes", - "providerId" : "allowed-client-templates", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "allow-default-scopes" : [ "true" ] - } - }, { - "id" : "f169f251-9dd3-4f12-bd77-2cb32fbd56bf", - "name" : "Full Scope Disabled", - "providerId" : "scope", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { } - }, { - "id" : "cad1ead1-d047-4b02-bd40-0ae39f3b43d5", - "name" : "Trusted Hosts", - "providerId" : "trusted-hosts", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "host-sending-registration-request-must-match" : [ "true" ], - "client-uris-must-match" : [ "true" ] - } - }, { - "id" : "1ecaad76-c287-463a-a047-df57a87e1ece", - "name" : "Max Clients Limit", - "providerId" : "max-clients", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "max-clients" : [ "200" ] - } - }, { - "id" : "2fef13f9-82ec-4d11-844b-91f2579e0f41", - "name" : "Consent Required", - "providerId" : "consent-required", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { } - } ], - "org.keycloak.keys.KeyProvider" : [ { - "id" : "48f1d0ad-88df-4f05-af32-9f9866742df1", - "name" : "hmac-generated", - "providerId" : "hmac-generated", - "subComponents" : { }, - "config" : { - "kid" : [ "372ba0f8-c5a2-400d-9776-dc17e1daa067" ], - "secret" : [ "kK2s6ddtY20eWA4nWp9bMAaTQC6tUH88dbptqhKyyPNjQlxKBAHD-Hc-Guilb-f-MtN7r40_hW_Q8VErY7t5AA" ], - "priority" : [ "100" ], - "algorithm" : [ "HS256" ] - } - }, { - "id" : "acaf1a5b-87ca-4d19-8659-e224dad5825a", - "name" : "rsa-generated", - "providerId" : "rsa-generated", - "subComponents" : { }, - "config" : { - "privateKey" : [ "MIIEowIBAAKCAQEAjBmNgFh6gx8nTRP+E7ZJDg87FfIAVo8iCrq17WQsl4KrBbVl/YVLEvr5EW2LqBnsRUZDZGtwXtZ+QNMsOzyerOoUcJMlU13Hwq92F80wQaDRRvUCtxxtD6cT2QDmWbf+aa9TTYYpEL5OS8CVCZol+4+DbzH4Bg7tMKAr8NNSr660jDGMvy8/VK3AJ0Zkc6mGt/wUw3wF1cOZXHRtsftCYNGYZEKkkAMlG3OOqGVzKpTL6XRqApJnbow+chQmwTnxXMXgLVyRQToJOHYqw83P9qhkpfnkzaKqKklv337DNN97eVqmGNb7E4lvqtaiR6LVWyeS541xDlW61fbFT8bP3QIDAQABAoIBAEP6Ng1bYP50REaC99oqrWHUBBBO3tkhFBxuoc1wuK4/KapYbQdJALdR7T4GkCfdhCXMxPBZrSlnG9VqYWDQthEidw50Zzz/GOke58b+uXZuiHzMbyfX9BcPM3Msm5hWzWwMNPg9q3lDTYw2AlqpX9qitNxkO3r9DRt17Dwq3Uj+WLCZ9KvL8ePE6ujfJ6BohB1Mg0acZSqdyRQfeVzUQ2kwDYnqqUaGevsJviRP8b/MoPVaMvGPRHeLfr6ylixUaSHUMwS2dCczofTyys7jqiP/1E740rV4S6HizhO+VsD7Tb8meH/rRuW9N013uLzknhil1APe0Nu7Myw0uWOPFGECgYEA7E+WD/Q06U02ddnL8/el5DRqH9j7LdYuADWwaVJrnV3xjG8Ze5oHnoWxUt/QXY7amWuZz6uxRR4xhQU3NXvI3t/lLiLcCgtvSO0gDYwCJhJ9bE5fdP5dKMj01HWoMHmGC+mgcCS/p2IXO6C240RxtZCiE8ykAiP64eG0scPVfXUCgYEAl8XS+EQ015CqUTxi62+r6WBkZNeSLawj/8fiozVjH30q6UB9A18LXXuQfNToNs2IfKdSNTGo8uv0wOUF7c9oWYg58f7VPtBrxO9N544wwR6wCyJCV4r6f1eJmKGuflIxP+HfphISv2S9SFRbrEQLXfrG9VijDKE0+ncjE65lM8kCgYAwj/pqtOjauP9kIKoFLPNufkcA3Hph5Q33BRGH02RCJrgo//vgprrCHP9f5JbRYzYRKUemocYASkAq8fNyjkmtY52ZaZiGh+sKtZBMuGUIpewYgdKkHFHQu9t0felebNrbP9u0sBiisUnM+y4abkpf4aUtJHTf67z3Boc3sOMCsQKBgEOkpp+B/q8oydAFAu19yvfrvzL2pS737t98HfWxwKjzJ2HoHQ+Yl78laENKvOhX+IHeLRSKOotyQJaMPHU+IHru7Sx+8FnbmHygT29pfy9DVyDPNxQ/W9/PiwLc5KFmTo7zQ7OHkJV+96G5/1Wqygorz+rfg2QIoU0UNiz6aB6JAoGBAJOBObmMjnH/0uy0+QzkA6ALciBHD5MjuvsXcn211hlLYcnzi2CdJYUoZ2iF0vUnLu231kG/tZX7Pv350+AJHlJzvfAcQr5tlV3S0aHtR3IAiviEhTHQuECdC0ALTp2puaCfVbjpb3LB94F6RBAfe9CKdittrOeKPkDgYEBAeent" ], - "certificate" : [ "MIICoTCCAYkCBgF5mb2TNjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlkZXYtcmVhbG0wHhcNMjEwNTIzMTQ1ODI4WhcNMzEwNTIzMTUwMDA4WjAUMRIwEAYDVQQDDAlkZXYtcmVhbG0wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCMGY2AWHqDHydNE/4TtkkODzsV8gBWjyIKurXtZCyXgqsFtWX9hUsS+vkRbYuoGexFRkNka3Be1n5A0yw7PJ6s6hRwkyVTXcfCr3YXzTBBoNFG9QK3HG0PpxPZAOZZt/5pr1NNhikQvk5LwJUJmiX7j4NvMfgGDu0woCvw01KvrrSMMYy/Lz9UrcAnRmRzqYa3/BTDfAXVw5lcdG2x+0Jg0ZhkQqSQAyUbc46oZXMqlMvpdGoCkmdujD5yFCbBOfFcxeAtXJFBOgk4dirDzc/2qGSl+eTNoqoqSW/ffsM033t5WqYY1vsTiW+q1qJHotVbJ5LnjXEOVbrV9sVPxs/dAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAHpNE9yKSQlTkCzlZq1/sOrX6IjUbEP/wKhCjrT19XbB1XikslMi3N6fHu6m/rD69vjZxd7HHyD11VhumkzdP2DU9EBWXKLyjHJXiV0a6Ajrq+WCTY/dOPOvpPhuYBSStTWbnyVqoLYjts3BDZUl23OrsIrFvdyyqQXFqAz8E2q9TCBwatYfP9uFUi8UBwZqQDvcAcYBmJo6OmVjINlij/Jcs69KsNSF/+O+gjFla0/l8ZJN3gFA2t5tRsVn153jlXoWTe8Isqy0VIFWmo0JvmAAfbB25QMwko7/B1BODD/qPViCf6CKVgk+UZ8xSm55I8bQ6HyydZAOxhgliRJqAM4=" ], - "priority" : [ "100" ] - } - }, { - "id" : "9fa560cb-9f5d-479b-8fe3-aafcc27438be", - "name" : "aes-generated", - "providerId" : "aes-generated", - "subComponents" : { }, - "config" : { - "kid" : [ "38e9be73-306f-4a75-be03-5a7bd753c1f3" ], - "secret" : [ "itjvbx5ySPhpafz7sL3JBw" ], - "priority" : [ "100" ] - } - } ] - }, - "internationalizationEnabled" : false, - "supportedLocales" : [ ], - "authenticationFlows" : [ { - "id" : "7b139c9e-957e-47be-a5a3-a69f12dde405", - "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", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 20, - "flowAlias" : "Verify Existing Account by Re-authentication", - "userSetupAllowed" : false, - "autheticatorFlow" : true - } ] - }, { - "id" : "fbba2eb2-102c-4689-8956-e39d16d08ec7", - "alias" : "Authentication Options", - "description" : "Authentication options.", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "basic-auth", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "basic-auth-otp", - "authenticatorFlow" : false, - "requirement" : "DISABLED", - "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "auth-spnego", - "authenticatorFlow" : false, - "requirement" : "DISABLED", - "priority" : 30, - "userSetupAllowed" : false, - "autheticatorFlow" : false - } ] - }, { - "id" : "d7f36066-7cb3-4b68-acb8-222260085ad7", - "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", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "auth-otp-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false - } ] - }, { - "id" : "5821e943-ed1d-4586-94eb-94737cfcb70a", - "alias" : "Browser with user attribute", - "description" : "browser based authentication", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : false, - "authenticationExecutions" : [ { - "authenticator" : "auth-cookie", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "auth-spnego", - "authenticatorFlow" : false, - "requirement" : "DISABLED", - "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "identity-provider-redirector", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 25, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 30, - "flowAlias" : "Browser with user attribute forms", - "userSetupAllowed" : false, - "autheticatorFlow" : true - } ] - }, { - "id" : "d57a67e5-82d5-43f5-ab14-26e222410e0f", - "alias" : "Browser with user attribute Browser - Conditional OTP", - "description" : "Flow to determine if the OTP is required for the authentication", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : false, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "auth-otp-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false - } ] - }, { - "id" : "63d2e484-9632-48ee-abe8-9dd2b942ee49", - "alias" : "Browser with user attribute forms", - "description" : "Username, password, otp and other auth forms.", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : false, - "authenticationExecutions" : [ { - "authenticatorConfig" : "foot_size form", - "authenticator" : "auth-username-password-attr-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 21, - "flowAlias" : "Browser with user attribute Browser - Conditional OTP", - "userSetupAllowed" : false, - "autheticatorFlow" : true - } ] - }, { - "id" : "8ddce5ce-4810-4ec7-90d7-e77446e985d1", - "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", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "direct-grant-validate-otp", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false - } ] - }, { - "id" : "5c20b6a9-7d97-4b59-bba1-b656500c82b3", - "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", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "auth-otp-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false - } ] - }, { - "id" : "f4138a98-fb99-4455-a825-6b7a717cf8c7", - "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", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticatorFlow" : true, - "requirement" : "REQUIRED", - "priority" : 20, - "flowAlias" : "Account verification options", - "userSetupAllowed" : false, - "autheticatorFlow" : true - } ] - }, { - "id" : "3c89516a-3072-4ae3-a95f-dd5b5cb5caa4", - "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", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "reset-otp", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false - } ] - }, { - "id" : "9e73043f-c10d-4cd2-aedf-4ab3cdf98a24", - "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", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 20, - "flowAlias" : "Handle Existing Account", - "userSetupAllowed" : false, - "autheticatorFlow" : true - } ] - }, { - "id" : "2f04ee16-f2e7-4963-8225-517c1f1094d7", - "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", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 20, - "flowAlias" : "First broker login - Conditional OTP", - "userSetupAllowed" : false, - "autheticatorFlow" : true - } ] - }, { - "id" : "98c9498d-567e-4c06-a66d-c18e822f411e", - "alias" : "browser", - "description" : "browser based authentication", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "auth-cookie", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "auth-spnego", - "authenticatorFlow" : false, - "requirement" : "DISABLED", - "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "identity-provider-redirector", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 25, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 30, - "flowAlias" : "forms", - "userSetupAllowed" : false, - "autheticatorFlow" : true - } ] - }, { - "id" : "64342850-b437-4249-a03d-06b54cd992ed", - "alias" : "clients", - "description" : "Base authentication for clients", - "providerId" : "client-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "client-secret", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "client-jwt", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "client-secret-jwt", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 30, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "client-x509", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 40, - "userSetupAllowed" : false, - "autheticatorFlow" : false - } ] - }, { - "id" : "550ed946-264f-4a25-a074-5a3f870db190", - "alias" : "direct grant", - "description" : "OpenID Connect Resource Owner Grant", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "direct-grant-validate-username", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "direct-grant-validate-password", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 30, - "flowAlias" : "Direct Grant - Conditional OTP", - "userSetupAllowed" : false, - "autheticatorFlow" : true - } ] - }, { - "id" : "118eed11-490e-457f-b373-7669d9601178", - "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", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - } ] - }, { - "id" : "ca18811d-7ff3-48f9-9740-01b2b505f494", - "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", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticatorFlow" : true, - "requirement" : "REQUIRED", - "priority" : 20, - "flowAlias" : "User creation or linking", - "userSetupAllowed" : false, - "autheticatorFlow" : true - } ] - }, { - "id" : "0a5d7ced-7aaf-4816-9983-36dbbd2279f9", - "alias" : "forms", - "description" : "Username, password, otp and other auth forms.", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "auth-username-password-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 20, - "flowAlias" : "Browser - Conditional OTP", - "userSetupAllowed" : false, - "autheticatorFlow" : true - } ] - }, { - "id" : "078c1520-073b-40ff-b48e-6a655ae6fa22", - "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", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticatorFlow" : true, - "requirement" : "REQUIRED", - "priority" : 20, - "flowAlias" : "Authentication Options", - "userSetupAllowed" : false, - "autheticatorFlow" : true - } ] - }, { - "id" : "9a38ca67-9292-4593-bb59-4ff56ba0a963", - "alias" : "registration", - "description" : "registration flow", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "registration-page-form", - "authenticatorFlow" : true, - "requirement" : "REQUIRED", - "priority" : 10, - "flowAlias" : "registration form", - "userSetupAllowed" : false, - "autheticatorFlow" : true - } ] - }, { - "id" : "3bcba973-e02c-4deb-bd1a-0267810d1a55", - "alias" : "registration form", - "description" : "registration form", - "providerId" : "form-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "registration-user-creation", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "registration-profile-action", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 40, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "registration-password-action", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 50, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "registration-recaptcha-action", - "authenticatorFlow" : false, - "requirement" : "DISABLED", - "priority" : 60, - "userSetupAllowed" : false, - "autheticatorFlow" : false - } ] - }, { - "id" : "10f26923-105c-4a49-8a8f-9698a72c70a8", - "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", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "reset-credential-email", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticator" : "reset-password", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 30, - "userSetupAllowed" : false, - "autheticatorFlow" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 40, - "flowAlias" : "Reset - Conditional OTP", - "userSetupAllowed" : false, - "autheticatorFlow" : true - } ] - }, { - "id" : "286812a9-25fd-45b1-a1e3-dc472ab1da94", - "alias" : "saml ecp", - "description" : "SAML ECP Profile Authentication Flow", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "http-basic-authenticator", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "userSetupAllowed" : false, - "autheticatorFlow" : false - } ] - } ], - "authenticatorConfig" : [ { - "id" : "85879435-ec83-4236-a935-72bffa66f643", - "alias" : "create unique user config", - "config" : { - "require.password.update.after.registration" : "false" - } - }, { - "id" : "ffefd84e-6290-4a1a-b068-b0fede72c539", - "alias" : "review profile config", - "config" : { - "update.profile.on.first.login" : "missing" - } - }, { - "id" : "313d1d2f-08ac-4e5f-9eef-9899e0a64d3d", - "alias" : "foot_size form", - "config" : { - "login_form_user_attribute" : "foot_size", - "clear_user_on_attribute_validation_fail" : "true", - "login_form_generate_label": "true" - } - }, { - "id" : "def2c287-f0b2-4b71-bf8e-9dee33bcbe6b", - "alias" : "foot_size auth", - "config" : { - "user_attribute" : "foot_size" - } - } ], - "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" : { } - }, { - "alias" : "delete_account", - "name" : "Delete Account", - "providerId" : "delete_account", - "enabled" : false, - "defaultAction" : false, - "priority" : 60, - "config" : { } - }, { - "alias" : "update_user_locale", - "name" : "Update User Locale", - "providerId" : "update_user_locale", - "enabled" : true, - "defaultAction" : false, - "priority" : 1000, - "config" : { } - } ], - "browserFlow" : "browser", - "registrationFlow" : "registration", - "directGrantFlow" : "direct grant", - "resetCredentialsFlow" : "reset credentials", - "clientAuthenticationFlow" : "clients", - "dockerAuthenticationFlow" : "docker auth", - "attributes" : { - "cibaBackchannelTokenDeliveryMode" : "poll", - "cibaExpiresIn" : "120", - "cibaAuthRequestedUserHint" : "login_hint", - "oauth2DeviceCodeLifespan" : "600", - "clientOfflineSessionMaxLifespan" : "0", - "oauth2DevicePollingInterval" : "5", - "clientSessionIdleTimeout" : "0", - "clientSessionMaxLifespan" : "0", - "clientOfflineSessionIdleTimeout" : "0", - "cibaInterval" : "5" - }, - "keycloakVersion" : "13.0.0", - "userManagedAccessAllowed" : false -} \ No newline at end of file diff --git a/src/test/resources/log4j.properties b/src/test/resources/log4j.properties deleted file mode 100644 index 23f534f..0000000 --- a/src/test/resources/log4j.properties +++ /dev/null @@ -1,4 +0,0 @@ -log4j.rootLogger=INFO, theConsoleAppender -log4j.appender.theConsoleAppender=org.apache.log4j.ConsoleAppender -log4j.appender.theConsoleAppender.layout=org.apache.log4j.PatternLayout -log4j.appender.theConsoleAppender.layout.ConversionPattern=[%t] - %m%n \ No newline at end of file