From 8ce9414e09e7d4332c4c3997572ab485d5decd99 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 18 Oct 2023 16:08:07 +0200 Subject: [PATCH 01/14] feat: added Keycloak support for email 2fa to --- keycloak/Dockerfile | 17 +++++++++++++---- .../email/messages/messages_en.properties | 2 ++ .../login/messages/messages_en.properties | 1 + 3 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 keycloak/aam-theme/login/messages/messages_en.properties diff --git a/keycloak/Dockerfile b/keycloak/Dockerfile index 8731015..b77c9f1 100644 --- a/keycloak/Dockerfile +++ b/keycloak/Dockerfile @@ -1,9 +1,18 @@ +# Build repos that are not delpoyed (because these are feature branches) +FROM maven:3.9.4-eclipse-temurin-17 AS java +RUN git clone https://github.com/Perchouille/keycloak-spi-trusted-device.git trusted-device +RUN cd trusted-device && mvn package +RUN git clone https://github.com/Aam-Digital/keycloak-2fa-email-authenticator.git email-auth +RUN cd email-auth && mvn package + # Inspired by https://www.keycloak.org/server/containers -FROM quay.io/keycloak/keycloak:19.0.1 as builder +FROM quay.io/keycloak/keycloak:22.0.1 AS builder ARG KC_DB=postgres -RUN curl -L https://github.com/aerogear/keycloak-metrics-spi/releases/download/3.0.0/keycloak-metrics-spi-3.0.0.jar > /opt/keycloak/providers/keycloak-metrics-spi.jar +ADD --chown=keycloak:keycloak https://github.com/aerogear/keycloak-metrics-spi/releases/download/3.0.0/keycloak-metrics-spi-3.0.0.jar /opt/keycloak/providers/keycloak-metrics-spi.jar +COPY --from=java trusted-device/spi/target/keycloak-spi-trusted-device-1.0-SNAPSHOT.jar /opt/keycloak/providers/keycloak-trusted-device.jar +COPY --from=java email-auth/target/keycloak-2fa-email-authenticator-1.0.0.0-SNAPSHOT.jar /opt/keycloak/providers/keycloak-2fa-email-authenticator.jar RUN /opt/keycloak/bin/kc.sh build -FROM quay.io/keycloak/keycloak:19.0.1 +FROM quay.io/keycloak/keycloak:22.0.1 COPY --from=builder /opt/keycloak/lib/quarkus/ /opt/keycloak/lib/quarkus/ -COPY --from=builder /opt/keycloak/providers/keycloak-metrics-spi.jar /opt/keycloak/providers/ +COPY --from=builder /opt/keycloak/providers /opt/keycloak/providers/ diff --git a/keycloak/aam-theme/email/messages/messages_en.properties b/keycloak/aam-theme/email/messages/messages_en.properties index 08414a7..8234dc0 100644 --- a/keycloak/aam-theme/email/messages/messages_en.properties +++ b/keycloak/aam-theme/email/messages/messages_en.properties @@ -2,3 +2,5 @@ emailVerificationBody=Your email has been linked to the Aam Digital user: {1}. T emailVerificationBodyHtml=

Your email has been linked to the Aam Digital user: {1}. To verify your email, click the link below. After verifying your email, you will be forwarded to the Aam Digital application.

Verify email

This link will expire within {3}.

Please keep in mind that your account gives access to personal information of your project''s participants that should be handled with care. Don''t share your access with anyone.

After verifying your email, you can open the Application with the link below.

Open Aam Digital

passwordResetBody=Someone just requested to change the password for your Aam Digital account with the name: {1}. If this was you, click on the link below to reset it.\n\n{0}\n\nThis link and code will expire within {3}.\n\nIf you don''t want to reset your password, just ignore this message and nothing will be changed. passwordResetBodyHtml=

Someone just requested to change the password for your Aam Digital account with the name: {1}. If this was you, click on the link below to reset it.

Reset password

This link will expire within {3}.

If you don''t want to reset your password, just ignore this message and nothing will be changed.

