diff --git a/CHANGELOG.md b/CHANGELOG.md index 30dcaaaa1..58d48ddcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,28 +3,32 @@ For documentation on how to update this changelog, please see [changelog_updates.md](docs/dev/changelog_updates.md). -## Unreleased - YYYY-MM-DD +## [v4.1.5] - 2025-01-31 ### Overview -### Detailed Changes - -#### Major +Keycloak 26 compatibility update -#### Minor +### Detailed Changes #### Patch +- Updated backend framework for Keycloak 26 compatibility + ### Known issues ### Deployment Migration Notes +- To maintain compatibility, update **Keycloak** to version **26.0.7** and **oauth2-proxy** to **7.7.1** + - If you encounter issues keeping the user session alive, configure your auth proxy to either no longer require a nonce in the access token or add the legacy nonce mapper to your oauth-proxy client. Consult the Keycloak documentation for more information. + #### Compatible Versions -- Authority Portal Backend Docker Image: `ghcr.io/sovity/authority-portal-backend:{{ version }}` -- Authority Portal Frontend Docker Image: `ghcr.io/sovity/authority-portal-frontend:{{ version }}` -- Catalog Crawler CE: `ghcr.io/sovity/authority-portal-crawler:{{ version }}` -- Sovity EDC CE: {{ CE Release Link }} +- Authority Portal Backend Docker Image: `ghcr.io/sovity/authority-portal-ee-backend:4.1.5` +- Authority Portal Frontend Docker Image: `ghcr.io/sovity/authority-portal-ee-frontend:4.1.5` +- Catalog Crawler CE: `ghcr.io/sovity/authority-portal-ee-crawler:4.1.5` +- sovity EDC CE: [`v10.5.0`](https://github.com/sovity/edc-ce/releases/tag/v10.5.0) +- Keycloak: 26.0.7 ## [v4.1.4] - 2024-12-13 @@ -32,14 +36,6 @@ please see [changelog_updates.md](docs/dev/changelog_updates.md). ### Detailed Changes -#### Major - -#### Minor - -#### Patch - -### Known issues - ### Deployment Migration Notes - Deploy a Catalog Crawler with version `10.5.0`. Previous versions are not compatible with this release. diff --git a/authority-portal-backend/authority-portal-quarkus/build.gradle.kts b/authority-portal-backend/authority-portal-quarkus/build.gradle.kts index f72d96331..1f5a8d7ba 100644 --- a/authority-portal-backend/authority-portal-quarkus/build.gradle.kts +++ b/authority-portal-backend/authority-portal-quarkus/build.gradle.kts @@ -33,20 +33,20 @@ dependencies { implementation("io.quarkus:quarkus-logging-json") implementation("io.quarkus:quarkus-opentelemetry") implementation("io.quarkus:quarkus-micrometer") - implementation("io.quarkus:quarkus-resteasy-reactive") - implementation("io.quarkus:quarkus-resteasy-reactive-jackson") + implementation("io.quarkus:quarkus-rest") + implementation("io.quarkus:quarkus-rest-jackson") implementation("io.quarkus:quarkus-smallrye-context-propagation") implementation("io.quarkus:quarkus-smallrye-openapi") implementation("io.quarkus:quarkus-smallrye-health") - implementation("io.quarkus:quarkus-oidc-client-reactive-filter") + implementation("io.quarkus:quarkus-rest-client-oidc-filter") implementation("io.quarkus:quarkus-hibernate-validator") - implementation("io.quarkus:quarkus-resteasy-reactive-jackson") + implementation("io.quarkus:quarkus-rest-jackson") + implementation("io.quarkus:quarkus-keycloak-admin-rest-client") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("io.opentelemetry.instrumentation:opentelemetry-jdbc") implementation("org.bouncycastle:bcprov-jdk18on:1.77") implementation("org.bouncycastle:bcpkix-jdk18on:1.77") implementation("com.opencsv:opencsv:5.9") - implementation(libs.quarkus.keycloakAdminClientReactive) implementation(libs.quarkus.jooq) implementation(libs.commons.lang3) implementation(project(":authority-portal-api")) diff --git a/authority-portal-backend/authority-portal-quarkus/src/main/resources/application.properties b/authority-portal-backend/authority-portal-quarkus/src/main/resources/application.properties index 470688e82..0b491e3c8 100644 --- a/authority-portal-backend/authority-portal-quarkus/src/main/resources/application.properties +++ b/authority-portal-backend/authority-portal-quarkus/src/main/resources/application.properties @@ -27,7 +27,7 @@ quarkus.oidc.enabled=true %dev.quarkus.keycloak.devservices.enabled=true %dev.quarkus.keycloak.devservices.port=8081 %dev.quarkus.keycloak.devservices.realm-path=realm.dev.json -%dev.quarkus.keycloak.devservices.image-name=quay.io/keycloak/keycloak:24.0.4 +%dev.quarkus.keycloak.devservices.image-name=quay.io/keycloak/keycloak:26.0.7 %dev.quarkus.keycloak.admin-client.server-url=http://localhost:8081 %dev.quarkus.keycloak.admin-client.realm=mds-portal diff --git a/authority-portal-backend/gradle/libs.versions.toml b/authority-portal-backend/gradle/libs.versions.toml index d62694a17..37344fc63 100644 --- a/authority-portal-backend/gradle/libs.versions.toml +++ b/authority-portal-backend/gradle/libs.versions.toml @@ -5,8 +5,7 @@ npmVersion = "8.15.0" sovity-edcCe = "10.5.0" -quarkus = "3.9.2" -quarkus-keycloakAdminClientReactive = "3.6.6" +quarkus = "3.18.1" quarkus-jooq = "2.0.0" jakarta-servletApi = "5.0.0" @@ -31,7 +30,6 @@ commons-lang = "3.14.0" sovity-edc-wrapperCommonApi = { module = "de.sovity.edc:wrapper-common-api", version.ref = "sovity-edcCe" } quarkus-universeBom = { module = "io.quarkus.platform:quarkus-bom", version.ref = "quarkus" } -quarkus-keycloakAdminClientReactive = { module = "io.quarkus:quarkus-keycloak-admin-client-reactive", version.ref = "quarkus-keycloakAdminClientReactive" } quarkus-jooq = { module = "io.quarkiverse.jooq:quarkus-jooq", version.ref = "quarkus-jooq" } jakarta-servletApi = { module = "jakarta.servlet:jakarta.servlet-api", version.ref = "jakarta-servletApi" } diff --git a/authority-portal-keycloak/mds-theme/login/login-config-totp.ftl b/authority-portal-keycloak/mds-theme/login/login-config-totp.ftl index 7d8378887..2983f4aee 100755 --- a/authority-portal-keycloak/mds-theme/login/login-config-totp.ftl +++ b/authority-portal-keycloak/mds-theme/login/login-config-totp.ftl @@ -51,8 +51,9 @@
-
- * +
+ + *
<#if messagesPerField.existsError('totp')> - - ${kcSanitize(messagesPerField.get('totp'))?no_esc} - + + ${kcSanitize(messagesPerField.get('totp'))?no_esc} + - +
<#if mode??> diff --git a/authority-portal-keycloak/mds-theme/login/login-update-password.ftl b/authority-portal-keycloak/mds-theme/login/login-update-password.ftl new file mode 100644 index 000000000..94458d550 --- /dev/null +++ b/authority-portal-keycloak/mds-theme/login/login-update-password.ftl @@ -0,0 +1,54 @@ +<#import "template.ftl" as layout> +<#import "password-commons.ftl" as passwordCommons> +<@layout.registrationLayout displayMessage=!messagesPerField.existsError('password','password-confirm'); section> + <#if section = "header"> + ${msg("updatePasswordTitle")} + <#elseif section = "form"> + +
+ +
+ + <#if messagesPerField.existsError('password')> + + ${kcSanitize(messagesPerField.get('password'))?no_esc} + + + +
+ +
+ + <#if messagesPerField.existsError('password-confirm')> + + ${kcSanitize(messagesPerField.get('password-confirm'))?no_esc} + + + +
+ <@passwordCommons.logoutOtherSessions/> + +
+ <#if isAppInitiatedAction??> + + + <#else> + + +
+
+ + + \ No newline at end of file diff --git a/authority-portal-keycloak/mds-theme/login/resources/css/login.css b/authority-portal-keycloak/mds-theme/login/resources/css/login.css index 6e440084b..ec530b7b3 100644 --- a/authority-portal-keycloak/mds-theme/login/resources/css/login.css +++ b/authority-portal-keycloak/mds-theme/login/resources/css/login.css @@ -33,8 +33,9 @@ a:hover { flex-direction: column; justify-content: center; align-items: center; - width: 100vw; height: 100vh; + font-size: 12px; + line-height: 20px; } /* default - IE compatibility */ @@ -104,7 +105,7 @@ h1#kc-page-title { } #kc-content { - width: 35rem; + width: 100%; } #kc-attempted-username { @@ -125,7 +126,12 @@ h1#kc-page-title { } #kc-info-wrapper { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; font-size: 13px; + margin-top: 30px; } #kc-form-options span { @@ -200,14 +206,13 @@ ul#kc-totp-supported-apps { .card-pff { margin: 0 auto; padding: 10px 20px !important; - max-width: 500px; + max-width: 350px; border-radius: 25px; max-height: calc(100vh - 100px); - overflow-y: auto; } .login-pf-page .login-pf-signup { - font-size: 15px; + font-size: 12px; color: #72767b; } #kc-content-wrapper .row { @@ -249,10 +254,16 @@ ul#kc-totp-supported-apps { } .form-group { - align-items: center; - justify-content: center; + display: flex; + flex-direction: column; color: black; margin-bottom: 0; + column-gap: 8px; + margin: 2px 20px; +} + +.form-group input { + margin: 3px 0px; } .no-bottom-margin { @@ -284,7 +295,6 @@ ul#kc-totp-supported-apps { } .text-input { - width: 100%; border: 1px solid #474747; margin: 10px auto; color: rgb(0, 0, 0); @@ -292,6 +302,9 @@ ul#kc-totp-supported-apps { text-align: center; border-radius: 0.5rem; padding: 1.5rem; + width: 100%; + max-width: 350px; + height: 5px; } #kc-logout-confirm { @@ -312,22 +325,25 @@ ul#kc-totp-supported-apps { background-repeat: no-repeat; background-position: top; height: 80px; + width: 350px; max-width: 350px; background-size: 63%; } div.form-group.login-pf-settings { display: flex; + flex-direction: row; align-items: center; justify-content: space-between; - padding: 0 25px; margin-right: 0px !important; + width: 306px; } .col-xs-12.col-sm-12.col-md-12.col-lg-12 { position: relative; + display: flex; + flex-direction: column; justify-content: center; - align-items: center; min-height: 1px; } @@ -335,6 +351,13 @@ div.form-group.login-pf-settings { color: black; } +.form-group-row { + display: flex; + flex-direction: row !important; + justify-content: start; + align-items: start; +} + .pf-c-button.pf-m-primary.pf-m-block.btn-lg { margin-top: 10px !important; margin-bottom: 10px !important; @@ -401,7 +424,7 @@ div.form-group.login-pf-settings { margin: 0 10px 0 6px; } -.kc-login-tooltip { +#kc-login-tooltip { display: flex; justify-content: center; } @@ -418,5 +441,91 @@ div.form-group.login-pf-settings { .legal-notices { display: flex; + column-gap: 5px; + justify-content: space-between; + align-items: center; +} + +button { + min-width: 16px; + min-height: 16px; +} + +/* Keycloak 26 */ +/* sorry for the styles, but it's the only way to make it work +without refactoring the whole Keycloak theme */ + +body { + font-size: 12px; + line-height: 1.66666667; + color: #363636; +} + +.alert-warning { + color: #363636; + background-color: #fdf2e5; + border-color: #ec7a08; +} + +#kc-totp-settings-form { + display: flex; + flex-direction: column; + align-items: start; + justify-content: center; +} + +.formContainer .form-group { + display: flex; + flex-direction: column; + align-items: start; justify-content: center; + font-weight: bold; +} + +.form-group input { + line-height: 20px; + border-radius: 3px; + border: 1px solid black; +} + +#rememberMe { + width: 20px !important; +} + +#kc-form-login .text-input { + width: 260px; +} + +.legal-notices p { + margin: 0; +} + +#kc-login { + width: auto; } + +#kc-form-buttons { + align-items: center; +} + +#kc-reset-password-form .form-group { + align-items: normal; +} + +#username { + width: 256px; +} + +#otp { + width: 260px; +} + +#password-new, +#password-confirm { + width: 260px; +} + +#reset-login { + display: flex; + justify-content: center; +} \ No newline at end of file diff --git a/authority-portal-keycloak/mds-theme/login/theme.properties b/authority-portal-keycloak/mds-theme/login/theme.properties index eb16e7558..5f5e99e59 100644 --- a/authority-portal-keycloak/mds-theme/login/theme.properties +++ b/authority-portal-keycloak/mds-theme/login/theme.properties @@ -44,6 +44,7 @@ kcFormSocialAccountGridItem=pf-l-grid__item kcFormSocialAccountNameClass=kc-social-provider-name kcFormSocialAccountLinkClass=pf-c-login__main-footer-links-item-link kcFormSocialAccountSectionClass=kc-social-section kc-social-gray +# logo kcFormHeaderClass=login-pf-header kcFeedbackErrorIcon=fa fa-fw fa-exclamation-circle diff --git a/authority-portal-keycloak/sovity-theme/login/login-config-totp.ftl b/authority-portal-keycloak/sovity-theme/login/login-config-totp.ftl index 7d8378887..2983f4aee 100755 --- a/authority-portal-keycloak/sovity-theme/login/login-config-totp.ftl +++ b/authority-portal-keycloak/sovity-theme/login/login-config-totp.ftl @@ -51,8 +51,9 @@
-
- * +
+ + *
<#if messagesPerField.existsError('totp')> - - ${kcSanitize(messagesPerField.get('totp'))?no_esc} - + + ${kcSanitize(messagesPerField.get('totp'))?no_esc} + - +
<#if mode??> diff --git a/authority-portal-keycloak/sovity-theme/login/login-update-password.ftl b/authority-portal-keycloak/sovity-theme/login/login-update-password.ftl new file mode 100644 index 000000000..94458d550 --- /dev/null +++ b/authority-portal-keycloak/sovity-theme/login/login-update-password.ftl @@ -0,0 +1,54 @@ +<#import "template.ftl" as layout> +<#import "password-commons.ftl" as passwordCommons> +<@layout.registrationLayout displayMessage=!messagesPerField.existsError('password','password-confirm'); section> + <#if section = "header"> + ${msg("updatePasswordTitle")} + <#elseif section = "form"> + +
+ +
+ + <#if messagesPerField.existsError('password')> + + ${kcSanitize(messagesPerField.get('password'))?no_esc} + + + +
+ +
+ + <#if messagesPerField.existsError('password-confirm')> + + ${kcSanitize(messagesPerField.get('password-confirm'))?no_esc} + + + +
+ <@passwordCommons.logoutOtherSessions/> + +
+ <#if isAppInitiatedAction??> + + + <#else> + + +
+
+ + + \ No newline at end of file diff --git a/authority-portal-keycloak/sovity-theme/login/password-commons.ftl b/authority-portal-keycloak/sovity-theme/login/password-commons.ftl new file mode 100644 index 000000000..ce8aeab1f --- /dev/null +++ b/authority-portal-keycloak/sovity-theme/login/password-commons.ftl @@ -0,0 +1,12 @@ +<#macro logoutOtherSessions> +
+
+
+ +
+
+
+ \ No newline at end of file diff --git a/authority-portal-keycloak/sovity-theme/login/resources/css/login.css b/authority-portal-keycloak/sovity-theme/login/resources/css/login.css index d9cf9101d..cf8d2b1a5 100644 --- a/authority-portal-keycloak/sovity-theme/login/resources/css/login.css +++ b/authority-portal-keycloak/sovity-theme/login/resources/css/login.css @@ -57,6 +57,25 @@ a:hover { color: rgb(93 169 255) !important; } +.cancel-button { + display: block; + background-color: white !important; + color: black; + text-transform: uppercase; + border-radius: 0.25rem; + line-height: 1; + height: 2.5em; + margin: 1rem auto 0; + padding: 0 5em 0 5em; + border: none; + cursor: pointer; + transition: all 0.2s ease-in-out; +} + +.cancel-button:hover { + color: rgb(93 169 255) !important; +} + /* default - IE compatibility */ .pf-c-button.pf-m-control { border: solid 1px; @@ -104,7 +123,7 @@ h1#kc-page-title { } #kc-content { - width: 35rem; + width: 100%; } #kc-attempted-username { @@ -125,7 +144,12 @@ h1#kc-page-title { } #kc-info-wrapper { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; font-size: 13px; + margin-top: 30px; } #kc-form-options span { @@ -200,14 +224,13 @@ ul#kc-totp-supported-apps { .card-pff { margin: 0 auto; padding: 10px 20px !important; - max-width: 500px; + max-width: 350px; border-radius: 25px; max-height: calc(100vh - 100px); - overflow-y: auto; } .login-pf-page .login-pf-signup { - font-size: 15px; + font-size: 12px; color: #72767b; } #kc-content-wrapper .row { @@ -249,10 +272,16 @@ ul#kc-totp-supported-apps { } .form-group { - align-items: center; - justify-content: center; + display: flex; + flex-direction: column; color: black; margin-bottom: 0; + column-gap: 8px; + margin: 2px 20px; +} + +.form-group input { + margin: 3px 0px; } .no-bottom-margin { @@ -284,7 +313,6 @@ ul#kc-totp-supported-apps { } .text-input { - width: 100%; border: 1px solid #474747; margin: 10px auto; color: rgb(0, 0, 0); @@ -292,6 +320,9 @@ ul#kc-totp-supported-apps { text-align: center; border-radius: 0.5rem; padding: 1.5rem; + width: 100%; + max-width: 350px; + height: 5px; } #kc-logout-confirm { @@ -311,23 +342,26 @@ ul#kc-totp-supported-apps { background-image: url(../img/sovity_logo.svg); background-repeat: no-repeat; background-position: top; - height: 110px; - max-width: 400px; + height: 80px; + width: 350px; + max-width: 350px; background-size: 63%; } div.form-group.login-pf-settings { display: flex; + flex-direction: row; align-items: center; justify-content: space-between; - padding: 0 25px; margin-right: 0px !important; + width: 306px; } .col-xs-12.col-sm-12.col-md-12.col-lg-12 { position: relative; + display: flex; + flex-direction: column; justify-content: center; - align-items: center; min-height: 1px; } @@ -335,10 +369,17 @@ div.form-group.login-pf-settings { color: black; } +.form-group-row { + display: flex; + flex-direction: row !important; + justify-content: start; + align-items: start; +} + .pf-c-button.pf-m-primary.pf-m-block.btn-lg { margin-top: 10px !important; margin-bottom: 10px !important; - max-width: 211px; + width: 211px; height: 40px; background-color: black; color: white; @@ -347,6 +388,16 @@ div.form-group.login-pf-settings { line-height: 17px; } +.pf-c-button.cancel-button.pf-m-block.btn-lg { + margin-top: 10px !important; + margin-bottom: 10px !important; + width: 200px; + height: 40px; + font-weight: 600; + font-size: 14px; + line-height: 17px; +} + .kc-registration-container.a:link { color: white !important; } @@ -401,7 +452,7 @@ div.form-group.login-pf-settings { margin: 0 10px 0 6px; } -.kc-login-tooltip { +#kc-login-tooltip { display: flex; justify-content: center; } @@ -418,5 +469,91 @@ div.form-group.login-pf-settings { .legal-notices { display: flex; + column-gap: 5px; + justify-content: space-between; + align-items: center; +} + +button { + min-width: 16px; + min-height: 16px; +} + +/* Keycloak 26 */ +/* sorry for the styles, but it's the only way to make it work + without refactoring the whole Keycloak theme */ + +body { + font-size: 12px; + line-height: 1.66666667; + color: #363636; +} + +.alert-warning { + color: #363636; + background-color: #fdf2e5; + border-color: #ec7a08; +} + +#kc-totp-settings-form { + display: flex; + flex-direction: column; + align-items: start; justify-content: center; } + +.formContainer .form-group { + display: flex; + flex-direction: column; + align-items: start; + justify-content: center; + font-weight: bold; +} + +.form-group input { + line-height: 20px; + border-radius: 3px; + border: 1px solid black; +} + +#rememberMe { + width: 20px !important; +} + +#kc-form-login .text-input { + width: 260px; +} + +.legal-notices p { + margin: 0; +} + +#kc-login { + width: auto; +} + +#kc-form-buttons { + align-items: center; +} + +#kc-reset-password-form .form-group { + align-items: normal; +} + +#username { + width: 256px; +} + +#otp { + width: 260px; +} + +#password-new, +#password-confirm { + width: 260px; +} + +#reset-login { + display: flex; + justify-content: center; +} \ No newline at end of file diff --git a/authority-portal-keycloak/sovity-theme/login/theme.properties b/authority-portal-keycloak/sovity-theme/login/theme.properties index eb16e7558..e4b0abc93 100644 --- a/authority-portal-keycloak/sovity-theme/login/theme.properties +++ b/authority-portal-keycloak/sovity-theme/login/theme.properties @@ -76,7 +76,8 @@ kcInfoAreaClass=col-xs-12 col-sm-4 col-md-4 col-lg-5 details kcButtonClass=pf-c-button # classes defining priority of the button - primary or default (there is typically only one priority button for the form) kcButtonPrimaryClass=pf-m-primary -kcButtonDefaultClass=btn-default +kcButtonCancelClass=cancel-button +kcButtonDefaultClass=pf-c-button # classes defining size of the button kcButtonLargeClass=btn-lg kcButtonBlockClass=pf-m-block