+emailCodeSubject={0} access code +emailCodeBody=Access code: {0}\n\n.This code will expire within {1} seconds. diff --git a/keycloak/aam-theme/login/messages/messages_en.properties b/keycloak/aam-theme/login/messages/messages_en.properties new file mode 100644 index 0000000..32b20fb --- /dev/null +++ b/keycloak/aam-theme/login/messages/messages_en.properties @@ -0,0 +1 @@ +resendCode=Resend code From 1c3d5a765ef2902314ffcfef357ce61ef214a019 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 19 Oct 2023 12:44:37 +0200 Subject: [PATCH 02/14] added email template --- keycloak/aam-theme/email/html/code-email.ftl | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 keycloak/aam-theme/email/html/code-email.ftl diff --git a/keycloak/aam-theme/email/html/code-email.ftl b/keycloak/aam-theme/email/html/code-email.ftl new file mode 100644 index 0000000..d88693d --- /dev/null +++ b/keycloak/aam-theme/email/html/code-email.ftl @@ -0,0 +1,5 @@ + + +${kcSanitize(msg("emailCodeBody", code, ttl))?no_esc} + + From 1a0bd311bc114bdfc6fb9c7d416737b12557d7b0 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 19 Oct 2023 12:47:05 +0200 Subject: [PATCH 03/14] added text template --- keycloak/aam-theme/email/text/code-email.ftl | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 keycloak/aam-theme/email/text/code-email.ftl diff --git a/keycloak/aam-theme/email/text/code-email.ftl b/keycloak/aam-theme/email/text/code-email.ftl new file mode 100644 index 0000000..b786836 --- /dev/null +++ b/keycloak/aam-theme/email/text/code-email.ftl @@ -0,0 +1,2 @@ +<#ftl output_format="plainText"> +${msg("emailCodeBody", code, ttl)} \ No newline at end of file From 85914b96392c94a72515fe255f3392fe95c0c841 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 19 Oct 2023 15:17:59 +0200 Subject: [PATCH 04/14] improved template --- keycloak/aam-theme/email/html/code-email.ftl | 2 +- keycloak/aam-theme/email/messages/messages_en.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/keycloak/aam-theme/email/html/code-email.ftl b/keycloak/aam-theme/email/html/code-email.ftl index d88693d..7945037 100644 --- a/keycloak/aam-theme/email/html/code-email.ftl +++ b/keycloak/aam-theme/email/html/code-email.ftl @@ -1,5 +1,5 @@ -${kcSanitize(msg("emailCodeBody", code, ttl))?no_esc} +${kcSanitize(msg("emailCodeBody", code, ttl))} diff --git a/keycloak/aam-theme/email/messages/messages_en.properties b/keycloak/aam-theme/email/messages/messages_en.properties index 8234dc0..3e4ed55 100644 --- a/keycloak/aam-theme/email/messages/messages_en.properties +++ b/keycloak/aam-theme/email/messages/messages_en.properties @@ -3,4 +3,4 @@ emailVerificationBodyHtml=

Your email has been linked to the Aam Digital user: passwordResetBody=Someone just requested to change the password for your Aam Digital account with the name: {1}. If this was you, click on the link below to reset it.\n\n{0}\n\nThis link and code will expire within {3}.\n\nIf you don''t want to reset your password, just ignore this message and nothing will be changed. passwordResetBodyHtml=

Someone just requested to change the password for your Aam Digital account with the name: {1}. If this was you, click on the link below to reset it.

Reset password

This link will expire within {3}.

If you don''t want to reset your password, just ignore this message and nothing will be changed.

emailCodeSubject={0} access code -emailCodeBody=Access code: {0}\n\n.This code will expire within {1} seconds. +emailCodeBody=Access code: {0}. \n\nThis code will expire within {1} seconds. From 5806867bb538355342321b82c81a444971996546 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 19 Oct 2023 15:18:25 +0200 Subject: [PATCH 05/14] updated client config with necessary default scopes for retrieving email data --- keycloak/client_config.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/keycloak/client_config.json b/keycloak/client_config.json index 65bdd63..a8b0286 100644 --- a/keycloak/client_config.json +++ b/keycloak/client_config.json @@ -88,6 +88,9 @@ } ], "defaultClientScopes": [ + "web-origins", + "roles", + "profile", "email" ], "optionalClientScopes": [], From 733111b4575b9e52a1a99ff507dd608a693791a2 Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 19 Oct 2023 18:00:57 +0200 Subject: [PATCH 06/14] added favicon to login screen --- .../aam-theme/login/resources/img/favicon.ico | Bin 0 -> 101785 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 keycloak/aam-theme/login/resources/img/favicon.ico diff --git a/keycloak/aam-theme/login/resources/img/favicon.ico b/keycloak/aam-theme/login/resources/img/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..9320afdd6624b1266b0b5d5b19e12a1cd3c3981d GIT binary patch literal 101785 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ℜ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 literal 0 HcmV?d00001 From a93ef974f6ed6bccee7b2f806b122ed2048f59be Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 20 Oct 2023 13:52:59 +0200 Subject: [PATCH 07/14] added newline --- keycloak/aam-theme/email/text/code-email.ftl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keycloak/aam-theme/email/text/code-email.ftl b/keycloak/aam-theme/email/text/code-email.ftl index b786836..3240f6e 100644 --- a/keycloak/aam-theme/email/text/code-email.ftl +++ b/keycloak/aam-theme/email/text/code-email.ftl @@ -1,2 +1,2 @@ <#ftl output_format="plainText"> -${msg("emailCodeBody", code, ttl)} \ No newline at end of file +${msg("emailCodeBody", code, ttl)} From 7082d107a12fc70da2470e32bb21cdb23100bcdc Mon Sep 17 00:00:00 2001 From: Simon Date: Sat, 21 Oct 2023 14:41:33 +0200 Subject: [PATCH 08/14] using official trusted device build --- keycloak/Dockerfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/keycloak/Dockerfile b/keycloak/Dockerfile index b77c9f1..cf368ee 100644 --- a/keycloak/Dockerfile +++ b/keycloak/Dockerfile @@ -1,7 +1,5 @@ # Build repos that are not delpoyed (because these are feature branches) FROM maven:3.9.4-eclipse-temurin-17 AS java -RUN git clone https://github.com/Perchouille/keycloak-spi-trusted-device.git trusted-device -RUN cd trusted-device && mvn package RUN git clone https://github.com/Aam-Digital/keycloak-2fa-email-authenticator.git email-auth RUN cd email-auth && mvn package @@ -9,7 +7,7 @@ RUN cd email-auth && mvn package FROM quay.io/keycloak/keycloak:22.0.1 AS builder ARG KC_DB=postgres ADD --chown=keycloak:keycloak https://github.com/aerogear/keycloak-metrics-spi/releases/download/3.0.0/keycloak-metrics-spi-3.0.0.jar /opt/keycloak/providers/keycloak-metrics-spi.jar -COPY --from=java trusted-device/spi/target/keycloak-spi-trusted-device-1.0-SNAPSHOT.jar /opt/keycloak/providers/keycloak-trusted-device.jar +ADD --chown=keycloak:keycloak https://github.com/wouterh-dev/keycloak-spi-trusted-device/releases/download/v0.0.1-22/keycloak-spi-trusted-device-0.0.1-22.jar /opt/keycloak/providers/keycloak-trusted-device.jar COPY --from=java email-auth/target/keycloak-2fa-email-authenticator-1.0.0.0-SNAPSHOT.jar /opt/keycloak/providers/keycloak-2fa-email-authenticator.jar RUN /opt/keycloak/bin/kc.sh build From a094afa94345f9a2bd547819fa75af64c7b6d17b Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 25 Oct 2023 15:26:48 +0200 Subject: [PATCH 09/14] updated keycloak version --- keycloak/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/keycloak/Dockerfile b/keycloak/Dockerfile index cf368ee..d651f13 100644 --- a/keycloak/Dockerfile +++ b/keycloak/Dockerfile @@ -4,13 +4,13 @@ RUN git clone https://github.com/Aam-Digital/keycloak-2fa-email-authenticator.gi RUN cd email-auth && mvn package # Inspired by https://www.keycloak.org/server/containers -FROM quay.io/keycloak/keycloak:22.0.1 AS builder +FROM quay.io/keycloak/keycloak:22.0.5 AS builder ARG KC_DB=postgres ADD --chown=keycloak:keycloak https://github.com/aerogear/keycloak-metrics-spi/releases/download/3.0.0/keycloak-metrics-spi-3.0.0.jar /opt/keycloak/providers/keycloak-metrics-spi.jar ADD --chown=keycloak:keycloak https://github.com/wouterh-dev/keycloak-spi-trusted-device/releases/download/v0.0.1-22/keycloak-spi-trusted-device-0.0.1-22.jar /opt/keycloak/providers/keycloak-trusted-device.jar COPY --from=java email-auth/target/keycloak-2fa-email-authenticator-1.0.0.0-SNAPSHOT.jar /opt/keycloak/providers/keycloak-2fa-email-authenticator.jar RUN /opt/keycloak/bin/kc.sh build -FROM quay.io/keycloak/keycloak:22.0.1 +FROM quay.io/keycloak/keycloak:22.0.5 COPY --from=builder /opt/keycloak/lib/quarkus/ /opt/keycloak/lib/quarkus/ COPY --from=builder /opt/keycloak/providers /opt/keycloak/providers/ From 84eae86fc10cf9ea42d5a33b5f0d384d98f7b48d Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 25 Oct 2023 16:51:06 +0200 Subject: [PATCH 10/14] added client scopes to support `/userinfo` changes --- keycloak/client_config.json | 6 +- keycloak/realm_config.json | 486 +++++++++++++++++++++++++++++++++++- 2 files changed, 487 insertions(+), 5 deletions(-) diff --git a/keycloak/client_config.json b/keycloak/client_config.json index a8b0286..cc96a6b 100644 --- a/keycloak/client_config.json +++ b/keycloak/client_config.json @@ -88,10 +88,8 @@ } ], "defaultClientScopes": [ - "web-origins", - "roles", - "profile", - "email" + "email", + "openid" ], "optionalClientScopes": [], "access": { diff --git a/keycloak/realm_config.json b/keycloak/realm_config.json index 645f85f..1ad54c2 100644 --- a/keycloak/realm_config.json +++ b/keycloak/realm_config.json @@ -70,5 +70,489 @@ "description": "${role_default-roles}", "composite": true, "clientRole": false - } + }, + "clientScopes": [ + + { + "id": "43b431ac-1ccf-4101-ab69-ba0b78d4167b", + "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": [ + { + "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" + } + }, + { + "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" + } + } + ] + }, + { + "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": [ + { + "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" + } + } + ] + }, + { + "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": [ + { + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + }, + { + "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" + } + }, + { + "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" + } + } + ] + }, + { + "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": [ + { + "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" + } + }, + { + "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" + } + }, + { + "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" + } + }, + { + "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" + } + }, + { + "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" + } + }, + { + "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" + } + }, + { + "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" + } + }, + { + "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" + } + }, + { + "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" + } + }, + { + "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" + } + }, + { + "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" + } + }, + { + "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" + } + }, + { + "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" + } + }, + { + "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" + } + } + ] + }, + { + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "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" + } + }, + { + "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" + } + } + ] + }, + { + "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": [ + { + "name": "acr loa level", + "protocol": "openid-connect", + "protocolMapper": "oidc-acr-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "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": [ + { + "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" + } + }, + { + "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" + } + } + ] + }, + { + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "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": [ + { + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "name": "openid", + "description": "", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "gui.order": "", + "consent.screen.text": "" + } + } + ] } From 7884e385325d315d5a6b73b8be080db38380f3ac Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 25 Oct 2023 17:17:21 +0200 Subject: [PATCH 11/14] added passwort reset and remember me to login page --- keycloak/realm_config.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/keycloak/realm_config.json b/keycloak/realm_config.json index 1ad54c2..b96f9e2 100644 --- a/keycloak/realm_config.json +++ b/keycloak/realm_config.json @@ -2,6 +2,8 @@ "enabled": true, "loginTheme": "aam-theme", "emailTheme": "aam-theme", + "rememberMe": true, + "resetPasswordAllowed": true, "accessTokenLifespan": 300, "ssoSessionIdleTimeout": 7200, "ssoSessionMaxLifespan": 36000, @@ -14,12 +16,12 @@ "ssl": "false", "replyTo": "", "replyToDisplayName": "", - "from": "", - "fromDisplayName": "", - "host": "", - "port": "", - "user": "", - "password": "" + "from": "accounts@aam-digital.com", + "fromDisplayName": "Aam Digital", + "host": "w01b1893.kasserver.com", + "port": "587", + "user": "accounts@aam-digital.com", + "password": "Bx2*4EdhVe@@" }, "eventsListeners": [ "metrics-listener", @@ -72,9 +74,7 @@ "clientRole": false }, "clientScopes": [ - { - "id": "43b431ac-1ccf-4101-ab69-ba0b78d4167b", "name": "email", "description": "OpenID Connect built-in scope: email", "protocol": "openid-connect", From 11c41e3260d0f026e7859ba8debc952476774f3a Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 25 Oct 2023 17:18:19 +0200 Subject: [PATCH 12/14] made background color white --- keycloak/aam-theme/login/resources/css/styles.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keycloak/aam-theme/login/resources/css/styles.css b/keycloak/aam-theme/login/resources/css/styles.css index 5aa172a..625dd5c 100644 --- a/keycloak/aam-theme/login/resources/css/styles.css +++ b/keycloak/aam-theme/login/resources/css/styles.css @@ -1,5 +1,5 @@ .login-pf body { - background: #fff3e0; + background: white; } .card-pf { From 054169b7aea25ff70d17ab51af2506ef13097679 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 25 Oct 2023 17:51:10 +0200 Subject: [PATCH 13/14] added browser 2fa flow --- keycloak/realm_config.json | 623 +++++++++++++++++++++++++++++++++++++ 1 file changed, 623 insertions(+) diff --git a/keycloak/realm_config.json b/keycloak/realm_config.json index b96f9e2..8c2bdc4 100644 --- a/keycloak/realm_config.json +++ b/keycloak/realm_config.json @@ -73,6 +73,629 @@ "composite": true, "clientRole": false }, + "authenticationFlows": [ + { + "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 + } + ] + }, + { + "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 + } + ] + }, + { + "alias": "browser 2FA", + "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": "forms and OTP", + "userSetupAllowed": false + } + ] + }, + { + "alias": "forms and OTP", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": false, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 11, + "autheticatorFlow": true, + "flowAlias": "email OTP", + "userSetupAllowed": false + } + ] + }, + { + "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 + } + ] + }, + { + "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 + } + ] + }, + { + "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 + } + ] + }, + { + "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 + } + ] + }, + { + "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 + } + ] + }, + { + "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 + } + ] + }, + { + "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 + } + ] + }, + { + "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 + } + ] + }, + { + "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 + } + ] + }, + { + "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 + } + ] + }, + { + "alias": "email OTP", + "description": "", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": false, + "authenticationExecutions": [ + { + "authenticatorConfig": "trusted-config", + "authenticator": "trusted-device-condition", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 0, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "email-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 1, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "trusted-device-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 2, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "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 + } + ] + }, + { + "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 + } + ] + }, + { + "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 + } + ] + }, + { + "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 + } + ] + }, + { + "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 + } + ] + }, + { + "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": [ + { + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + }, + { + "alias": "trusted-config", + "config": { + "negate": "true" + } + } + ], "clientScopes": [ { "name": "email", From 98659eabc643f5eb0296b9ce5f50209b6dffcc7a Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 25 Oct 2023 19:12:42 +0200 Subject: [PATCH 14/14] improved email templates --- keycloak/aam-theme/email/html/code-email.ftl | 5 ++++- keycloak/aam-theme/email/html/executeActions.ftl | 6 +----- .../aam-theme/email/messages/messages_en.properties | 5 ++++- keycloak/aam-theme/email/text/code-email.ftl | 2 ++ keycloak/aam-theme/email/text/executeActions.ftl | 5 +---- keycloak/realm_config.json | 12 ++++++------ 6 files changed, 18 insertions(+), 17 deletions(-) diff --git a/keycloak/aam-theme/email/html/code-email.ftl b/keycloak/aam-theme/email/html/code-email.ftl index 7945037..aa75a53 100644 --- a/keycloak/aam-theme/email/html/code-email.ftl +++ b/keycloak/aam-theme/email/html/code-email.ftl @@ -1,5 +1,8 @@ -${kcSanitize(msg("emailCodeBody", code, ttl))} +

Aam Digital - ${realmName}

+${kcSanitize(msg("emailCodeBodyHtml", ttl))} +

${code}

+${kcSanitize(msg("emailFooterHtml"))?no_esc} diff --git a/keycloak/aam-theme/email/html/executeActions.ftl b/keycloak/aam-theme/email/html/executeActions.ftl index 78f3b48..8c913d2 100644 --- a/keycloak/aam-theme/email/html/executeActions.ftl +++ b/keycloak/aam-theme/email/html/executeActions.ftl @@ -14,10 +14,6 @@ ${kcSanitize(msg("passwordResetBodyHtml", link, user.username, realmName, linkEx <#else> ${kcSanitize(msg("executeActionsBodyHtml", link, linkExpiration, realmName, requiredActionsText, linkExpirationFormatter(linkExpiration)))?no_esc} -
-

If you have any problems or questions, don’t hesitate to get in touch with us at support@aam-digital.com.

-
-

Best regards,

-

Your Aam Digital Team

+${kcSanitize(msg("emailFooterHtml"))?no_esc} diff --git a/keycloak/aam-theme/email/messages/messages_en.properties b/keycloak/aam-theme/email/messages/messages_en.properties index 3e4ed55..661ed62 100644 --- a/keycloak/aam-theme/email/messages/messages_en.properties +++ b/keycloak/aam-theme/email/messages/messages_en.properties @@ -2,5 +2,8 @@ emailVerificationBody=Your email has been linked to the Aam Digital user: {1}. T emailVerificationBodyHtml=

Your email has been linked to the Aam Digital user: {1}. To verify your email, click the link below. After verifying your email, you will be forwarded to the Aam Digital application.

Verify email

This link will expire within {3}.

Please keep in mind that your account gives access to personal information of your project''s participants that should be handled with care. Don''t share your access with anyone.

After verifying your email, you can open the Application with the link below.

Open Aam Digital

passwordResetBody=Someone just requested to change the password for your Aam Digital account with the name: {1}. If this was you, click on the link below to reset it.\n\n{0}\n\nThis link and code will expire within {3}.\n\nIf you don''t want to reset your password, just ignore this message and nothing will be changed. passwordResetBodyHtml=

Someone just requested to change the password for your Aam Digital account with the name: {1}. If this was you, click on the link below to reset it.

Reset password

This link will expire within {3}.

If you don''t want to reset your password, just ignore this message and nothing will be changed.

+emailFooter=\n\nIf you have any problems or questions, don''t hesitate to get in touch with us at support@aam-digital.com .\n\n Best regards, \n\nYour Aam Digital Team +emailFooterHtml=

If you have any problems or questions, don''t hesitate to get in touch with us at support@aam-digital.com.


Best regards,

Your Aam Digital Team

emailCodeSubject={0} access code -emailCodeBody=Access code: {0}. \n\nThis code will expire within {1} seconds. +emailCodeBody=Access Code: {0} \n\nThis code will expire within {1} seconds. +emailCodeBodyHtml=Enter the code below. \n\nThis code will expire within {0} seconds. diff --git a/keycloak/aam-theme/email/text/code-email.ftl b/keycloak/aam-theme/email/text/code-email.ftl index 3240f6e..f0c0c2b 100644 --- a/keycloak/aam-theme/email/text/code-email.ftl +++ b/keycloak/aam-theme/email/text/code-email.ftl @@ -1,2 +1,4 @@ <#ftl output_format="plainText"> +Aam Digital - ${realmName}\n\n ${msg("emailCodeBody", code, ttl)} +${msg("emailFooter")} diff --git a/keycloak/aam-theme/email/text/executeActions.ftl b/keycloak/aam-theme/email/text/executeActions.ftl index 9331021..88500fe 100644 --- a/keycloak/aam-theme/email/text/executeActions.ftl +++ b/keycloak/aam-theme/email/text/executeActions.ftl @@ -10,7 +10,4 @@ ${msg("passwordResetBody",link, user.username, linkExpirationFormatter(linkExpir <#else> ${msg("executeActionsBody",link, linkExpiration, realmName, requiredActionsText, linkExpirationFormatter(linkExpiration))} -\n\n -If you have any problems or questions, don’t hesitate to get in touch with us at support@aam-digital.com .\n\n - Best regards,\n\n -Your Aam Digital Team +${msg("emailFooter")} diff --git a/keycloak/realm_config.json b/keycloak/realm_config.json index 8c2bdc4..d994cbd 100644 --- a/keycloak/realm_config.json +++ b/keycloak/realm_config.json @@ -16,12 +16,12 @@ "ssl": "false", "replyTo": "", "replyToDisplayName": "", - "from": "accounts@aam-digital.com", - "fromDisplayName": "Aam Digital", - "host": "w01b1893.kasserver.com", - "port": "587", - "user": "accounts@aam-digital.com", - "password": "Bx2*4EdhVe@@" + "from": "", + "fromDisplayName": "", + "host": "", + "port": "", + "user": "", + "password": "" }, "eventsListeners": [ "metrics-listener",