From 2db38f021a2e6a9b29ab6bc4df4a8828bb0548f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Tue, 2 Jun 2026 11:08:28 +0200 Subject: [PATCH 01/14] build/local: pin Java 17 in deploy script and align Keycloak to 26.5.3 The local deploy script (run-local-postgres-cicd.sh) failed under a Java 11 shell default because the provider targets Java 17. Add an ensure_java17 step that auto-selects an installed JDK 17+ before the Maven build, with a clear error if none is found. Also compile the provider against the same Keycloak version the image runs by passing -Dversion.keycloak from .env (KEYCLOAK_VERSION), and bump every stale 26.5.1 reference (pom default + docs/comments) to 26.5.3 for consistency. --- development/README.md | 4 +- development/docker/Dockerfile | 2 +- .../docs/themed-keycloak-design-flow.md | 6 +-- development/run-local-postgres-cicd.sh | 48 ++++++++++++++++++- pom.xml | 2 +- 5 files changed, 54 insertions(+), 8 deletions(-) diff --git a/development/README.md b/development/README.md index 3ae0cd6..e9968fd 100644 --- a/development/README.md +++ b/development/README.md @@ -92,9 +92,9 @@ docker build --no-cache --build-arg THEMED=true -t obp-keycloak:themed -f develo The unified Dockerfile accepts several build-time arguments (passed with `--build-arg`). The provider JAR must be pre-built on the host before running `docker build` (the deployment script handles this automatically). -- `KEYCLOAK_VERSION` (default: `26.5.1`) — the Keycloak base image tag used in the builder and final images. Example: +- `KEYCLOAK_VERSION` (default: `26.5.3`) — the Keycloak base image tag used in the builder and final images. Example: ```bash ---build-arg KEYCLOAK_VERSION=26.5.1 +--build-arg KEYCLOAK_VERSION=26.5.3 ``` - `THEMED` (default: `false`) — controls whether the Dockerfile retains the `themes/obp` and `themes/obp-dark` directories in the final image. Set to `true` to keep themes in the image (the deployment script passes this when `--themed` is used): diff --git a/development/docker/Dockerfile b/development/docker/Dockerfile index 808caed..bcbc41a 100644 --- a/development/docker/Dockerfile +++ b/development/docker/Dockerfile @@ -1,7 +1,7 @@ # Development Dockerfile for OBP Keycloak Provider # # Usage: -# docker build --build-arg KEYCLOAK_VERSION=26.5.1 -t obp-keycloak:latest . +# docker build --build-arg KEYCLOAK_VERSION=26.5.3 -t obp-keycloak:latest . # # Notes: # - The provider JAR must be pre-built on the host before running docker build diff --git a/development/docs/themed-keycloak-design-flow.md b/development/docs/themed-keycloak-design-flow.md index c95ea85..796ea57 100644 --- a/development/docs/themed-keycloak-design-flow.md +++ b/development/docs/themed-keycloak-design-flow.md @@ -13,7 +13,7 @@ This document describes the end-to-end process for building and running a locall | Host Machine | | Docker Container | | PostgreSQL (host) | | | | (obp-keycloak-local) | | | | .env | | +-------------------------+ | | keycloakdb | -| themes/obp/ | -----> | | Keycloak 26.5.1 | | <----> | (realm data, | +| themes/obp/ | -----> | | Keycloak 26.5.3 | | <----> | (realm data, | | themes/obp-dark/ | build | | + obp-keycloak- | | JDBC | clients, tokens) | | src/ + pom.xml | | | provider.jar | | +---------------------+ | | | | + obp theme | | @@ -122,7 +122,7 @@ docker build --no-cache \ #### Dockerfile Multi-Stage Build ``` - Stage 1: builder (quay.io/keycloak/keycloak:26.5.1) + Stage 1: builder (quay.io/keycloak/keycloak:26.5.3) +--------------------------------------------------+ | Generate self-signed SSL keystore | | COPY obp-keycloak-provider.jar -> providers/ | @@ -131,7 +131,7 @@ docker build --no-cache \ +--------------------------------------------------+ | v - Stage 2: final (quay.io/keycloak/keycloak:26.5.1) + Stage 2: final (quay.io/keycloak/keycloak:26.5.3) +--------------------------------------------------+ | COPY --from=builder /opt/keycloak/ | | COPY themes/obp/ -> themes/obp/ | diff --git a/development/run-local-postgres-cicd.sh b/development/run-local-postgres-cicd.sh index ff4501b..963ab50 100755 --- a/development/run-local-postgres-cicd.sh +++ b/development/run-local-postgres-cicd.sh @@ -174,7 +174,53 @@ echo -e "${GREEN}✓ Connectivity check done${NC}" # Step 3: Clean build echo -e "${CYAN}[3/8] Building Maven Project${NC}" -mvn clean package -DskipTests -q +# The provider targets Java 17 (see pom.xml maven.compiler.source/target). If the +# shell default is an older JDK, the build fails with "invalid target release: 17". +# Auto-select a Java 17 JDK unless the active java is already >= 17. +ensure_java17() { + local current_major="" + if command -v java &> /dev/null; then + # "openjdk version "17.0.1"" → 17, or "11.0.30" → 11 + current_major=$(java -version 2>&1 | sed -n 's/.*version "\([0-9]*\).*/\1/p' | head -1) + fi + + if [ -n "$current_major" ] && [ "$current_major" -ge 17 ] 2>/dev/null; then + return 0 + fi + + # Look for a Java 17+ JDK in common locations + local candidate + for candidate in \ + "$JAVA_HOME" \ + /usr/lib/jvm/java-17-openjdk-amd64 \ + /usr/lib/jvm/java-1.17.0-openjdk-amd64 \ + /usr/lib/jvm/java-21-openjdk-amd64 \ + /usr/lib/jvm/temurin-17-jdk-amd64 \ + /usr/lib/jvm/java-17-openjdk; do + if [ -n "$candidate" ] && [ -x "$candidate/bin/java" ]; then + local cand_major + cand_major=$("$candidate/bin/java" -version 2>&1 | sed -n 's/.*version "\([0-9]*\).*/\1/p' | head -1) + if [ -n "$cand_major" ] && [ "$cand_major" -ge 17 ] 2>/dev/null; then + export JAVA_HOME="$candidate" + export PATH="$candidate/bin:$PATH" + echo -e "${BLUE} Using Java $cand_major for the build: $candidate${NC}" + return 0 + fi + fi + done + + echo -e "${RED}✗ Java 17+ is required to build the provider, but none was found${NC}" + echo " Active java: ${current_major:-unknown}. Install a JDK 17 (e.g. apt install openjdk-17-jdk)" + echo " or set JAVA_HOME to a Java 17+ installation before running this script." + exit 1 +} + +ensure_java17 + +# Compile the provider against the same Keycloak version the image runs +# (KEYCLOAK_VERSION from .env), overriding the pom.xml default so the SPI +# matches the runtime exactly. +mvn clean package -DskipTests -q -Dversion.keycloak="$KEYCLOAK_VERSION" if [ $? -ne 0 ]; then echo -e "${RED}✗ Maven build failed${NC}" diff --git a/pom.xml b/pom.xml index 7a58270..10cb2e0 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ 17 - 26.5.1 + 26.5.3 3.5.1 3.1.0 3.0.0 From 53c4afd53fe061b84b2f40469b0d142855c0f778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Tue, 2 Jun 2026 11:56:43 +0200 Subject: [PATCH 02/14] fix(theme): declare parent=base on the obp login theme; fix update-profile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keycloak reads theme.properties per theme type (/login/theme.properties), not the top-level /theme.properties. The obp login theme had no parent declared, so nothing from the base theme resolved: the user-profile-commons.ftl import threw HTTP 500 on the VERIFY_PROFILE page, base message keys rendered as raw keys (firstName, lastName, error-user-attribute-required), and styles/CSS classes never applied. - themes/obp/login/theme.properties: add parent=base, styles, locales, i18n, branding and the kc*Class block (consolidated from the dead top-level file). - themes/obp/theme.properties: delete — Keycloak never read it; it only misled. - login-update-profile.ftl: render via the userProfileFormFields macro (prefills from the profile bean, drops the non-editable username field, marks required attributes) instead of legacy ${user.*} vars that KC26 no longer populates. - messages_en.properties: add firstName/lastName/doSubmit/doCancel and user profile validation keys (explicit; base now also provides them). - Repoint the deploy script's theme health check and the docs to the per-type theme.properties path. Verified end to end: admin login reaches VERIFY_PROFILE, the page renders 200 with correct labels and validation messages, and submitting the profile issues an auth code. --- development/README.md | 4 +- .../docs/themed-keycloak-design-flow.md | 4 +- development/run-local-postgres-cicd.sh | 2 +- docs/CICD_DEPLOYMENT.md | 2 +- themes/obp/login/login-update-profile.ftl | 74 +++--------------- .../obp/login/messages/messages_en.properties | 13 ++++ themes/obp/login/theme.properties | 71 ++++++++++++++++- themes/obp/theme.properties | 76 ------------------- 8 files changed, 98 insertions(+), 148 deletions(-) delete mode 100644 themes/obp/theme.properties diff --git a/development/README.md b/development/README.md index e9968fd..57a39a2 100644 --- a/development/README.md +++ b/development/README.md @@ -185,7 +185,7 @@ docker ps --filter name=obp-keycloak-local ## Themed Deployments ### Prerequisites -- `themes/obp/theme.properties` - Theme configuration +- `themes/obp/login/theme.properties` - Theme configuration (Keycloak reads the per-type file) - `themes/obp/login/login.ftl` - Login template - `themes/obp/login/template.ftl` - Base template - Optional: CSS, images, message files in `themes/obp/login/resources/` @@ -231,7 +231,7 @@ docker system prune -f find themes/obp -type f # Verify theme configuration -cat themes/obp/theme.properties +cat themes/obp/login/theme.properties # Try standard deployment first ./development/run-local-postgres-cicd.sh diff --git a/development/docs/themed-keycloak-design-flow.md b/development/docs/themed-keycloak-design-flow.md index 796ea57..22bf855 100644 --- a/development/docs/themed-keycloak-design-flow.md +++ b/development/docs/themed-keycloak-design-flow.md @@ -82,7 +82,7 @@ The deployment script executes an 8-step pipeline: - `OBP_AUTHUSER_PROVIDER` (mandatory provider filter) - **Themed-specific**: runs `validate_theme_files()` which verifies: - `themes/obp/` directory exists - - `themes/obp/theme.properties` contains `parent=base` and `styles=` + - `themes/obp/login/theme.properties` contains `parent=base` and `styles=` - `themes/obp/login/` exists with `login.ftl` and `template.ftl` - Optionally checks for CSS, images, and i18n message files @@ -162,7 +162,7 @@ The container is launched with: - Polls `https://:/health/ready` every 2 seconds, up to 120 seconds. - **Themed-specific** post-readiness checks: - Tests if theme resources are accessible at `/resources/obp/` - - Verifies theme files exist inside the container at `/opt/keycloak/themes/obp/theme.properties` + - Verifies theme files exist inside the container at `/opt/keycloak/themes/obp/login/theme.properties` --- diff --git a/development/run-local-postgres-cicd.sh b/development/run-local-postgres-cicd.sh index 963ab50..1449006 100755 --- a/development/run-local-postgres-cicd.sh +++ b/development/run-local-postgres-cicd.sh @@ -352,7 +352,7 @@ while [ $WAIT_COUNT -lt $MAX_WAIT ] && [ "$READY" = false ]; do echo -e "${GREEN}✓ Service is ready${NC}" echo -n "Verifying theme installation... " - if docker exec "$CONTAINER_NAME" ls /opt/keycloak/themes/obp/theme.properties > /dev/null 2>&1; then + if docker exec "$CONTAINER_NAME" ls /opt/keycloak/themes/obp/login/theme.properties > /dev/null 2>&1; then echo -e "${GREEN}✓ Theme files installed${NC}" else echo -e "${RED}✗ Theme files missing in container${NC}" diff --git a/docs/CICD_DEPLOYMENT.md b/docs/CICD_DEPLOYMENT.md index cb535a8..a412d84 100644 --- a/docs/CICD_DEPLOYMENT.md +++ b/docs/CICD_DEPLOYMENT.md @@ -78,7 +78,7 @@ The script follows an 8-step pipeline: ## Theme Validation (--themed flag) **Themed Deployment Requirements**: -- ✅ `themes/obp/theme.properties` with valid content +- ✅ `themes/obp/login/theme.properties` with valid content - ✅ `themes/obp/login/` directory structure - ✅ Required templates: `login.ftl`, `template.ftl` - ✅ Optional: CSS files, images, message files diff --git a/themes/obp/login/login-update-profile.ftl b/themes/obp/login/login-update-profile.ftl index 38c442b..2a0a4cb 100644 --- a/themes/obp/login/login-update-profile.ftl +++ b/themes/obp/login/login-update-profile.ftl @@ -1,73 +1,17 @@ <#import "template.ftl" as layout> -<@layout.registrationLayout displayMessage=!messagesPerField.existsError('username','email','firstName','lastName'); section> +<#import "user-profile-commons.ftl" as userProfileCommons> +<@layout.registrationLayout displayMessage=messagesPerField.exists('global') displayRequiredFields=true; section> <#if section = "header"> ${msg("loginProfileTitle")} <#elseif section = "form">
-
-
- -
-
- readonly/> - - <#if messagesPerField.existsError('username')> - - ${kcSanitize(messagesPerField.get('username'))?no_esc} - - -
-
- -
-
- -
-
- - - <#if messagesPerField.existsError('email')> - - ${kcSanitize(messagesPerField.get('email'))?no_esc} - - -
-
-
-
- -
-
- - - <#if messagesPerField.existsError('firstName')> - - ${kcSanitize(messagesPerField.get('firstName'))?no_esc} - - -
-
- -
-
- -
-
- - - <#if messagesPerField.existsError('lastName')> - - ${kcSanitize(messagesPerField.get('lastName'))?no_esc} - - -
-
+ <#-- Render fields from the declarative user profile (profile bean). This + prefills values from the user, respects editUsernameAllowed (the + username is shown read-only when editing is disabled), and marks + required attributes. Replaces the old hand-rolled fields that read + legacy ${user.*} variables no longer populated by Keycloak. --> + <@userProfileCommons.userProfileFormFields/>
@@ -78,7 +22,7 @@
<#if isAppInitiatedAction??> - + <#else> diff --git a/themes/obp/login/messages/messages_en.properties b/themes/obp/login/messages/messages_en.properties index ed6c878..c5869c8 100644 --- a/themes/obp/login/messages/messages_en.properties +++ b/themes/obp/login/messages/messages_en.properties @@ -22,6 +22,13 @@ loginTotpTitle=Mobile Authenticator Setup loginProfileTitle=Update Account Information loginTimeout=Your login attempt timed out. Login will start from the beginning. +# Update profile page (VERIFY_PROFILE required action) — field labels and buttons. +# Defined here because this theme's bundle does not inherit them from the base theme. +firstName=First name +lastName=Last name +doSubmit=Submit +doCancel=Cancel + # OAuth grant page oauthGrantTitle=Grant Access to {0} oauthGrantInformation=By granting access, you allow {0} to access your Open Bank Project account information. @@ -113,6 +120,12 @@ registerUsernameExists=Username already exists. registerEmailExists=Email already exists. registerPasswordConfirmNotMatch=Password confirmation doesn't match. +# User profile validation messages (declarative user profile / VERIFY_PROFILE) +error-user-attribute-required=Please specify this field. +error-invalid-blank=Please specify value. +error-invalid-email=Invalid email address. +error-invalid-length=Length must be between {1} and {2}. + # Generic error messages unexpectedErrorTitle=An unexpected error has occurred unexpectedErrorTitleHtml=An unexpected error has occurred diff --git a/themes/obp/login/theme.properties b/themes/obp/login/theme.properties index 674bdfc..9602f86 100644 --- a/themes/obp/login/theme.properties +++ b/themes/obp/login/theme.properties @@ -1,9 +1,78 @@ # OBP Login Theme Properties -# Inherits all structural config (parent, styles, locales) from ../theme.properties +# +# Keycloak reads theme.properties PER THEME TYPE — i.e. it loads this +# /login/theme.properties file. The top-level /theme.properties is +# NOT consulted, so parent/styles/locales/CSS classes must be declared here (an +# earlier version wrongly assumed they were inherited from ../theme.properties). +parent=base +styles=css/styles.css +locales=en,de,fr,es,it,pt,ja,zh-CN # Provider version — single source of truth is in pom.xml projectVersion=@project.version@ +# Internationalization +internationalizationEnabled=true +supportedLocales=en,de,fr,es,it,pt,ja,zh-CN + +# Branding assets +logo=img/obp_logo.png +favicon=img/favicon.png + +# CSS Properties - Keycloak CSS Classes +kcHtmlClass=login-pf +kcBodyClass= +kcLoginClass= +kcFormCardClass= +kcFormHeaderClass= +kcHeaderClass= +kcHeaderWrapperClass= +kcFormClass= +kcFormGroupClass=pf-c-form__group +kcFormGroupErrorClass=pf-c-form__group pf-m-error +kcLabelClass=pf-c-form__label-text +kcInputClass=pf-c-form-control +kcInputErrorClass=pf-c-form-control pf-m-error +kcInputGroupClass=pf-c-input-group +kcFormPasswordVisibilityButtonClass=pf-c-button pf-m-control +kcFormPasswordVisibilityIconShow=fas fa-eye +kcFormPasswordVisibilityIconHide=fas fa-eye-slash +kcButtonClass=pf-c-button +kcButtonPrimaryClass=pf-m-primary +kcButtonSecondaryClass=pf-m-secondary +kcButtonDefaultClass=pf-m-secondary +kcButtonLinkClass=pf-m-link +kcButtonBlockClass=pf-m-block +kcButtonLargeClass=pf-m-lg +kcAlertClass=pf-c-alert +kcSignUpClass= +kcInfoAreaWrapperClass= + +# Form styling +kcFormOptionsClass= +kcFormOptionsWrapperClass= +kcFormSettingClass= +kcFormSocialAccountSectionClass= +kcFormSocialAccountListClass= +kcFormSocialAccountListButtonClass=pf-c-button pf-m-secondary kc-social-provider-button +kcFormSocialAccountListGridClass= +kcFormSocialAccountGridItem= +kcFormSocialAccountNameClass= +kcCommonLogoIdP= + +# Alert/Message styling +kcFeedbackSuccessIcon=fas fa-check-circle +kcFeedbackWarningIcon=fas fa-exclamation-triangle +kcFeedbackErrorIcon=fas fa-times-circle +kcFeedbackInfoIcon=fas fa-info-circle +kcAlertTitleClass= + +# Theme metadata +name=OBP Keycloak Theme +displayName=Open Bank Project +version=1.0.0 +author=Open Bank Project / TESOBE GmbH + # Custom "Forgot Password?" link URL (overrides Keycloak's default reset credentials page) # Set via FORGOT_PASSWORD_URL environment variable at runtime, or edit directly here. # Leave empty to use Keycloak's built-in password reset flow. diff --git a/themes/obp/theme.properties b/themes/obp/theme.properties deleted file mode 100644 index 6f9f857..0000000 --- a/themes/obp/theme.properties +++ /dev/null @@ -1,76 +0,0 @@ -parent=base -styles=css/styles.css -locales=en,de,fr,es,it,pt,ja,zh-CN - -# CSS Properties - Keycloak CSS Classes -kcHtmlClass=login-pf -kcBodyClass= -kcLoginClass= -kcFormCardClass= -kcFormHeaderClass= -kcHeaderClass= -kcHeaderWrapperClass= -kcFormClass= -kcFormGroupClass=pf-c-form__group -kcFormGroupErrorClass=pf-c-form__group pf-m-error -kcLabelClass=pf-c-form__label-text -kcInputClass=pf-c-form-control -kcInputErrorClass=pf-c-form-control pf-m-error -kcInputGroupClass=pf-c-input-group -kcFormPasswordVisibilityButtonClass=pf-c-button pf-m-control -kcFormPasswordVisibilityIconShow=fas fa-eye -kcFormPasswordVisibilityIconHide=fas fa-eye-slash -kcButtonClass=pf-c-button -kcButtonPrimaryClass=pf-m-primary -kcButtonSecondaryClass=pf-m-secondary -kcButtonLinkClass=pf-m-link -kcButtonBlockClass=pf-m-block -kcButtonLargeClass=pf-m-lg -kcAlertClass=pf-c-alert -kcSignUpClass= -kcInfoAreaWrapperClass= - -# Form styling -kcFormOptionsClass= -kcFormOptionsWrapperClass= -kcFormSettingClass= -kcFormSocialAccountSectionClass= -kcFormSocialAccountListClass= -kcFormSocialAccountListButtonClass=pf-c-button pf-m-secondary kc-social-provider-button -kcFormSocialAccountListGridClass= -kcFormSocialAccountGridItem= -kcFormSocialAccountNameClass= -kcCommonLogoIdP= - -# Alert/Message styling -kcFeedbackSuccessIcon=fas fa-check-circle -kcFeedbackWarningIcon=fas fa-exclamation-triangle -kcFeedbackErrorIcon=fas fa-times-circle -kcFeedbackInfoIcon=fas fa-info-circle -kcAlertTitleClass= - -# OBP Theme Configuration -# Based on Open Bank Project Portal design system - -# Theme metadata -name=OBP Keycloak Theme -displayName=Open Bank Project -version=1.0.0 -author=Open Bank Project / TESOBE GmbH - -# Internationalization support -internationalizationEnabled=true -supportedLocales=en,de,fr,es,it,pt,ja,zh-CN - -# Custom properties for OBP branding -logo=img/obp_logo.png -favicon=img/favicon.png - -# Custom "Forgot Password?" link URL (overrides Keycloak's default reset credentials page) -# Set via FORGOT_PASSWORD_URL environment variable at runtime, or edit directly here. -# Leave empty to use Keycloak's built-in password reset flow. -forgotPasswordUrl= - -# OBP Auth User Provider name, displayed on the login page. -# Set via OBP_AUTHUSER_PROVIDER environment variable at runtime. -obpAuthUserProvider= From 07c0be90abc533b8dfa6467ee39480952067d4f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Tue, 2 Jun 2026 12:09:36 +0200 Subject: [PATCH 03/14] i18n(theme): add de/fr/es/it/pt/ja/zh-CN login message bundles The obp login theme advertised 8 locales but shipped only messages_en. With parent=base now resolving standard keys, OBP-custom keys (obpWelcome, branded titles, etc.) still rendered as raw keys in non-English locales. Add full translated bundles mirroring messages_en.properties for all advertised locales (zh-CN kept as declared, file messages_zh_CN.properties). Each bundle has identical key parity with en (178 keys), preserves placeholders ({0}/{1}/{2}), tags, and proper nouns (Open Bank Project, TESOBE, Keycloak). Translations are machine-generated and should be reviewed by native speakers before production use. --- .../obp/login/messages/messages_de.properties | 227 ++++++++++++++++++ .../obp/login/messages/messages_es.properties | 227 ++++++++++++++++++ .../obp/login/messages/messages_fr.properties | 227 ++++++++++++++++++ .../obp/login/messages/messages_it.properties | 227 ++++++++++++++++++ .../obp/login/messages/messages_ja.properties | 227 ++++++++++++++++++ .../obp/login/messages/messages_pt.properties | 227 ++++++++++++++++++ .../login/messages/messages_zh_CN.properties | 227 ++++++++++++++++++ 7 files changed, 1589 insertions(+) create mode 100644 themes/obp/login/messages/messages_de.properties create mode 100644 themes/obp/login/messages/messages_es.properties create mode 100644 themes/obp/login/messages/messages_fr.properties create mode 100644 themes/obp/login/messages/messages_it.properties create mode 100644 themes/obp/login/messages/messages_ja.properties create mode 100644 themes/obp/login/messages/messages_pt.properties create mode 100644 themes/obp/login/messages/messages_zh_CN.properties diff --git a/themes/obp/login/messages/messages_de.properties b/themes/obp/login/messages/messages_de.properties new file mode 100644 index 0000000..b0cf486 --- /dev/null +++ b/themes/obp/login/messages/messages_de.properties @@ -0,0 +1,227 @@ +# OBP Keycloak Theme - English Messages +# Open Bank Project branding and improved user experience + +# Login page +loginTitle=Bei Open Bank Project anmelden +loginTitleHtml=Bei Open Bank Project anmelden +usernameOrEmail=Benutzername oder E-Mail +username=Benutzername +email=E-Mail +password=Passwort +loginUsername=Benutzername oder E-Mail +loginPassword=Passwort +loginRememberMe=Angemeldet bleiben +doLogIn=Anmelden +loginSubmit=Anmelden +doForgotPassword=Passwort vergessen? +loginForgotPassword=Passwort vergessen? +loginNoAccount=Neuer Benutzer? +doRegister=Konto erstellen +loginRegister=Konto erstellen +loginTotpTitle=Einrichtung des mobilen Authentifikators +loginProfileTitle=Kontoinformationen aktualisieren +loginTimeout=Ihr Anmeldeversuch ist abgelaufen. Die Anmeldung beginnt von vorne. + +# Update profile page (VERIFY_PROFILE required action) — field labels and buttons. +# Defined here because this theme's bundle does not inherit them from the base theme. +firstName=Vorname +lastName=Nachname +doSubmit=Absenden +doCancel=Abbrechen + +# OAuth grant page +oauthGrantTitle=Zugriff auf {0} gewähren +oauthGrantInformation=Indem Sie den Zugriff gewähren, erlauben Sie {0}, auf Ihre Kontoinformationen bei Open Bank Project zuzugreifen. + +# Registration page +registerTitle=Für Open Bank Project registrieren +registerSubmit=Registrieren +registerWithTitle=Oder registrieren mit +registerUsername=Benutzername +registerEmail=E-Mail +registerFirstName=Vorname +registerLastName=Nachname +registerPassword=Passwort +registerPasswordConfirm=Passwort bestätigen +registerAlreadyHaveAccount=Sie haben bereits ein Konto? +registerBackToLogin=« Zurück zur Anmeldung + +# Password reset +resetPasswordTitle=Passwort vergessen? +resetPasswordInstruction=Geben Sie Ihren Benutzernamen oder Ihre E-Mail-Adresse ein, und wir senden Ihnen Anweisungen, wie Sie ein neues Passwort erstellen können. +resetPasswordSubmit=Absenden +resetPasswordBackToLogin=« Zurück zur Anmeldung + +# Update password +updatePasswordTitle=Passwort aktualisieren +updatePasswordInstruction=Bitte erstellen Sie ein neues Passwort für Ihr Open Bank Project-Konto. +updatePasswordNewPassword=Neues Passwort +updatePasswordConfirmPassword=Neues Passwort bestätigen +updatePasswordSubmit=Absenden + +# Verify email +verifyEmailTitle=E-Mail-Verifizierung +verifyEmailInstruction=Eine E-Mail mit Anweisungen zur Verifizierung Ihrer E-Mail-Adresse wurde an Sie gesendet. +verifyEmailInstructionHtml=Eine E-Mail mit Anweisungen zur Verifizierung Ihrer E-Mail-Adresse wurde an {0} gesendet. +verifyEmailNoReceived=Sie haben keinen Verifizierungscode in Ihrer E-Mail erhalten? +verifyEmailResendInstruction=Klicken Sie auf den untenstehenden Link, um die E-Mail erneut zu senden. +verifyEmailResend=E-Mail erneut senden + +# Terms and conditions +termsTitle=Allgemeine Geschäftsbedingungen +termsText=Allgemeine Geschäftsbedingungen für Open Bank Project müssen noch festgelegt werden. +termsPlainText=Allgemeine Geschäftsbedingungen für Open Bank Project müssen noch festgelegt werden. +acceptTerms=Ich akzeptiere die Allgemeinen Geschäftsbedingungen + +# Error messages +invalidUserMessage=Ungültiger Benutzername oder ungültiges Passwort. +invalidUsernameMessage=Ungültiger Benutzername. +invalidUsernameOrEmailMessage=Ungültiger Benutzername oder ungültige E-Mail. +invalidPasswordMessage=Ungültiges Passwort. +invalidEmailMessage=Ungültige E-Mail-Adresse. +loginInvalidCredentials=Ungültiger Benutzername oder ungültiges Passwort. +loginAccountDisabled=Das Konto ist deaktiviert, wenden Sie sich an Ihren Administrator. +loginAccountTemporarilyDisabled=Das Konto ist vorübergehend deaktiviert, wenden Sie sich an Ihren Administrator oder versuchen Sie es später erneut. +accountDisabledMessage=Das Konto ist deaktiviert, wenden Sie sich an Ihren Administrator. +accountTemporarilyDisabledMessage=Ungültiger Benutzername oder ungültiges Passwort. +accountPermanentlyDisabledMessage=Ungültiger Benutzername oder ungültiges Passwort. +loginInvalidTotp=Ungültiger Authentifikatorcode. +invalidTotpMessage=Ungültiger Authentifikatorcode. +loginMissingUsername=Bitte geben Sie einen Benutzernamen an. +loginMissingPassword=Bitte geben Sie ein Passwort an. +loginMissingTotp=Bitte geben Sie den Authentifikatorcode an. +missingUsernameMessage=Bitte geben Sie einen Benutzernamen an. +missingPasswordMessage=Bitte geben Sie ein Passwort an. +missingTotpMessage=Bitte geben Sie den Authentifikatorcode an. +expiredCodeMessage=Anmeldung abgelaufen. Bitte melden Sie sich erneut an. +expiredActionMessage=Die Aktion ist abgelaufen. Bitte fahren Sie jetzt mit der Anmeldung fort. +sessionNotActiveMessage=Die Sitzung ist nicht aktiv. +invalidCodeMessage=Ein Fehler ist aufgetreten, bitte melden Sie sich erneut über Ihre Anwendung an. +noAccount=Neuer Benutzer? +loginAccountTitle=Bei Ihrem Konto anmelden +loginTitle=Bei {0} anmelden +loginTitleHtml={0} +loginTimeout=Ihr Anmeldeversuch ist abgelaufen. Die Anmeldung beginnt von vorne. +pageExpiredTitle=Die Seite ist abgelaufen +pageExpiredMsg1=Um den Anmeldevorgang neu zu starten +pageExpiredMsg2=Um den Anmeldevorgang fortzusetzen + +# Registration error messages +registerMissingUsername=Bitte geben Sie einen Benutzernamen an. +registerMissingFirstName=Bitte geben Sie einen Vornamen an. +registerMissingLastName=Bitte geben Sie einen Nachnamen an. +registerMissingEmail=Bitte geben Sie eine E-Mail an. +registerMissingPassword=Bitte geben Sie ein Passwort an. +registerMissingPasswordConfirm=Bitte bestätigen Sie das Passwort. +registerPasswordNotMatch=Die Passwortbestätigung stimmt nicht überein. +registerInvalidPasswordExisting=Ungültiges vorhandenes Passwort. +registerInvalidPasswordPattern=Ungültiges Passwort: muss mindestens 8 Zeichen enthalten, mindestens einen Großbuchstaben, einen Kleinbuchstaben, eine Ziffer und ein Sonderzeichen. +registerUsernameExists=Der Benutzername existiert bereits. +registerEmailExists=Die E-Mail existiert bereits. +registerPasswordConfirmNotMatch=Die Passwortbestätigung stimmt nicht überein. + +# User profile validation messages (declarative user profile / VERIFY_PROFILE) +error-user-attribute-required=Bitte geben Sie dieses Feld an. +error-invalid-blank=Bitte geben Sie einen Wert an. +error-invalid-email=Ungültige E-Mail-Adresse. +error-invalid-length=Die Länge muss zwischen {1} und {2} liegen. + +# Generic error messages +unexpectedErrorTitle=Ein unerwarteter Fehler ist aufgetreten +unexpectedErrorTitleHtml=Ein unerwarteter Fehler ist aufgetreten +backToApplication=« Zurück zur Anwendung +missingParameter=Fehlender Parameter: {0} +missingParameterMessage=Fehlende Parameter: {0} +invalidRequest=Ungültige Anfrage +invalidParameter=Ungültiger Parameter +invalidParameterValue=Ungültiger Parameterwert für ''{0}'' +invalidParameterMessage=Ungültiger Parameter: {0} +clientNotFound=Client nicht gefunden. +clientNotFoundMessage=Client nicht gefunden. +invalidCode=Ungültiger Code. +invalidGrant=Ungültige Berechtigung. +invalidToken=Ungültiges Token. +accessDenied=Zugriff verweigert. +httpsRequiredMessage=HTTPS erforderlich +realmNotEnabledMessage=Realm nicht aktiviert +invalidRequestMessage=Ungültige Anfrage +unknownLoginRequesterMessage=Unbekannter Anmeldeanforderer +loginRequesterNotEnabledMessage=Anmeldeanforderer nicht aktiviert +bearerOnlyMessage=Bearer-only-Anwendungen ist es nicht erlaubt, eine Browser-Anmeldung zu initiieren +standardFlowDisabledMessage=Der Client darf mit dem angegebenen response_type keine Browser-Anmeldung initiieren. Der Standardablauf ist für den Client deaktiviert. +invalidRedirectUriMessage=Ungültige Weiterleitungs-URI +registrationNotAllowedMessage=Registrierung nicht erlaubt +resetCredentialNotAllowedMessage=Zurücksetzen der Anmeldedaten nicht erlaubt + +# Logout +logoutTitle=Abmeldung läuft +logoutConfirmTitle=Sind Sie sicher, dass Sie sich abmelden möchten? +logoutConfirmHeader=Abmeldung läuft +logoutConfirmationMessage=Sie werden von Open Bank Project und allen verbundenen Anwendungen abgemeldet. +doLogout=Abmelden + +# Account pages +accountManagementTitle=Open Bank Project-Kontoverwaltung +personalInfo=Persönliche Informationen +accountSecurity=Kontosicherheit +applicationsHtml=Anwendungen +linkedAccountsHtml=Verknüpfte Konten + +# Two-factor authentication +loginTotpIntro=Sie müssen einen mobilen Authentifikator einrichten, um auf Ihr Konto zugreifen zu können +loginTotpStep1=Installieren Sie eine der folgenden Anwendungen auf Ihrem Mobilgerät +loginTotpStep2=Öffnen Sie die Anwendung und scannen Sie den Barcode +loginTotpStep3=Geben Sie den von der Anwendung bereitgestellten Einmalcode ein und klicken Sie auf Absenden, um die Einrichtung abzuschließen +loginTotpManualStep2=Öffnen Sie die Anwendung und geben Sie den Schlüssel ein +loginTotpManualStep3=Verwenden Sie die folgenden Konfigurationswerte +loginTotpUnableToScan=Scannen nicht möglich? +loginTotpScanBarcode=Barcode scannen? +loginCredential=Anmeldedaten + +# Social login +loginTitleHtml=Bei Open Bank Project anmelden +loginIdpReviewProfileTitle=Kontoinformationen aktualisieren +loginIdpReviewProfileInfo=Bitte überprüfen Sie Ihre von {0} abgerufenen Kontoinformationen + +# Application permissions +clientScopeRole.openid=OpenID Connect integrierter Bereich: openid +clientScopeRole.email=OpenID Connect integrierter Bereich: email +clientScopeRole.profile=OpenID Connect integrierter Bereich: profile +clientScopeRole.address=OpenID Connect integrierter Bereich: address +clientScopeRole.phone=OpenID Connect integrierter Bereich: phone +clientScopeRole.offline_access=OpenID Connect integrierter Bereich: offline_access + +# Custom OBP-specific messages +obpWelcome=Willkommen bei Open Bank Project +obpDescription=Die führende Open-Source-API-Plattform für Banken +obpSecureLogin=Sichere Anmeldung mit Keycloak +obpSupport=Benötigen Sie Hilfe? Kontaktieren Sie unser Support-Team +obpPrivacy=Ihre Privatsphäre und Sicherheit haben für uns Priorität +obpCopyright=© 2011-2025 TESOBE. Alle Rechte vorbehalten. + +# Show/Hide password +showPassword=Passwort anzeigen +hidePassword=Passwort verbergen + +# Additional standard Keycloak messages for complete coverage +alreadyLoggedIn=Sie sind bereits angemeldet. +differentUserAuthenticated=Sie sind in dieser Sitzung bereits als anderer Benutzer ''{0}'' authentifiziert. Bitte melden Sie sich zuerst ab. +cookieNotFoundMessage=Das Cookie zum Neustart der Anmeldung wurde nicht gefunden. Es ist möglicherweise abgelaufen, wurde gelöscht oder Cookies sind in Ihrem Browser deaktiviert. +staleCodeMessage=Diese Seite ist nicht mehr gültig, bitte kehren Sie zu Ihrer Anwendung zurück und melden Sie sich erneut an +emailSentMessage=Sie sollten in Kürze eine E-Mail mit weiteren Anweisungen erhalten. +emailSendErrorMessage=Senden der E-Mail fehlgeschlagen, bitte versuchen Sie es später erneut. + +# Identity provider login +identity-provider-login-label=Oder anmelden mit + +# Additional security messages +loginRecoveryKeyTitle=Einrichtung des Wiederherstellungsschlüssels +loginRecoveryKeyInstruction=Bitte notieren Sie sich diesen Wiederherstellungsschlüssel und bewahren Sie ihn an einem sicheren Ort auf. Sie können ihn verwenden, um Ihr Konto wiederherzustellen, falls Sie den Zugriff auf Ihren Authentifikator verlieren. +loginBackupCodesTitle=Backup-Codes +loginBackupCodesInstruction=Bitte notieren Sie sich diese Backup-Codes und bewahren Sie sie an einem sicheren Ort auf. Jeder Code kann nur einmal verwendet werden. + +# WebAuthn messages +webauthnTitle=Sicherheitsschlüssel +webauthnInstruction=Bitte berühren Sie Ihren Sicherheitsschlüssel +webauthnErrorTitle=Fehler beim Sicherheitsschlüssel +webauthnUnsupported=Sicherheitsschlüssel werden von diesem Browser nicht unterstützt. diff --git a/themes/obp/login/messages/messages_es.properties b/themes/obp/login/messages/messages_es.properties new file mode 100644 index 0000000..5b7d87d --- /dev/null +++ b/themes/obp/login/messages/messages_es.properties @@ -0,0 +1,227 @@ +# OBP Keycloak Theme - English Messages +# Open Bank Project branding and improved user experience + +# Login page +loginTitle=Inicie sesión en Open Bank Project +loginTitleHtml=Inicie sesión en Open Bank Project +usernameOrEmail=Nombre de usuario o email +username=Nombre de usuario +email=Email +password=Contraseña +loginUsername=Nombre de usuario o email +loginPassword=Contraseña +loginRememberMe=Recuérdeme +doLogIn=Iniciar sesión +loginSubmit=Iniciar sesión +doForgotPassword=¿Olvidó su contraseña? +loginForgotPassword=¿Olvidó su contraseña? +loginNoAccount=¿Usuario nuevo? +doRegister=Crear una cuenta +loginRegister=Crear una cuenta +loginTotpTitle=Configuración del autenticador móvil +loginProfileTitle=Actualizar la información de la cuenta +loginTimeout=Su intento de inicio de sesión expiró. El inicio de sesión comenzará desde el principio. + +# Update profile page (VERIFY_PROFILE required action) — field labels and buttons. +# Defined here because this theme's bundle does not inherit them from the base theme. +firstName=Nombre +lastName=Apellido +doSubmit=Enviar +doCancel=Cancelar + +# OAuth grant page +oauthGrantTitle=Conceder acceso a {0} +oauthGrantInformation=Al conceder acceso, permite que {0} acceda a la información de su cuenta de Open Bank Project. + +# Registration page +registerTitle=Regístrese en Open Bank Project +registerSubmit=Registrarse +registerWithTitle=O regístrese con +registerUsername=Nombre de usuario +registerEmail=Email +registerFirstName=Nombre +registerLastName=Apellido +registerPassword=Contraseña +registerPasswordConfirm=Confirmar contraseña +registerAlreadyHaveAccount=¿Ya tiene una cuenta? +registerBackToLogin=« Volver al inicio de sesión + +# Password reset +resetPasswordTitle=¿Olvidó su contraseña? +resetPasswordInstruction=Introduzca su nombre de usuario o dirección de email y le enviaremos instrucciones sobre cómo crear una nueva contraseña. +resetPasswordSubmit=Enviar +resetPasswordBackToLogin=« Volver al inicio de sesión + +# Update password +updatePasswordTitle=Actualizar contraseña +updatePasswordInstruction=Por favor, cree una nueva contraseña para su cuenta de Open Bank Project. +updatePasswordNewPassword=Nueva contraseña +updatePasswordConfirmPassword=Confirmar la nueva contraseña +updatePasswordSubmit=Enviar + +# Verify email +verifyEmailTitle=Verificación de email +verifyEmailInstruction=Se le ha enviado un email con instrucciones para verificar su dirección de email. +verifyEmailInstructionHtml=Se ha enviado un email con instrucciones para verificar su dirección de email a {0}. +verifyEmailNoReceived=¿No recibió un código de verificación en su email? +verifyEmailResendInstruction=Haga clic en el enlace de abajo para reenviar el email. +verifyEmailResend=Reenviar email + +# Terms and conditions +termsTitle=Términos y condiciones +termsText=Términos y condiciones por definir para Open Bank Project. +termsPlainText=Términos y condiciones por definir para Open Bank Project. +acceptTerms=Acepto los términos y condiciones + +# Error messages +invalidUserMessage=Nombre de usuario o contraseña no válidos. +invalidUsernameMessage=Nombre de usuario no válido. +invalidUsernameOrEmailMessage=Nombre de usuario o email no válidos. +invalidPasswordMessage=Contraseña no válida. +invalidEmailMessage=Dirección de email no válida. +loginInvalidCredentials=Nombre de usuario o contraseña no válidos. +loginAccountDisabled=La cuenta está deshabilitada, póngase en contacto con su administrador. +loginAccountTemporarilyDisabled=La cuenta está temporalmente deshabilitada, póngase en contacto con su administrador o inténtelo de nuevo más tarde. +accountDisabledMessage=La cuenta está deshabilitada, póngase en contacto con su administrador. +accountTemporarilyDisabledMessage=Nombre de usuario o contraseña no válidos. +accountPermanentlyDisabledMessage=Nombre de usuario o contraseña no válidos. +loginInvalidTotp=Código de autenticador no válido. +invalidTotpMessage=Código de autenticador no válido. +loginMissingUsername=Por favor, especifique el nombre de usuario. +loginMissingPassword=Por favor, especifique la contraseña. +loginMissingTotp=Por favor, especifique el código de autenticador. +missingUsernameMessage=Por favor, especifique el nombre de usuario. +missingPasswordMessage=Por favor, especifique la contraseña. +missingTotpMessage=Por favor, especifique el código de autenticador. +expiredCodeMessage=El inicio de sesión expiró. Por favor, inicie sesión de nuevo. +expiredActionMessage=La acción expiró. Por favor, continúe ahora con el inicio de sesión. +sessionNotActiveMessage=La sesión no está activa. +invalidCodeMessage=Se produjo un error, por favor inicie sesión de nuevo a través de su aplicación. +noAccount=¿Usuario nuevo? +loginAccountTitle=Inicie sesión en su cuenta +loginTitle=Inicie sesión en {0} +loginTitleHtml={0} +loginTimeout=Su intento de inicio de sesión expiró. El inicio de sesión comenzará desde el principio. +pageExpiredTitle=La página ha expirado +pageExpiredMsg1=Para reiniciar el proceso de inicio de sesión +pageExpiredMsg2=Para continuar el proceso de inicio de sesión + +# Registration error messages +registerMissingUsername=Por favor, especifique el nombre de usuario. +registerMissingFirstName=Por favor, especifique el nombre. +registerMissingLastName=Por favor, especifique el apellido. +registerMissingEmail=Por favor, especifique el email. +registerMissingPassword=Por favor, especifique la contraseña. +registerMissingPasswordConfirm=Por favor, confirme la contraseña. +registerPasswordNotMatch=La confirmación de la contraseña no coincide. +registerInvalidPasswordExisting=La contraseña existente no es válida. +registerInvalidPasswordPattern=Contraseña no válida: debe contener al menos 8 caracteres, al menos una mayúscula, una minúscula, un dígito y un carácter especial. +registerUsernameExists=El nombre de usuario ya existe. +registerEmailExists=El email ya existe. +registerPasswordConfirmNotMatch=La confirmación de la contraseña no coincide. + +# User profile validation messages (declarative user profile / VERIFY_PROFILE) +error-user-attribute-required=Por favor, especifique este campo. +error-invalid-blank=Por favor, especifique un valor. +error-invalid-email=Dirección de email no válida. +error-invalid-length=La longitud debe estar entre {1} y {2}. + +# Generic error messages +unexpectedErrorTitle=Se ha producido un error inesperado +unexpectedErrorTitleHtml=Se ha producido un error inesperado +backToApplication=« Volver a la aplicación +missingParameter=Falta el parámetro: {0} +missingParameterMessage=Faltan parámetros: {0} +invalidRequest=Solicitud no válida +invalidParameter=Parámetro no válido +invalidParameterValue=Valor de parámetro no válido para ''{0}'' +invalidParameterMessage=Parámetro no válido: {0} +clientNotFound=Cliente no encontrado. +clientNotFoundMessage=Cliente no encontrado. +invalidCode=Código no válido. +invalidGrant=Concesión no válida. +invalidToken=Token no válido. +accessDenied=Acceso denegado. +httpsRequiredMessage=Se requiere HTTPS +realmNotEnabledMessage=Realm no habilitado +invalidRequestMessage=Solicitud no válida +unknownLoginRequesterMessage=Solicitante de inicio de sesión desconocido +loginRequesterNotEnabledMessage=El solicitante de inicio de sesión no está habilitado +bearerOnlyMessage=Las aplicaciones Bearer-only no pueden iniciar el inicio de sesión en el navegador +standardFlowDisabledMessage=El cliente no puede iniciar el inicio de sesión en el navegador con el response_type indicado. El flujo estándar está deshabilitado para el cliente. +invalidRedirectUriMessage=URI de redirección no válida +registrationNotAllowedMessage=Registro no permitido +resetCredentialNotAllowedMessage=Restablecimiento de credencial no permitido + +# Logout +logoutTitle=Cerrando sesión +logoutConfirmTitle=¿Está seguro de que desea cerrar sesión? +logoutConfirmHeader=Cerrando sesión +logoutConfirmationMessage=Se cerrará su sesión en Open Bank Project y en todas las aplicaciones conectadas. +doLogout=Cerrar sesión + +# Account pages +accountManagementTitle=Gestión de la cuenta de Open Bank Project +personalInfo=Información personal +accountSecurity=Seguridad de la cuenta +applicationsHtml=Aplicaciones +linkedAccountsHtml=Cuentas vinculadas + +# Two-factor authentication +loginTotpIntro=Necesita configurar un autenticador móvil para acceder a su cuenta +loginTotpStep1=Instale una de las siguientes aplicaciones en su móvil +loginTotpStep2=Abra la aplicación y escanee el código de barras +loginTotpStep3=Introduzca el código de un solo uso proporcionado por la aplicación y haga clic en Enviar para finalizar la configuración +loginTotpManualStep2=Abra la aplicación e introduzca la clave +loginTotpManualStep3=Utilice los siguientes valores de configuración +loginTotpUnableToScan=¿No puede escanear? +loginTotpScanBarcode=¿Escanear código de barras? +loginCredential=Credencial + +# Social login +loginTitleHtml=Inicie sesión en Open Bank Project +loginIdpReviewProfileTitle=Actualizar la información de la cuenta +loginIdpReviewProfileInfo=Por favor, revise la información de su cuenta obtenida de {0} + +# Application permissions +clientScopeRole.openid=OpenID Connect built-in scope: openid +clientScopeRole.email=OpenID Connect built-in scope: email +clientScopeRole.profile=OpenID Connect built-in scope: profile +clientScopeRole.address=OpenID Connect built-in scope: address +clientScopeRole.phone=OpenID Connect built-in scope: phone +clientScopeRole.offline_access=OpenID Connect built-in scope: offline_access + +# Custom OBP-specific messages +obpWelcome=Bienvenido a Open Bank Project +obpDescription=La plataforma de API de código abierto líder para bancos +obpSecureLogin=Inicio de sesión seguro con tecnología de Keycloak +obpSupport=¿Necesita ayuda? Póngase en contacto con nuestro equipo de soporte +obpPrivacy=Su privacidad y seguridad son nuestra prioridad +obpCopyright=© 2011-2025 TESOBE. Todos los derechos reservados. + +# Show/Hide password +showPassword=Mostrar contraseña +hidePassword=Ocultar contraseña + +# Additional standard Keycloak messages for complete coverage +alreadyLoggedIn=Ya ha iniciado sesión. +differentUserAuthenticated=Ya está autenticado como un usuario diferente ''{0}'' en esta sesión. Por favor, cierre sesión primero. +cookieNotFoundMessage=No se encontró la cookie de reinicio de inicio de sesión. Es posible que haya expirado, que se haya eliminado o que las cookies estén deshabilitadas en su navegador. +staleCodeMessage=Esta página ya no es válida, por favor vuelva a su aplicación e inicie sesión de nuevo +emailSentMessage=En breve debería recibir un email con más instrucciones. +emailSendErrorMessage=No se pudo enviar el email, por favor inténtelo de nuevo más tarde. + +# Identity provider login +identity-provider-login-label=O inicie sesión con + +# Additional security messages +loginRecoveryKeyTitle=Configuración de la clave de recuperación +loginRecoveryKeyInstruction=Por favor, anote esta clave de recuperación y guárdela en un lugar seguro. Puede utilizarla para recuperar su cuenta si pierde el acceso a su autenticador. +loginBackupCodesTitle=Códigos de respaldo +loginBackupCodesInstruction=Por favor, anote estos códigos de respaldo y guárdelos en un lugar seguro. Cada código solo se puede utilizar una vez. + +# WebAuthn messages +webauthnTitle=Clave de seguridad +webauthnInstruction=Por favor, toque su clave de seguridad +webauthnErrorTitle=Error de clave de seguridad +webauthnUnsupported=Este navegador no admite claves de seguridad. diff --git a/themes/obp/login/messages/messages_fr.properties b/themes/obp/login/messages/messages_fr.properties new file mode 100644 index 0000000..3003231 --- /dev/null +++ b/themes/obp/login/messages/messages_fr.properties @@ -0,0 +1,227 @@ +# OBP Keycloak Theme - English Messages +# Open Bank Project branding and improved user experience + +# Login page +loginTitle=Connectez-vous à Open Bank Project +loginTitleHtml=Connectez-vous à Open Bank Project +usernameOrEmail=Nom d'utilisateur ou email +username=Nom d'utilisateur +email=Email +password=Mot de passe +loginUsername=Nom d'utilisateur ou email +loginPassword=Mot de passe +loginRememberMe=Se souvenir de moi +doLogIn=Se connecter +loginSubmit=Se connecter +doForgotPassword=Mot de passe oublié ? +loginForgotPassword=Mot de passe oublié ? +loginNoAccount=Nouvel utilisateur ? +doRegister=Créer un compte +loginRegister=Créer un compte +loginTotpTitle=Configuration de l'authentificateur mobile +loginProfileTitle=Mettre à jour les informations du compte +loginTimeout=Votre tentative de connexion a expiré. La connexion va recommencer depuis le début. + +# Update profile page (VERIFY_PROFILE required action) — field labels and buttons. +# Defined here because this theme's bundle does not inherit them from the base theme. +firstName=Prénom +lastName=Nom +doSubmit=Envoyer +doCancel=Annuler + +# OAuth grant page +oauthGrantTitle=Accorder l'accès à {0} +oauthGrantInformation=En accordant l'accès, vous autorisez {0} à accéder aux informations de votre compte Open Bank Project. + +# Registration page +registerTitle=Inscription à Open Bank Project +registerSubmit=S'inscrire +registerWithTitle=Ou inscrivez-vous avec +registerUsername=Nom d'utilisateur +registerEmail=Email +registerFirstName=Prénom +registerLastName=Nom +registerPassword=Mot de passe +registerPasswordConfirm=Confirmer le mot de passe +registerAlreadyHaveAccount=Vous avez déjà un compte ? +registerBackToLogin=« Retour à la connexion + +# Password reset +resetPasswordTitle=Vous avez oublié votre mot de passe ? +resetPasswordInstruction=Saisissez votre nom d'utilisateur ou votre adresse email et nous vous enverrons des instructions pour créer un nouveau mot de passe. +resetPasswordSubmit=Envoyer +resetPasswordBackToLogin=« Retour à la connexion + +# Update password +updatePasswordTitle=Mettre à jour le mot de passe +updatePasswordInstruction=Veuillez créer un nouveau mot de passe pour votre compte Open Bank Project. +updatePasswordNewPassword=Nouveau mot de passe +updatePasswordConfirmPassword=Confirmer le nouveau mot de passe +updatePasswordSubmit=Envoyer + +# Verify email +verifyEmailTitle=Vérification de l'email +verifyEmailInstruction=Un email contenant des instructions pour vérifier votre adresse email vous a été envoyé. +verifyEmailInstructionHtml=Un email contenant des instructions pour vérifier votre adresse email a été envoyé à {0}. +verifyEmailNoReceived=Vous n'avez pas reçu de code de vérification dans votre email ? +verifyEmailResendInstruction=Cliquez sur le lien ci-dessous pour renvoyer l'email. +verifyEmailResend=Renvoyer l'email + +# Terms and conditions +termsTitle=Conditions générales +termsText=Conditions générales à définir pour Open Bank Project. +termsPlainText=Conditions générales à définir pour Open Bank Project. +acceptTerms=J'accepte les conditions générales + +# Error messages +invalidUserMessage=Nom d'utilisateur ou mot de passe invalide. +invalidUsernameMessage=Nom d'utilisateur invalide. +invalidUsernameOrEmailMessage=Nom d'utilisateur ou email invalide. +invalidPasswordMessage=Mot de passe invalide. +invalidEmailMessage=Adresse email invalide. +loginInvalidCredentials=Nom d'utilisateur ou mot de passe invalide. +loginAccountDisabled=Le compte est désactivé, contactez votre administrateur. +loginAccountTemporarilyDisabled=Le compte est temporairement désactivé, contactez votre administrateur ou réessayez plus tard. +accountDisabledMessage=Le compte est désactivé, contactez votre administrateur. +accountTemporarilyDisabledMessage=Nom d'utilisateur ou mot de passe invalide. +accountPermanentlyDisabledMessage=Nom d'utilisateur ou mot de passe invalide. +loginInvalidTotp=Code d'authentification invalide. +invalidTotpMessage=Code d'authentification invalide. +loginMissingUsername=Veuillez indiquer un nom d'utilisateur. +loginMissingPassword=Veuillez indiquer un mot de passe. +loginMissingTotp=Veuillez indiquer le code d'authentification. +missingUsernameMessage=Veuillez indiquer un nom d'utilisateur. +missingPasswordMessage=Veuillez indiquer un mot de passe. +missingTotpMessage=Veuillez indiquer le code d'authentification. +expiredCodeMessage=Délai de connexion expiré. Veuillez vous reconnecter. +expiredActionMessage=L'action a expiré. Veuillez maintenant poursuivre la connexion. +sessionNotActiveMessage=La session n'est pas active. +invalidCodeMessage=Une erreur s'est produite, veuillez vous reconnecter via votre application. +noAccount=Nouvel utilisateur ? +loginAccountTitle=Connectez-vous à votre compte +loginTitle=Connectez-vous à {0} +loginTitleHtml={0} +loginTimeout=Votre tentative de connexion a expiré. La connexion va recommencer depuis le début. +pageExpiredTitle=La page a expiré +pageExpiredMsg1=Pour recommencer le processus de connexion +pageExpiredMsg2=Pour poursuivre le processus de connexion + +# Registration error messages +registerMissingUsername=Veuillez indiquer un nom d'utilisateur. +registerMissingFirstName=Veuillez indiquer un prénom. +registerMissingLastName=Veuillez indiquer un nom. +registerMissingEmail=Veuillez indiquer un email. +registerMissingPassword=Veuillez indiquer un mot de passe. +registerMissingPasswordConfirm=Veuillez confirmer le mot de passe. +registerPasswordNotMatch=La confirmation du mot de passe ne correspond pas. +registerInvalidPasswordExisting=Mot de passe actuel invalide. +registerInvalidPasswordPattern=Mot de passe invalide : il doit contenir au moins 8 caractères, au moins une majuscule, une minuscule, un chiffre et un caractère spécial. +registerUsernameExists=Ce nom d'utilisateur existe déjà. +registerEmailExists=Cet email existe déjà. +registerPasswordConfirmNotMatch=La confirmation du mot de passe ne correspond pas. + +# User profile validation messages (declarative user profile / VERIFY_PROFILE) +error-user-attribute-required=Veuillez renseigner ce champ. +error-invalid-blank=Veuillez indiquer une valeur. +error-invalid-email=Adresse email invalide. +error-invalid-length=La longueur doit être comprise entre {1} et {2}. + +# Generic error messages +unexpectedErrorTitle=Une erreur inattendue s'est produite +unexpectedErrorTitleHtml=Une erreur inattendue s'est produite +backToApplication=« Retour à l'application +missingParameter=Paramètre manquant : {0} +missingParameterMessage=Paramètres manquants : {0} +invalidRequest=Requête invalide +invalidParameter=Paramètre invalide +invalidParameterValue=Valeur de paramètre invalide pour ''{0}'' +invalidParameterMessage=Paramètre invalide : {0} +clientNotFound=Client introuvable. +clientNotFoundMessage=Client introuvable. +invalidCode=Code invalide. +invalidGrant=Autorisation invalide. +invalidToken=Jeton invalide. +accessDenied=Accès refusé. +httpsRequiredMessage=HTTPS requis +realmNotEnabledMessage=Realm non activé +invalidRequestMessage=Requête invalide +unknownLoginRequesterMessage=Demandeur de connexion inconnu +loginRequesterNotEnabledMessage=Le demandeur de connexion n'est pas activé +bearerOnlyMessage=Les applications Bearer-only ne sont pas autorisées à initier une connexion via le navigateur +standardFlowDisabledMessage=Le client n'est pas autorisé à initier une connexion via le navigateur avec le response_type fourni. Le flux standard est désactivé pour ce client. +invalidRedirectUriMessage=URI de redirection invalide +registrationNotAllowedMessage=Inscription non autorisée +resetCredentialNotAllowedMessage=Réinitialisation des identifiants non autorisée + +# Logout +logoutTitle=Déconnexion en cours +logoutConfirmTitle=Êtes-vous sûr de vouloir vous déconnecter ? +logoutConfirmHeader=Déconnexion en cours +logoutConfirmationMessage=Vous serez déconnecté d'Open Bank Project et de toutes les applications connectées. +doLogout=Se déconnecter + +# Account pages +accountManagementTitle=Gestion du compte Open Bank Project +personalInfo=Informations personnelles +accountSecurity=Sécurité du compte +applicationsHtml=Applications +linkedAccountsHtml=Comptes liés + +# Two-factor authentication +loginTotpIntro=Vous devez configurer un authentificateur mobile pour accéder à votre compte +loginTotpStep1=Installez l'une des applications suivantes sur votre mobile +loginTotpStep2=Ouvrez l'application et scannez le code-barres +loginTotpStep3=Saisissez le code à usage unique fourni par l'application et cliquez sur Envoyer pour terminer la configuration +loginTotpManualStep2=Ouvrez l'application et saisissez la clé +loginTotpManualStep3=Utilisez les valeurs de configuration suivantes +loginTotpUnableToScan=Impossible de scanner ? +loginTotpScanBarcode=Scanner le code-barres ? +loginCredential=Identifiant + +# Social login +loginTitleHtml=Connectez-vous à Open Bank Project +loginIdpReviewProfileTitle=Mettre à jour les informations du compte +loginIdpReviewProfileInfo=Veuillez vérifier les informations de votre compte récupérées depuis {0} + +# Application permissions +clientScopeRole.openid=OpenID Connect built-in scope: openid +clientScopeRole.email=OpenID Connect built-in scope: email +clientScopeRole.profile=OpenID Connect built-in scope: profile +clientScopeRole.address=OpenID Connect built-in scope: address +clientScopeRole.phone=OpenID Connect built-in scope: phone +clientScopeRole.offline_access=OpenID Connect built-in scope: offline_access + +# Custom OBP-specific messages +obpWelcome=Bienvenue sur Open Bank Project +obpDescription=La principale plateforme d'API open source pour les banques +obpSecureLogin=Connexion sécurisée propulsée par Keycloak +obpSupport=Besoin d'aide ? Contactez notre équipe d'assistance +obpPrivacy=Votre confidentialité et votre sécurité sont notre priorité +obpCopyright=© 2011-2025 TESOBE. Tous droits réservés. + +# Show/Hide password +showPassword=Afficher le mot de passe +hidePassword=Masquer le mot de passe + +# Additional standard Keycloak messages for complete coverage +alreadyLoggedIn=Vous êtes déjà connecté. +differentUserAuthenticated=Vous êtes déjà authentifié en tant qu'utilisateur différent ''{0}'' dans cette session. Veuillez d'abord vous déconnecter. +cookieNotFoundMessage=Le cookie de redémarrage de la connexion est introuvable. Il a peut-être expiré, été supprimé, ou les cookies sont désactivés dans votre navigateur. +staleCodeMessage=Cette page n'est plus valide, veuillez retourner à votre application et vous reconnecter +emailSentMessage=Vous devriez recevoir sous peu un email contenant des instructions supplémentaires. +emailSendErrorMessage=Échec de l'envoi de l'email, veuillez réessayer plus tard. + +# Identity provider login +identity-provider-login-label=Ou connectez-vous avec + +# Additional security messages +loginRecoveryKeyTitle=Configuration de la clé de récupération +loginRecoveryKeyInstruction=Veuillez noter cette clé de récupération et la conserver en lieu sûr. Vous pouvez l'utiliser pour récupérer votre compte si vous perdez l'accès à votre authentificateur. +loginBackupCodesTitle=Codes de secours +loginBackupCodesInstruction=Veuillez noter ces codes de secours et les conserver en lieu sûr. Chaque code ne peut être utilisé qu'une seule fois. + +# WebAuthn messages +webauthnTitle=Clé de sécurité +webauthnInstruction=Veuillez toucher votre clé de sécurité +webauthnErrorTitle=Erreur de clé de sécurité +webauthnUnsupported=Les clés de sécurité ne sont pas prises en charge par ce navigateur. diff --git a/themes/obp/login/messages/messages_it.properties b/themes/obp/login/messages/messages_it.properties new file mode 100644 index 0000000..25ab6c5 --- /dev/null +++ b/themes/obp/login/messages/messages_it.properties @@ -0,0 +1,227 @@ +# OBP Keycloak Theme - English Messages +# Open Bank Project branding and improved user experience + +# Login page +loginTitle=Accedi a Open Bank Project +loginTitleHtml=Accedi a Open Bank Project +usernameOrEmail=Nome utente o email +username=Nome utente +email=Email +password=Password +loginUsername=Nome utente o email +loginPassword=Password +loginRememberMe=Ricordami +doLogIn=Accedi +loginSubmit=Accedi +doForgotPassword=Password dimenticata? +loginForgotPassword=Password dimenticata? +loginNoAccount=Nuovo utente? +doRegister=Crea un account +loginRegister=Crea un account +loginTotpTitle=Configurazione dell'autenticatore mobile +loginProfileTitle=Aggiorna le informazioni dell'account +loginTimeout=Il tentativo di accesso è scaduto. L'accesso ripartirà dall'inizio. + +# Update profile page (VERIFY_PROFILE required action) — field labels and buttons. +# Defined here because this theme's bundle does not inherit them from the base theme. +firstName=Nome +lastName=Cognome +doSubmit=Invia +doCancel=Annulla + +# OAuth grant page +oauthGrantTitle=Concedi l'accesso a {0} +oauthGrantInformation=Concedendo l'accesso, Lei consente a {0} di accedere alle informazioni del Suo account Open Bank Project. + +# Registration page +registerTitle=Registrati a Open Bank Project +registerSubmit=Registrati +registerWithTitle=Oppure registrati con +registerUsername=Nome utente +registerEmail=Email +registerFirstName=Nome +registerLastName=Cognome +registerPassword=Password +registerPasswordConfirm=Conferma password +registerAlreadyHaveAccount=Ha già un account? +registerBackToLogin=« Torna all'accesso + +# Password reset +resetPasswordTitle=Ha dimenticato la password? +resetPasswordInstruction=Inserisca il Suo nome utente o indirizzo email e Le invieremo le istruzioni su come creare una nuova password. +resetPasswordSubmit=Invia +resetPasswordBackToLogin=« Torna all'accesso + +# Update password +updatePasswordTitle=Aggiorna password +updatePasswordInstruction=Crei una nuova password per il Suo account Open Bank Project. +updatePasswordNewPassword=Nuova password +updatePasswordConfirmPassword=Conferma la nuova password +updatePasswordSubmit=Invia + +# Verify email +verifyEmailTitle=Verifica dell'email +verifyEmailInstruction=Le è stata inviata un'email con le istruzioni per verificare il Suo indirizzo email. +verifyEmailInstructionHtml=Un'email con le istruzioni per verificare il Suo indirizzo email è stata inviata a {0}. +verifyEmailNoReceived=Non ha ricevuto un codice di verifica nella Sua email? +verifyEmailResendInstruction=Clicchi sul link sottostante per inviare nuovamente l'email. +verifyEmailResend=Invia nuovamente l'email + +# Terms and conditions +termsTitle=Termini e condizioni +termsText=Termini e condizioni da definire per Open Bank Project. +termsPlainText=Termini e condizioni da definire per Open Bank Project. +acceptTerms=Accetto i Termini e le condizioni + +# Error messages +invalidUserMessage=Nome utente o password non validi. +invalidUsernameMessage=Nome utente non valido. +invalidUsernameOrEmailMessage=Nome utente o email non validi. +invalidPasswordMessage=Password non valida. +invalidEmailMessage=Indirizzo email non valido. +loginInvalidCredentials=Nome utente o password non validi. +loginAccountDisabled=L'account è disabilitato, contatti il Suo amministratore. +loginAccountTemporarilyDisabled=L'account è temporaneamente disabilitato, contatti il Suo amministratore o riprovi più tardi. +accountDisabledMessage=L'account è disabilitato, contatti il Suo amministratore. +accountTemporarilyDisabledMessage=Nome utente o password non validi. +accountPermanentlyDisabledMessage=Nome utente o password non validi. +loginInvalidTotp=Codice dell'autenticatore non valido. +invalidTotpMessage=Codice dell'autenticatore non valido. +loginMissingUsername=Specifichi il nome utente. +loginMissingPassword=Specifichi la password. +loginMissingTotp=Specifichi il codice dell'autenticatore. +missingUsernameMessage=Specifichi il nome utente. +missingPasswordMessage=Specifichi la password. +missingTotpMessage=Specifichi il codice dell'autenticatore. +expiredCodeMessage=Accesso scaduto. Effettui nuovamente l'accesso. +expiredActionMessage=Azione scaduta. Continui ora con l'accesso. +sessionNotActiveMessage=Sessione non attiva. +invalidCodeMessage=Si è verificato un errore, effettui nuovamente l'accesso tramite la Sua applicazione. +noAccount=Nuovo utente? +loginAccountTitle=Accedi al Suo account +loginTitle=Accedi a {0} +loginTitleHtml={0} +loginTimeout=Il tentativo di accesso è scaduto. L'accesso ripartirà dall'inizio. +pageExpiredTitle=La pagina è scaduta +pageExpiredMsg1=Per riavviare il processo di accesso +pageExpiredMsg2=Per continuare il processo di accesso + +# Registration error messages +registerMissingUsername=Specifichi il nome utente. +registerMissingFirstName=Specifichi il nome. +registerMissingLastName=Specifichi il cognome. +registerMissingEmail=Specifichi l'email. +registerMissingPassword=Specifichi la password. +registerMissingPasswordConfirm=Confermi la password. +registerPasswordNotMatch=La conferma della password non corrisponde. +registerInvalidPasswordExisting=Password esistente non valida. +registerInvalidPasswordPattern=Password non valida: deve contenere almeno 8 caratteri, almeno una lettera maiuscola, una minuscola, una cifra e un carattere speciale. +registerUsernameExists=Il nome utente esiste già. +registerEmailExists=L'email esiste già. +registerPasswordConfirmNotMatch=La conferma della password non corrisponde. + +# User profile validation messages (declarative user profile / VERIFY_PROFILE) +error-user-attribute-required=Specifichi questo campo. +error-invalid-blank=Specifichi un valore. +error-invalid-email=Indirizzo email non valido. +error-invalid-length=La lunghezza deve essere compresa tra {1} e {2}. + +# Generic error messages +unexpectedErrorTitle=Si è verificato un errore imprevisto +unexpectedErrorTitleHtml=Si è verificato un errore imprevisto +backToApplication=« Torna all'applicazione +missingParameter=Parametro mancante: {0} +missingParameterMessage=Parametri mancanti: {0} +invalidRequest=Richiesta non valida +invalidParameter=Parametro non valido +invalidParameterValue=Valore del parametro non valido per ''{0}'' +invalidParameterMessage=Parametro non valido: {0} +clientNotFound=Client non trovato. +clientNotFoundMessage=Client non trovato. +invalidCode=Codice non valido. +invalidGrant=Concessione non valida. +invalidToken=Token non valido. +accessDenied=Accesso negato. +httpsRequiredMessage=HTTPS richiesto +realmNotEnabledMessage=Realm non abilitato +invalidRequestMessage=Richiesta non valida +unknownLoginRequesterMessage=Richiedente di accesso sconosciuto +loginRequesterNotEnabledMessage=Richiedente di accesso non abilitato +bearerOnlyMessage=Le applicazioni Bearer-only non sono autorizzate ad avviare l'accesso tramite browser +standardFlowDisabledMessage=Il client non è autorizzato ad avviare l'accesso tramite browser con il response_type indicato. Il flusso standard è disabilitato per il client. +invalidRedirectUriMessage=URI di reindirizzamento non valido +registrationNotAllowedMessage=Registrazione non consentita +resetCredentialNotAllowedMessage=Reimpostazione delle credenziali non consentita + +# Logout +logoutTitle=Disconnessione in corso +logoutConfirmTitle=È sicuro di voler uscire? +logoutConfirmHeader=Disconnessione in corso +logoutConfirmationMessage=Verrà disconnesso da Open Bank Project e da tutte le applicazioni connesse. +doLogout=Esci + +# Account pages +accountManagementTitle=Gestione dell'account Open Bank Project +personalInfo=Informazioni personali +accountSecurity=Sicurezza dell'account +applicationsHtml=Applicazioni +linkedAccountsHtml=Account collegati + +# Two-factor authentication +loginTotpIntro=Deve configurare un autenticatore mobile per accedere al Suo account +loginTotpStep1=Installi una delle seguenti applicazioni sul Suo dispositivo mobile +loginTotpStep2=Apra l'applicazione e scansioni il codice a barre +loginTotpStep3=Inserisca il codice monouso fornito dall'applicazione e clicchi su Invia per completare la configurazione +loginTotpManualStep2=Apra l'applicazione e inserisca la chiave +loginTotpManualStep3=Utilizzi i seguenti valori di configurazione +loginTotpUnableToScan=Impossibile effettuare la scansione? +loginTotpScanBarcode=Scansionare il codice a barre? +loginCredential=Credenziale + +# Social login +loginTitleHtml=Accedi a Open Bank Project +loginIdpReviewProfileTitle=Aggiorna le informazioni dell'account +loginIdpReviewProfileInfo=Verifichi le informazioni del Suo account recuperate da {0} + +# Application permissions +clientScopeRole.openid=OpenID Connect built-in scope: openid +clientScopeRole.email=OpenID Connect built-in scope: email +clientScopeRole.profile=OpenID Connect built-in scope: profile +clientScopeRole.address=OpenID Connect built-in scope: address +clientScopeRole.phone=OpenID Connect built-in scope: phone +clientScopeRole.offline_access=OpenID Connect built-in scope: offline_access + +# Custom OBP-specific messages +obpWelcome=Benvenuto in Open Bank Project +obpDescription=La principale piattaforma API open source per le banche +obpSecureLogin=Accesso sicuro fornito da Keycloak +obpSupport=Ha bisogno di aiuto? Contatti il nostro team di assistenza +obpPrivacy=La Sua privacy e sicurezza sono la nostra priorità +obpCopyright=© 2011-2025 TESOBE. Tutti i diritti riservati. + +# Show/Hide password +showPassword=Mostra password +hidePassword=Nascondi password + +# Additional standard Keycloak messages for complete coverage +alreadyLoggedIn=Ha già effettuato l'accesso. +differentUserAuthenticated=In questa sessione si è già autenticato come utente diverso ''{0}''. Effettui prima la disconnessione. +cookieNotFoundMessage=Cookie di riavvio dell'accesso non trovato. Potrebbe essere scaduto, essere stato eliminato oppure i cookie sono disabilitati nel Suo browser. +staleCodeMessage=Questa pagina non è più valida, torni alla Sua applicazione ed effettui nuovamente l'accesso +emailSentMessage=Dovrebbe ricevere a breve un'email con ulteriori istruzioni. +emailSendErrorMessage=Invio dell'email non riuscito, riprovi più tardi. + +# Identity provider login +identity-provider-login-label=Oppure accedi con + +# Additional security messages +loginRecoveryKeyTitle=Configurazione della chiave di recupero +loginRecoveryKeyInstruction=Annoti questa chiave di recupero e la conservi in un luogo sicuro. Potrà utilizzarla per recuperare il Suo account in caso di perdita dell'accesso all'autenticatore. +loginBackupCodesTitle=Codici di backup +loginBackupCodesInstruction=Annoti questi codici di backup e li conservi in un luogo sicuro. Ogni codice può essere utilizzato una sola volta. + +# WebAuthn messages +webauthnTitle=Chiave di sicurezza +webauthnInstruction=Tocchi la Sua chiave di sicurezza +webauthnErrorTitle=Errore della chiave di sicurezza +webauthnUnsupported=Le chiavi di sicurezza non sono supportate da questo browser. diff --git a/themes/obp/login/messages/messages_ja.properties b/themes/obp/login/messages/messages_ja.properties new file mode 100644 index 0000000..b875d6a --- /dev/null +++ b/themes/obp/login/messages/messages_ja.properties @@ -0,0 +1,227 @@ +# OBP Keycloak Theme - English Messages +# Open Bank Project branding and improved user experience + +# Login page +loginTitle=Open Bank Project にサインイン +loginTitleHtml=Open Bank Project にサインイン +usernameOrEmail=ユーザー名またはメールアドレス +username=ユーザー名 +email=メールアドレス +password=パスワード +loginUsername=ユーザー名またはメールアドレス +loginPassword=パスワード +loginRememberMe=ログイン状態を保持する +doLogIn=サインイン +loginSubmit=サインイン +doForgotPassword=パスワードをお忘れですか? +loginForgotPassword=パスワードをお忘れですか? +loginNoAccount=新規ユーザーですか? +doRegister=アカウントを作成 +loginRegister=アカウントを作成 +loginTotpTitle=モバイル認証アプリの設定 +loginProfileTitle=アカウント情報の更新 +loginTimeout=ログイン試行がタイムアウトしました。ログインは最初からやり直しになります。 + +# Update profile page (VERIFY_PROFILE required action) — field labels and buttons. +# Defined here because this theme's bundle does not inherit them from the base theme. +firstName=名 +lastName=姓 +doSubmit=送信 +doCancel=キャンセル + +# OAuth grant page +oauthGrantTitle={0} へのアクセスを許可 +oauthGrantInformation=アクセスを許可すると、{0} があなたの Open Bank Project アカウント情報にアクセスできるようになります。 + +# Registration page +registerTitle=Open Bank Project への登録 +registerSubmit=登録 +registerWithTitle=または次で登録 +registerUsername=ユーザー名 +registerEmail=メールアドレス +registerFirstName=名 +registerLastName=姓 +registerPassword=パスワード +registerPasswordConfirm=パスワードの確認 +registerAlreadyHaveAccount=すでにアカウントをお持ちですか? +registerBackToLogin=« ログインに戻る + +# Password reset +resetPasswordTitle=パスワードをお忘れですか? +resetPasswordInstruction=ユーザー名またはメールアドレスを入力してください。新しいパスワードの作成方法をご案内します。 +resetPasswordSubmit=送信 +resetPasswordBackToLogin=« ログインに戻る + +# Update password +updatePasswordTitle=パスワードの更新 +updatePasswordInstruction=Open Bank Project アカウントの新しいパスワードを作成してください。 +updatePasswordNewPassword=新しいパスワード +updatePasswordConfirmPassword=新しいパスワードの確認 +updatePasswordSubmit=送信 + +# Verify email +verifyEmailTitle=メールアドレスの確認 +verifyEmailInstruction=メールアドレスを確認するための手順を記載したメールをお送りしました。 +verifyEmailInstructionHtml=メールアドレスを確認するための手順を記載したメールを {0} にお送りしました。 +verifyEmailNoReceived=確認コードのメールが届きませんでしたか? +verifyEmailResendInstruction=以下のリンクをクリックしてメールを再送信してください。 +verifyEmailResend=メールを再送信 + +# Terms and conditions +termsTitle=利用規約 +termsText=Open Bank Project の利用規約は今後定められます。 +termsPlainText=Open Bank Project の利用規約は今後定められます。 +acceptTerms=利用規約に同意します + +# Error messages +invalidUserMessage=ユーザー名またはパスワードが正しくありません。 +invalidUsernameMessage=ユーザー名が正しくありません。 +invalidUsernameOrEmailMessage=ユーザー名またはメールアドレスが正しくありません。 +invalidPasswordMessage=パスワードが正しくありません。 +invalidEmailMessage=メールアドレスが正しくありません。 +loginInvalidCredentials=ユーザー名またはパスワードが正しくありません。 +loginAccountDisabled=アカウントが無効になっています。管理者にお問い合わせください。 +loginAccountTemporarilyDisabled=アカウントが一時的に無効になっています。管理者にお問い合わせいただくか、後ほど再度お試しください。 +accountDisabledMessage=アカウントが無効になっています。管理者にお問い合わせください。 +accountTemporarilyDisabledMessage=ユーザー名またはパスワードが正しくありません。 +accountPermanentlyDisabledMessage=ユーザー名またはパスワードが正しくありません。 +loginInvalidTotp=認証コードが正しくありません。 +invalidTotpMessage=認証コードが正しくありません。 +loginMissingUsername=ユーザー名を入力してください。 +loginMissingPassword=パスワードを入力してください。 +loginMissingTotp=認証コードを入力してください。 +missingUsernameMessage=ユーザー名を入力してください。 +missingPasswordMessage=パスワードを入力してください。 +missingTotpMessage=認証コードを入力してください。 +expiredCodeMessage=ログインがタイムアウトしました。もう一度サインインしてください。 +expiredActionMessage=操作の有効期限が切れました。このままログインを続けてください。 +sessionNotActiveMessage=セッションが有効ではありません。 +invalidCodeMessage=エラーが発生しました。お使いのアプリケーションから再度ログインしてください。 +noAccount=新規ユーザーですか? +loginAccountTitle=アカウントにサインイン +loginTitle={0} にサインイン +loginTitleHtml={0} +loginTimeout=ログイン試行がタイムアウトしました。ログインは最初からやり直しになります。 +pageExpiredTitle=ページの有効期限が切れました +pageExpiredMsg1=ログイン処理を最初からやり直すには +pageExpiredMsg2=ログイン処理を続けるには + +# Registration error messages +registerMissingUsername=ユーザー名を入力してください。 +registerMissingFirstName=名を入力してください。 +registerMissingLastName=姓を入力してください。 +registerMissingEmail=メールアドレスを入力してください。 +registerMissingPassword=パスワードを入力してください。 +registerMissingPasswordConfirm=パスワードを確認してください。 +registerPasswordNotMatch=パスワードの確認が一致しません。 +registerInvalidPasswordExisting=現在のパスワードが正しくありません。 +registerInvalidPasswordPattern=パスワードが正しくありません。8文字以上で、大文字、小文字、数字、特殊文字をそれぞれ1文字以上含める必要があります。 +registerUsernameExists=このユーザー名はすでに使用されています。 +registerEmailExists=このメールアドレスはすでに使用されています。 +registerPasswordConfirmNotMatch=パスワードの確認が一致しません。 + +# User profile validation messages (declarative user profile / VERIFY_PROFILE) +error-user-attribute-required=この項目を入力してください。 +error-invalid-blank=値を入力してください。 +error-invalid-email=メールアドレスが正しくありません。 +error-invalid-length=長さは {1} から {2} の間でなければなりません。 + +# Generic error messages +unexpectedErrorTitle=予期しないエラーが発生しました +unexpectedErrorTitleHtml=予期しないエラーが発生しました +backToApplication=« アプリケーションに戻る +missingParameter=不足しているパラメーター: {0} +missingParameterMessage=不足しているパラメーター: {0} +invalidRequest=無効なリクエストです +invalidParameter=無効なパラメーターです +invalidParameterValue=''{0}'' のパラメーター値が無効です +invalidParameterMessage=無効なパラメーター: {0} +clientNotFound=クライアントが見つかりません。 +clientNotFoundMessage=クライアントが見つかりません。 +invalidCode=無効なコードです。 +invalidGrant=無効な許可です。 +invalidToken=無効なトークンです。 +accessDenied=アクセスが拒否されました。 +httpsRequiredMessage=HTTPS が必要です +realmNotEnabledMessage=Realm が有効になっていません +invalidRequestMessage=無効なリクエストです +unknownLoginRequesterMessage=不明なログイン要求元です +loginRequesterNotEnabledMessage=ログイン要求元が有効になっていません +bearerOnlyMessage=Bearer-only アプリケーションはブラウザログインを開始できません +standardFlowDisabledMessage=クライアントは指定された response_type でブラウザログインを開始できません。このクライアントでは標準フローが無効になっています。 +invalidRedirectUriMessage=無効なリダイレクト URI です +registrationNotAllowedMessage=登録は許可されていません +resetCredentialNotAllowedMessage=認証情報のリセットは許可されていません + +# Logout +logoutTitle=サインアウト中 +logoutConfirmTitle=サインアウトしてもよろしいですか? +logoutConfirmHeader=サインアウト中 +logoutConfirmationMessage=Open Bank Project および接続されているすべてのアプリケーションからサインアウトされます。 +doLogout=サインアウト + +# Account pages +accountManagementTitle=Open Bank Project アカウント管理 +personalInfo=個人情報 +accountSecurity=アカウントのセキュリティ +applicationsHtml=アプリケーション +linkedAccountsHtml=連携アカウント + +# Two-factor authentication +loginTotpIntro=アカウントにアクセスするにはモバイル認証アプリの設定が必要です +loginTotpStep1=以下のいずれかのアプリケーションをモバイル端末にインストールしてください +loginTotpStep2=アプリケーションを開いてバーコードをスキャンしてください +loginTotpStep3=アプリケーションが表示するワンタイムコードを入力し、「送信」をクリックして設定を完了してください +loginTotpManualStep2=アプリケーションを開いてキーを入力してください +loginTotpManualStep3=以下の設定値を使用してください +loginTotpUnableToScan=スキャンできませんか? +loginTotpScanBarcode=バーコードをスキャンしますか? +loginCredential=認証情報 + +# Social login +loginTitleHtml=Open Bank Project にサインイン +loginIdpReviewProfileTitle=アカウント情報の更新 +loginIdpReviewProfileInfo={0} から取得したアカウント情報をご確認ください + +# Application permissions +clientScopeRole.openid=OpenID Connect 組み込みスコープ: openid +clientScopeRole.email=OpenID Connect 組み込みスコープ: email +clientScopeRole.profile=OpenID Connect 組み込みスコープ: profile +clientScopeRole.address=OpenID Connect 組み込みスコープ: address +clientScopeRole.phone=OpenID Connect 組み込みスコープ: phone +clientScopeRole.offline_access=OpenID Connect 組み込みスコープ: offline_access + +# Custom OBP-specific messages +obpWelcome=Open Bank Project へようこそ +obpDescription=銀行向けの主要なオープンソース API プラットフォーム +obpSecureLogin=Keycloak による安全なログイン +obpSupport=お困りですか?サポートチームにお問い合わせください +obpPrivacy=お客様のプライバシーとセキュリティを最優先します +obpCopyright=© 2011-2025 TESOBE. All rights reserved. + +# Show/Hide password +showPassword=パスワードを表示 +hidePassword=パスワードを非表示 + +# Additional standard Keycloak messages for complete coverage +alreadyLoggedIn=すでにログインしています。 +differentUserAuthenticated=このセッションでは、すでに別のユーザー ''{0}'' として認証されています。先にサインアウトしてください。 +cookieNotFoundMessage=ログイン再開用の Cookie が見つかりません。有効期限が切れたか、削除されたか、ブラウザで Cookie が無効になっている可能性があります。 +staleCodeMessage=このページは有効ではなくなりました。お使いのアプリケーションに戻って、もう一度サインインしてください +emailSentMessage=まもなく詳しい手順を記載したメールが届きます。 +emailSendErrorMessage=メールの送信に失敗しました。後ほど再度お試しください。 + +# Identity provider login +identity-provider-login-label=または次でサインイン + +# Additional security messages +loginRecoveryKeyTitle=リカバリーキーの設定 +loginRecoveryKeyInstruction=このリカバリーキーを書き留めて、安全な場所に保管してください。認証アプリにアクセスできなくなった場合に、アカウントを復旧するために使用できます。 +loginBackupCodesTitle=バックアップコード +loginBackupCodesInstruction=これらのバックアップコードを書き留めて、安全な場所に保管してください。各コードは一度しか使用できません。 + +# WebAuthn messages +webauthnTitle=セキュリティキー +webauthnInstruction=セキュリティキーにタッチしてください +webauthnErrorTitle=セキュリティキーのエラー +webauthnUnsupported=このブラウザはセキュリティキーに対応していません。 diff --git a/themes/obp/login/messages/messages_pt.properties b/themes/obp/login/messages/messages_pt.properties new file mode 100644 index 0000000..46c1026 --- /dev/null +++ b/themes/obp/login/messages/messages_pt.properties @@ -0,0 +1,227 @@ +# OBP Keycloak Theme - English Messages +# Open Bank Project branding and improved user experience + +# Login page +loginTitle=Iniciar sessão no Open Bank Project +loginTitleHtml=Iniciar sessão no Open Bank Project +usernameOrEmail=Nome de utilizador ou email +username=Nome de utilizador +email=Email +password=Palavra-passe +loginUsername=Nome de utilizador ou email +loginPassword=Palavra-passe +loginRememberMe=Memorizar-me +doLogIn=Iniciar sessão +loginSubmit=Iniciar sessão +doForgotPassword=Esqueceu-se da palavra-passe? +loginForgotPassword=Esqueceu-se da palavra-passe? +loginNoAccount=Novo utilizador? +doRegister=Criar uma conta +loginRegister=Criar uma conta +loginTotpTitle=Configuração do Autenticador Móvel +loginProfileTitle=Atualizar Informações da Conta +loginTimeout=A sua tentativa de início de sessão expirou. O início de sessão recomeçará do princípio. + +# Update profile page (VERIFY_PROFILE required action) — field labels and buttons. +# Defined here because this theme's bundle does not inherit them from the base theme. +firstName=Nome próprio +lastName=Apelido +doSubmit=Submeter +doCancel=Cancelar + +# OAuth grant page +oauthGrantTitle=Conceder Acesso a {0} +oauthGrantInformation=Ao conceder acesso, permite que {0} aceda às informações da sua conta do Open Bank Project. + +# Registration page +registerTitle=Registar no Open Bank Project +registerSubmit=Registar +registerWithTitle=Ou registar com +registerUsername=Nome de utilizador +registerEmail=Email +registerFirstName=Nome próprio +registerLastName=Apelido +registerPassword=Palavra-passe +registerPasswordConfirm=Confirmar palavra-passe +registerAlreadyHaveAccount=Já tem uma conta? +registerBackToLogin=« Voltar ao Início de Sessão + +# Password reset +resetPasswordTitle=Esqueceu-se da Palavra-passe? +resetPasswordInstruction=Introduza o seu nome de utilizador ou endereço de email e enviar-lhe-emos instruções sobre como criar uma nova palavra-passe. +resetPasswordSubmit=Submeter +resetPasswordBackToLogin=« Voltar ao Início de Sessão + +# Update password +updatePasswordTitle=Atualizar Palavra-passe +updatePasswordInstruction=Crie uma nova palavra-passe para a sua conta do Open Bank Project. +updatePasswordNewPassword=Nova Palavra-passe +updatePasswordConfirmPassword=Confirmar Nova Palavra-passe +updatePasswordSubmit=Submeter + +# Verify email +verifyEmailTitle=Verificação de email +verifyEmailInstruction=Foi-lhe enviado um email com instruções para verificar o seu endereço de email. +verifyEmailInstructionHtml=Foi enviado um email com instruções para verificar o seu endereço de email para {0}. +verifyEmailNoReceived=Não recebeu um código de verificação no seu email? +verifyEmailResendInstruction=Clique na ligação abaixo para reenviar o email. +verifyEmailResend=Reenviar Email + +# Terms and conditions +termsTitle=Termos e Condições +termsText=Termos e condições a definir para o Open Bank Project. +termsPlainText=Termos e condições a definir para o Open Bank Project. +acceptTerms=Aceito os Termos e Condições + +# Error messages +invalidUserMessage=Nome de utilizador ou palavra-passe inválidos. +invalidUsernameMessage=Nome de utilizador inválido. +invalidUsernameOrEmailMessage=Nome de utilizador ou email inválidos. +invalidPasswordMessage=Palavra-passe inválida. +invalidEmailMessage=Endereço de email inválido. +loginInvalidCredentials=Nome de utilizador ou palavra-passe inválidos. +loginAccountDisabled=A conta está desativada, contacte o seu administrador. +loginAccountTemporarilyDisabled=A conta está temporariamente desativada, contacte o seu administrador ou tente novamente mais tarde. +accountDisabledMessage=A conta está desativada, contacte o seu administrador. +accountTemporarilyDisabledMessage=Nome de utilizador ou palavra-passe inválidos. +accountPermanentlyDisabledMessage=Nome de utilizador ou palavra-passe inválidos. +loginInvalidTotp=Código do autenticador inválido. +invalidTotpMessage=Código do autenticador inválido. +loginMissingUsername=Indique o nome de utilizador. +loginMissingPassword=Indique a palavra-passe. +loginMissingTotp=Indique o código do autenticador. +missingUsernameMessage=Indique o nome de utilizador. +missingPasswordMessage=Indique a palavra-passe. +missingTotpMessage=Indique o código do autenticador. +expiredCodeMessage=Tempo de início de sessão esgotado. Inicie sessão novamente. +expiredActionMessage=A ação expirou. Continue agora com o início de sessão. +sessionNotActiveMessage=Sessão não ativa. +invalidCodeMessage=Ocorreu um erro, inicie sessão novamente através da sua aplicação. +noAccount=Novo utilizador? +loginAccountTitle=Iniciar sessão na sua conta +loginTitle=Iniciar sessão em {0} +loginTitleHtml={0} +loginTimeout=A sua tentativa de início de sessão expirou. O início de sessão recomeçará do princípio. +pageExpiredTitle=A página expirou +pageExpiredMsg1=Para reiniciar o processo de início de sessão +pageExpiredMsg2=Para continuar o processo de início de sessão + +# Registration error messages +registerMissingUsername=Indique o nome de utilizador. +registerMissingFirstName=Indique o nome próprio. +registerMissingLastName=Indique o apelido. +registerMissingEmail=Indique o email. +registerMissingPassword=Indique a palavra-passe. +registerMissingPasswordConfirm=Confirme a palavra-passe. +registerPasswordNotMatch=A confirmação da palavra-passe não coincide. +registerInvalidPasswordExisting=Palavra-passe existente inválida. +registerInvalidPasswordPattern=Palavra-passe inválida: deve conter pelo menos 8 caracteres, pelo menos uma maiúscula, uma minúscula, um dígito e um carácter especial. +registerUsernameExists=O nome de utilizador já existe. +registerEmailExists=O email já existe. +registerPasswordConfirmNotMatch=A confirmação da palavra-passe não coincide. + +# User profile validation messages (declarative user profile / VERIFY_PROFILE) +error-user-attribute-required=Indique este campo. +error-invalid-blank=Indique um valor. +error-invalid-email=Endereço de email inválido. +error-invalid-length=O comprimento deve estar entre {1} e {2}. + +# Generic error messages +unexpectedErrorTitle=Ocorreu um erro inesperado +unexpectedErrorTitleHtml=Ocorreu um erro inesperado +backToApplication=« Voltar à aplicação +missingParameter=Parâmetro em falta: {0} +missingParameterMessage=Parâmetros em falta: {0} +invalidRequest=Pedido inválido +invalidParameter=Parâmetro inválido +invalidParameterValue=Valor de parâmetro inválido para ''{0}'' +invalidParameterMessage=Parâmetro inválido: {0} +clientNotFound=Cliente não encontrado. +clientNotFoundMessage=Cliente não encontrado. +invalidCode=Código inválido. +invalidGrant=Concessão inválida. +invalidToken=Token inválido. +accessDenied=Acesso negado. +httpsRequiredMessage=HTTPS obrigatório +realmNotEnabledMessage=Realm não ativado +invalidRequestMessage=Pedido Inválido +unknownLoginRequesterMessage=Requerente de início de sessão desconhecido +loginRequesterNotEnabledMessage=Requerente de início de sessão não ativado +bearerOnlyMessage=As aplicações Bearer-only não estão autorizadas a iniciar o início de sessão no navegador +standardFlowDisabledMessage=O cliente não está autorizado a iniciar o início de sessão no navegador com o response_type fornecido. O fluxo padrão está desativado para o cliente. +invalidRedirectUriMessage=URI de redirecionamento inválido +registrationNotAllowedMessage=Registo não permitido +resetCredentialNotAllowedMessage=Reposição de Credencial não permitida + +# Logout +logoutTitle=A terminar sessão +logoutConfirmTitle=Tem a certeza de que pretende terminar sessão? +logoutConfirmHeader=A terminar sessão +logoutConfirmationMessage=A sua sessão será terminada no Open Bank Project e em todas as aplicações ligadas. +doLogout=Terminar sessão + +# Account pages +accountManagementTitle=Gestão de Conta do Open Bank Project +personalInfo=Informações pessoais +accountSecurity=Segurança da conta +applicationsHtml=Aplicações +linkedAccountsHtml=Contas associadas + +# Two-factor authentication +loginTotpIntro=Precisa de configurar um Autenticador Móvel para aceder à sua conta +loginTotpStep1=Instale uma das seguintes aplicações no seu dispositivo móvel +loginTotpStep2=Abra a aplicação e leia o código de barras +loginTotpStep3=Introduza o código de uso único fornecido pela aplicação e clique em Submeter para concluir a configuração +loginTotpManualStep2=Abra a aplicação e introduza a chave +loginTotpManualStep3=Utilize os seguintes valores de configuração +loginTotpUnableToScan=Não consegue ler o código? +loginTotpScanBarcode=Ler código de barras? +loginCredential=Credencial + +# Social login +loginTitleHtml=Iniciar sessão no Open Bank Project +loginIdpReviewProfileTitle=Atualizar Informações da Conta +loginIdpReviewProfileInfo=Reveja as informações da sua conta obtidas de {0} + +# Application permissions +clientScopeRole.openid=Âmbito incorporado do OpenID Connect: openid +clientScopeRole.email=Âmbito incorporado do OpenID Connect: email +clientScopeRole.profile=Âmbito incorporado do OpenID Connect: profile +clientScopeRole.address=Âmbito incorporado do OpenID Connect: address +clientScopeRole.phone=Âmbito incorporado do OpenID Connect: phone +clientScopeRole.offline_access=Âmbito incorporado do OpenID Connect: offline_access + +# Custom OBP-specific messages +obpWelcome=Bem-vindo ao Open Bank Project +obpDescription=A principal plataforma de API de código aberto para bancos +obpSecureLogin=Início de sessão seguro com tecnologia Keycloak +obpSupport=Precisa de ajuda? Contacte a nossa equipa de apoio +obpPrivacy=A sua privacidade e segurança são a nossa prioridade +obpCopyright=© 2011-2025 TESOBE. Todos os direitos reservados. + +# Show/Hide password +showPassword=Mostrar palavra-passe +hidePassword=Ocultar palavra-passe + +# Additional standard Keycloak messages for complete coverage +alreadyLoggedIn=A sua sessão já está iniciada. +differentUserAuthenticated=A sua sessão já está autenticada como um utilizador diferente ''{0}''. Termine primeiro a sessão. +cookieNotFoundMessage=Cookie de reinício de início de sessão não encontrado. Pode ter expirado; pode ter sido eliminado ou os cookies estão desativados no seu navegador. +staleCodeMessage=Esta página já não é válida, volte à sua aplicação e inicie sessão novamente +emailSentMessage=Deverá receber em breve um email com mais instruções. +emailSendErrorMessage=Falha ao enviar o email, tente novamente mais tarde. + +# Identity provider login +identity-provider-login-label=Ou iniciar sessão com + +# Additional security messages +loginRecoveryKeyTitle=Configuração da Chave de Recuperação +loginRecoveryKeyInstruction=Anote esta chave de recuperação e guarde-a num local seguro. Pode utilizá-la para recuperar a sua conta caso perca o acesso ao seu autenticador. +loginBackupCodesTitle=Códigos de Recuperação +loginBackupCodesInstruction=Anote estes códigos de recuperação e guarde-os num local seguro. Cada código só pode ser utilizado uma vez. + +# WebAuthn messages +webauthnTitle=Chave de Segurança +webauthnInstruction=Toque na sua chave de segurança +webauthnErrorTitle=Erro da Chave de Segurança +webauthnUnsupported=As chaves de segurança não são suportadas por este navegador. diff --git a/themes/obp/login/messages/messages_zh_CN.properties b/themes/obp/login/messages/messages_zh_CN.properties new file mode 100644 index 0000000..e42a4c7 --- /dev/null +++ b/themes/obp/login/messages/messages_zh_CN.properties @@ -0,0 +1,227 @@ +# OBP Keycloak Theme - English Messages +# Open Bank Project branding and improved user experience + +# Login page +loginTitle=登录 Open Bank Project +loginTitleHtml=登录 Open Bank Project +usernameOrEmail=用户名或电子邮箱 +username=用户名 +email=电子邮箱 +password=密码 +loginUsername=用户名或电子邮箱 +loginPassword=密码 +loginRememberMe=记住我 +doLogIn=登录 +loginSubmit=登录 +doForgotPassword=忘记密码? +loginForgotPassword=忘记密码? +loginNoAccount=新用户? +doRegister=创建账户 +loginRegister=创建账户 +loginTotpTitle=移动验证器设置 +loginProfileTitle=更新账户信息 +loginTimeout=您的登录尝试已超时。登录将从头开始。 + +# Update profile page (VERIFY_PROFILE required action) — field labels and buttons. +# Defined here because this theme's bundle does not inherit them from the base theme. +firstName=名字 +lastName=姓氏 +doSubmit=提交 +doCancel=取消 + +# OAuth grant page +oauthGrantTitle=授予 {0} 访问权限 +oauthGrantInformation=授予访问权限后,您允许 {0} 访问您的 Open Bank Project 账户信息。 + +# Registration page +registerTitle=注册 Open Bank Project +registerSubmit=注册 +registerWithTitle=或使用以下方式注册 +registerUsername=用户名 +registerEmail=电子邮箱 +registerFirstName=名字 +registerLastName=姓氏 +registerPassword=密码 +registerPasswordConfirm=确认密码 +registerAlreadyHaveAccount=已有账户? +registerBackToLogin=« 返回登录 + +# Password reset +resetPasswordTitle=忘记密码? +resetPasswordInstruction=请输入您的用户名或电子邮箱地址,我们将向您发送如何创建新密码的说明。 +resetPasswordSubmit=提交 +resetPasswordBackToLogin=« 返回登录 + +# Update password +updatePasswordTitle=更新密码 +updatePasswordInstruction=请为您的 Open Bank Project 账户创建新密码。 +updatePasswordNewPassword=新密码 +updatePasswordConfirmPassword=确认新密码 +updatePasswordSubmit=提交 + +# Verify email +verifyEmailTitle=电子邮箱验证 +verifyEmailInstruction=一封包含验证电子邮箱地址说明的邮件已发送给您。 +verifyEmailInstructionHtml=一封包含验证电子邮箱地址说明的邮件已发送至 {0}。 +verifyEmailNoReceived=没有在您的邮箱中收到验证码? +verifyEmailResendInstruction=点击下面的链接重新发送邮件。 +verifyEmailResend=重新发送邮件 + +# Terms and conditions +termsTitle=条款与条件 +termsText=Open Bank Project 的条款与条件待定义。 +termsPlainText=Open Bank Project 的条款与条件待定义。 +acceptTerms=我接受条款与条件 + +# Error messages +invalidUserMessage=用户名或密码无效。 +invalidUsernameMessage=用户名无效。 +invalidUsernameOrEmailMessage=用户名或电子邮箱无效。 +invalidPasswordMessage=密码无效。 +invalidEmailMessage=电子邮箱地址无效。 +loginInvalidCredentials=用户名或密码无效。 +loginAccountDisabled=账户已被禁用,请联系您的管理员。 +loginAccountTemporarilyDisabled=账户已被临时禁用,请联系您的管理员或稍后重试。 +accountDisabledMessage=账户已被禁用,请联系您的管理员。 +accountTemporarilyDisabledMessage=用户名或密码无效。 +accountPermanentlyDisabledMessage=用户名或密码无效。 +loginInvalidTotp=验证器代码无效。 +invalidTotpMessage=验证器代码无效。 +loginMissingUsername=请输入用户名。 +loginMissingPassword=请输入密码。 +loginMissingTotp=请输入验证器代码。 +missingUsernameMessage=请输入用户名。 +missingPasswordMessage=请输入密码。 +missingTotpMessage=请输入验证器代码。 +expiredCodeMessage=登录超时。请重新登录。 +expiredActionMessage=操作已过期。请立即继续登录。 +sessionNotActiveMessage=会话未激活。 +invalidCodeMessage=发生错误,请通过您的应用程序重新登录。 +noAccount=新用户? +loginAccountTitle=登录您的账户 +loginTitle=登录 {0} +loginTitleHtml={0} +loginTimeout=您的登录尝试已超时。登录将从头开始。 +pageExpiredTitle=页面已过期 +pageExpiredMsg1=重新开始登录流程 +pageExpiredMsg2=继续登录流程 + +# Registration error messages +registerMissingUsername=请输入用户名。 +registerMissingFirstName=请输入名字。 +registerMissingLastName=请输入姓氏。 +registerMissingEmail=请输入电子邮箱。 +registerMissingPassword=请输入密码。 +registerMissingPasswordConfirm=请确认密码。 +registerPasswordNotMatch=密码确认不匹配。 +registerInvalidPasswordExisting=现有密码无效。 +registerInvalidPasswordPattern=密码无效:必须至少包含 8 个字符,至少一个大写字母、一个小写字母、一个数字和一个特殊字符。 +registerUsernameExists=用户名已存在。 +registerEmailExists=电子邮箱已存在。 +registerPasswordConfirmNotMatch=密码确认不匹配。 + +# User profile validation messages (declarative user profile / VERIFY_PROFILE) +error-user-attribute-required=请填写此字段。 +error-invalid-blank=请输入值。 +error-invalid-email=电子邮箱地址无效。 +error-invalid-length=长度必须介于 {1} 和 {2} 之间。 + +# Generic error messages +unexpectedErrorTitle=发生了意外错误 +unexpectedErrorTitleHtml=发生了意外错误 +backToApplication=« 返回应用程序 +missingParameter=缺少参数:{0} +missingParameterMessage=缺少参数:{0} +invalidRequest=请求无效 +invalidParameter=参数无效 +invalidParameterValue=''{0}'' 的参数值无效 +invalidParameterMessage=参数无效:{0} +clientNotFound=未找到客户端。 +clientNotFoundMessage=未找到客户端。 +invalidCode=代码无效。 +invalidGrant=授权无效。 +invalidToken=令牌无效。 +accessDenied=访问被拒绝。 +httpsRequiredMessage=需要 HTTPS +realmNotEnabledMessage=Realm 未启用 +invalidRequestMessage=请求无效 +unknownLoginRequesterMessage=未知的登录请求方 +loginRequesterNotEnabledMessage=登录请求方未启用 +bearerOnlyMessage=Bearer-only 应用程序不允许发起浏览器登录 +standardFlowDisabledMessage=客户端不允许使用给定的 response_type 发起浏览器登录。该客户端已禁用标准流程。 +invalidRedirectUriMessage=重定向 URI 无效 +registrationNotAllowedMessage=不允许注册 +resetCredentialNotAllowedMessage=不允许重置凭据 + +# Logout +logoutTitle=正在退出登录 +logoutConfirmTitle=您确定要退出登录吗? +logoutConfirmHeader=正在退出登录 +logoutConfirmationMessage=您将退出 Open Bank Project 及所有已连接的应用程序。 +doLogout=退出登录 + +# Account pages +accountManagementTitle=Open Bank Project 账户管理 +personalInfo=个人信息 +accountSecurity=账户安全 +applicationsHtml=应用程序 +linkedAccountsHtml=关联账户 + +# Two-factor authentication +loginTotpIntro=您需要设置移动验证器才能访问您的账户 +loginTotpStep1=在您的手机上安装以下应用程序之一 +loginTotpStep2=打开应用程序并扫描条形码 +loginTotpStep3=输入应用程序提供的一次性代码,然后点击"提交"完成设置 +loginTotpManualStep2=打开应用程序并输入密钥 +loginTotpManualStep3=使用以下配置值 +loginTotpUnableToScan=无法扫描? +loginTotpScanBarcode=扫描条形码? +loginCredential=凭据 + +# Social login +loginTitleHtml=登录 Open Bank Project +loginIdpReviewProfileTitle=更新账户信息 +loginIdpReviewProfileInfo=请查看从 {0} 检索到的账户信息 + +# Application permissions +clientScopeRole.openid=OpenID Connect 内置范围:openid +clientScopeRole.email=OpenID Connect 内置范围:email +clientScopeRole.profile=OpenID Connect 内置范围:profile +clientScopeRole.address=OpenID Connect 内置范围:address +clientScopeRole.phone=OpenID Connect 内置范围:phone +clientScopeRole.offline_access=OpenID Connect 内置范围:offline_access + +# Custom OBP-specific messages +obpWelcome=欢迎使用 Open Bank Project +obpDescription=面向银行的领先开源 API 平台 +obpSecureLogin=由 Keycloak 提供支持的安全登录 +obpSupport=需要帮助?请联系我们的支持团队 +obpPrivacy=您的隐私和安全是我们的首要任务 +obpCopyright=© 2011-2025 TESOBE. All rights reserved. + +# Show/Hide password +showPassword=显示密码 +hidePassword=隐藏密码 + +# Additional standard Keycloak messages for complete coverage +alreadyLoggedIn=您已登录。 +differentUserAuthenticated=在此会话中,您已以其他用户 ''{0}'' 的身份进行身份验证。请先退出登录。 +cookieNotFoundMessage=未找到重新启动登录的 cookie。它可能已过期、已被删除,或您的浏览器已禁用 cookie。 +staleCodeMessage=此页面不再有效,请返回您的应用程序并重新登录 +emailSentMessage=您应该很快会收到一封包含进一步说明的邮件。 +emailSendErrorMessage=邮件发送失败,请稍后重试。 + +# Identity provider login +identity-provider-login-label=或使用以下方式登录 + +# Additional security messages +loginRecoveryKeyTitle=恢复密钥设置 +loginRecoveryKeyInstruction=请记下此恢复密钥并将其存放在安全的地方。如果您无法访问验证器,可以使用它来恢复您的账户。 +loginBackupCodesTitle=备用代码 +loginBackupCodesInstruction=请记下这些备用代码并将其存放在安全的地方。每个代码只能使用一次。 + +# WebAuthn messages +webauthnTitle=安全密钥 +webauthnInstruction=请触摸您的安全密钥 +webauthnErrorTitle=安全密钥错误 +webauthnUnsupported=此浏览器不支持安全密钥。 From f79b7ba8932d8a60f302144412256b46ff666c08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Tue, 2 Jun 2026 12:22:43 +0200 Subject: [PATCH 04/14] docs: add local development onboarding guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add docs/ONBOARDING.md — a fresh-start walkthrough covering prerequisites, creating the Keycloak database, the .env KEYCLOAK_VERSION requirement, deploy, first-login VERIFY_PROFILE prompt, enabling realm i18n, teardown, and a troubleshooting table. Link it from the README documentation section. --- README.md | 1 + docs/ONBOARDING.md | 159 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 docs/ONBOARDING.md diff --git a/README.md b/README.md index 4ecf407..84cd33c 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ Click the [User federation](https://localhost:8443/admin/master/console/#/master ## Documentation +- [docs/ONBOARDING.md](docs/ONBOARDING.md) — local development onboarding (fresh-start guide) - [env.sample](env.sample) — full environment variable reference - [docs/CICD_DEPLOYMENT.md](docs/CICD_DEPLOYMENT.md) — CI/CD deployment guide - [development/README.md](development/README.md) — development scripts documentation diff --git a/docs/ONBOARDING.md b/docs/ONBOARDING.md new file mode 100644 index 0000000..80b2973 --- /dev/null +++ b/docs/ONBOARDING.md @@ -0,0 +1,159 @@ +# Local Development Onboarding + +A step-by-step guide to running the **OBP Keycloak Provider** locally from a fresh +start. Follow it top to bottom the first time; later runs are just step 3. + +## What this is + +A Keycloak User Storage SPI that authenticates users via the **OBP REST API** +instead of a database. Keycloak still needs its *own* PostgreSQL database for +realm/session state — that is separate from anything OBP. Authentication +(username lookup + credential verification) is delegated to OBP over HTTP. + +``` +Host machine Docker container (host network) PostgreSQL (host) + .env, themes/, src/ ---> Keycloak 26.5.x + provider.jar <--> keycloakdb + | authenticates via OBP REST | + | + v + OBP API (:8080) +``` + +--- + +## Prerequisites (install once) + +| Tool | Why | Notes | +|------|-----|-------| +| **Docker** | builds & runs the Keycloak image | daemon must be running | +| **Maven** 3.8.5+ | builds the provider JAR | | +| **JDK 17+** | the provider targets Java 17 | The deploy script auto-detects an installed JDK 17/21 even if your shell default is older (e.g. Java 11) — it just has to be installed. | +| **PostgreSQL** | Keycloak's internal database | local or remote; reachable from the host | +| **git**, **curl** | clone & health checks | `psql` handy but optional | + +--- + +## 1. Start the external services + +### a) PostgreSQL — and create the Keycloak database + +The deploy script **tests** the DB connection but does **not** create the database. +Create the database that `KC_DB_URL` points to (Keycloak builds its own tables inside it): + +```bash +createdb -h localhost -U postgres keycloakdb +# ensure the KC_DB_USERNAME role exists and can connect to keycloakdb +``` + +### b) OBP API + +Have an OBP API instance reachable at `OBP_API_URL` (default `http://localhost:8080`). + +> Keycloak will still **start** without it (the script only warns), but **every login +> fails until OBP is reachable** — authentication is delegated to OBP. The OBP admin +> account in `.env` must hold the roles `CanGetAnyUser`, `CanVerifyUserCredentials` +> (and `CanGetOidcClient`). + +--- + +## 2. Configure `.env` + +```bash +cp env.sample .env +# then edit .env +``` + +> ⚠️ **Gotcha:** the deploy script requires `KEYCLOAK_VERSION`, but `env.sample` does +> not include it. Add it or the run aborts with *"Missing variable: KEYCLOAK_VERSION"*: +> ``` +> KEYCLOAK_VERSION=26.5.3 +> ``` + +Mandatory values to fill in: + +| Variable | Meaning | +|----------|---------| +| `KC_DB_URL` / `KC_DB_USERNAME` / `KC_DB_PASSWORD` | Keycloak's internal Postgres (e.g. `jdbc:postgresql://host.docker.internal:5432/keycloakdb`) | +| `OBP_API_URL` | base URL of the OBP API (no trailing slash) | +| `OBP_API_USERNAME` / `OBP_API_PASSWORD` | OBP admin account with the required roles | +| `OBP_API_CONSUMER_KEY` | consumer key registered in OBP for Direct Login | +| `OBP_AUTHUSER_PROVIDER` | **hard-required** — only users with this `provider` value authenticate | +| `KEYCLOAK_VERSION` | Keycloak base image tag (see gotcha above) | + +Optional: `KEYCLOAK_ADMIN` / `KEYCLOAK_ADMIN_PASSWORD` (default `admin`/`admin`), +ports, `FORGOT_PASSWORD_URL`. See `env.sample` for the full reference. + +--- + +## 3. Deploy + +```bash +./development/run-local-postgres-cicd.sh # standard +./development/run-local-postgres-cicd.sh --themed # keep OBP themes in the image +``` + +The script runs an 8-step pipeline: validate env → test connectivity → Maven build +(Java 17) → stop/remove old container → build image → start → health check. It uses +`--network host`, so Keycloak binds host ports directly. + +### Access + +| URL | Purpose | +|-----|---------| +| `https://localhost:8443/admin` | Admin console | +| `http://localhost:7787` | HTTP | +| `https://localhost:9000/health/ready` | health endpoint | + +Default admin: `admin` / `admin` (unless overridden in `.env`). + +The provider appears under **User federation → `obp-keycloak-provider`**. + +--- + +## 4. First-login notes (fresh database) + +Two things are **runtime state in `keycloakdb`**, not in the repo — a brand-new +database won't have them: + +1. **"Update Account Information" prompt on first admin login.** The bootstrap admin + has no first/last name, so Keycloak 26 forces a one-time profile completion + (`VERIFY_PROFILE`). Just fill in name + email once and you're in permanently. +2. **The login language dropdown is OFF by default.** The theme ships translated + bundles for `en, de, fr, es, it, pt, ja, zh-CN`, but each realm must opt in: + **Realm settings → Localization → Internationalization ON**, select locales, Save. + +--- + +## 5. Manage & tear down + +```bash +./development/manage-container.sh # interactive menu (status, logs, restart, remove) +docker logs -f obp-keycloak-local # follow logs +docker restart obp-keycloak-local # restart (keeps the container's filesystem) +docker rm -f obp-keycloak-local # remove container (Postgres data persists) +``` + +A full reset = remove the container **and** drop/recreate `keycloakdb`. + +--- + +## Troubleshooting + +| Symptom | Cause / fix | +|---------|-------------| +| `Missing variable: KEYCLOAK_VERSION` | add `KEYCLOAK_VERSION=...` to `.env` | +| `invalid target release: 17` | no JDK 17+ installed; install `openjdk-17-jdk` | +| `Keycloak DB is unreachable — cannot continue` | Postgres not running, or `keycloakdb` not created, or `KC_DB_URL` wrong | +| Keycloak starts but every login fails | OBP API not reachable, or OBP creds/roles wrong, or `OBP_AUTHUSER_PROVIDER` doesn't match the user's provider in OBP | +| `OBP_AUTHUSER_PROVIDER is mandatory` | set it in `.env` | +| Login page shows raw message keys | theme message bundle issue — ensure `themes/obp/login/theme.properties` has `parent=base` | +| Port conflicts (7787/8443/9000) | `netstat -tulpn | grep -E ':(7787|8443|9000)'`; stop the conflicting process | + +--- + +## Related docs + +- [README.md](../README.md) — project overview & key environment variables +- [development/README.md](../development/README.md) — deploy/manage scripts reference +- [docs/CICD_DEPLOYMENT.md](CICD_DEPLOYMENT.md) — CI/CD deployment +- [env.sample](../env.sample) — full environment variable reference From e16a4837c1cdc40b0f354e440d0843a957e341e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Tue, 2 Jun 2026 14:32:16 +0200 Subject: [PATCH 05/14] build/local: auto-reclaim our docker build leftovers on each deploy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every --no-cache rebuild orphans the previous image and intermediate stages into dangling images, which accumulate (~600MB each). Label both build stages with com.openbankproject.image=obp-keycloak-provider and, after building, run a label-filtered `docker image prune` so only THIS project's dangling leftovers are removed — other projects' images and the shared build cache are never touched. --- development/docker/Dockerfile | 7 +++++++ development/run-local-postgres-cicd.sh | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/development/docker/Dockerfile b/development/docker/Dockerfile index bcbc41a..865bb07 100644 --- a/development/docker/Dockerfile +++ b/development/docker/Dockerfile @@ -22,6 +22,10 @@ ARG JAR_CHECKSUM # === Keycloak Builder Stage === FROM quay.io/keycloak/keycloak:${KEYCLOAK_VERSION} as builder +# Tag every image layer this project produces so the deploy script can prune +# only OUR dangling leftovers (label-filtered) without touching other projects. +LABEL com.openbankproject.image=obp-keycloak-provider + # Bring build args into this stage for cache invalidation metadata ARG BUILD_TIMESTAMP ARG JAR_CHECKSUM @@ -56,6 +60,9 @@ RUN /opt/keycloak/bin/kc.sh build # === Final Runtime Image === FROM quay.io/keycloak/keycloak:${KEYCLOAK_VERSION} +# Same project label on the final image (and thus on prior orphaned builds). +LABEL com.openbankproject.image=obp-keycloak-provider + # Bring the prebuilt Keycloak server into the final image COPY --from=builder /opt/keycloak/ /opt/keycloak/ COPY --from=builder /tmp/build-info.txt /opt/keycloak/ diff --git a/development/run-local-postgres-cicd.sh b/development/run-local-postgres-cicd.sh index 1449006..01aa864 100755 --- a/development/run-local-postgres-cicd.sh +++ b/development/run-local-postgres-cicd.sh @@ -285,6 +285,15 @@ fi rm -f "$DOCKER_BUILD_LOG" echo -e "${GREEN}✓ Docker image built${NC}" +# Reclaim build leftovers: every --no-cache rebuild orphans the previous image +# (and intermediate stages) into dangling images. Prune only images carrying this +# project's label so other projects' images and build cache are never touched. +PRUNE_LABEL="com.openbankproject.image=obp-keycloak-provider" +RECLAIMED=$(docker image prune -f --filter "label=$PRUNE_LABEL" 2>/dev/null | grep -i 'reclaimed' || true) +if [ -n "$RECLAIMED" ]; then + echo -e "${BLUE} Reclaimed build leftovers (${PRUNE_LABEL}): ${RECLAIMED##*Total reclaimed space: }${NC}" +fi + # Step 7: Start new container echo -e "${CYAN}[7/8] Starting New Container${NC}" From 63dff5f3a55295b92b8806d108af40c3888cca7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Tue, 2 Jun 2026 16:02:17 +0200 Subject: [PATCH 06/14] ops/local: logging & maintenance improvements (rotation, build banner, log knobs) Improve deployment/maintenance observability without touching the provider Java: - entrypoint prints a build banner (build-info.txt: timestamp + JAR checksum) at startup so logs identify exactly which image is running. - docker run caps the json-file log (--log-opt max-size=10m max-file=5, overridable via DOCKER_LOG_MAX_SIZE/DOCKER_LOG_MAX_FILE) to prevent unbounded log growth on long-lived hosts. - pass KC_LOG_LEVEL (default INFO; supports category overrides like io.tesobe:DEBUG) and KC_LOG_CONSOLE_OUTPUT (default/json) so verbosity and format can be tuned without rebuilding. - document all four in env.sample. --- development/docker/docker-entrypoint.sh | 9 +++++++++ development/run-local-postgres-cicd.sh | 11 +++++++++++ env.sample | 13 +++++++++++++ 3 files changed, 33 insertions(+) diff --git a/development/docker/docker-entrypoint.sh b/development/docker/docker-entrypoint.sh index 541c6b4..8f2fec8 100755 --- a/development/docker/docker-entrypoint.sh +++ b/development/docker/docker-entrypoint.sh @@ -2,6 +2,15 @@ # Custom entrypoint wrapper for OBP Keycloak Provider # Injects runtime environment variables into theme configuration before starting Keycloak. +# --- Build/version banner --- +# Surface which build is running so logs can be correlated to a specific image +# during deployment/maintenance (build-info.txt is baked in at image build time). +if [ -f /opt/keycloak/build-info.txt ]; then + echo "[OBP Entrypoint] ===== OBP Keycloak Provider build =====" + sed 's/^/[OBP Entrypoint] /' /opt/keycloak/build-info.txt + echo "[OBP Entrypoint] =======================================" +fi + # --- Forgot Password URL override --- # If FORGOT_PASSWORD_URL is set, inject it into all theme.properties files # so the "Forgot Password?" link points to a custom URL instead of Keycloak's default. diff --git a/development/run-local-postgres-cicd.sh b/development/run-local-postgres-cicd.sh index 01aa864..54026d7 100755 --- a/development/run-local-postgres-cicd.sh +++ b/development/run-local-postgres-cicd.sh @@ -331,13 +331,24 @@ CONTAINER_ENV_VARS=( "-e" "KC_METRICS_ENABLED=${KC_METRICS_ENABLED:-true}" "-e" "KC_FEATURES=${KC_FEATURES:-token-exchange}" "-e" "FORGOT_PASSWORD_URL=${FORGOT_PASSWORD_URL:-}" + # Logging — tune verbosity without rebuilding, and pick console format. + # KC_LOG_LEVEL root log level (e.g. INFO, DEBUG, WARN); category + # overrides allowed, e.g. "INFO,io.tesobe:DEBUG" + # KC_LOG_CONSOLE_OUTPUT 'default' (human text) or 'json' (for log aggregators) + "-e" "KC_LOG_LEVEL=${KC_LOG_LEVEL:-INFO}" + "-e" "KC_LOG_CONSOLE_OUTPUT=${KC_LOG_CONSOLE_OUTPUT:-default}" ) # Start container with host networking — no port mapping needed, Keycloak binds # directly to host ports (HTTP: ${KEYCLOAK_HTTP_PORT:-7787}, HTTPS: 8443, mgmt: 9000) +# +# Cap the json-file log so it can't grow unbounded and fill the disk on a +# long-lived host (override via DOCKER_LOG_MAX_SIZE / DOCKER_LOG_MAX_FILE). docker run -d \ --name "$CONTAINER_NAME" \ --network host \ + --log-opt max-size="${DOCKER_LOG_MAX_SIZE:-10m}" \ + --log-opt max-file="${DOCKER_LOG_MAX_FILE:-5}" \ "${CONTAINER_ENV_VARS[@]}" \ "$IMAGE_TAG" > /dev/null 2>&1 diff --git a/env.sample b/env.sample index d578941..b89f605 100644 --- a/env.sample +++ b/env.sample @@ -57,6 +57,19 @@ KC_HEALTH_ENABLED=true KC_METRICS_ENABLED=true KC_FEATURES=token-exchange +# ============================================================================= +# LOGGING +# ============================================================================= +# Root log level: INFO (default), DEBUG, WARN, ERROR. Category overrides allowed, +# e.g. KC_LOG_LEVEL=INFO,io.tesobe:DEBUG to debug just the OBP provider. +KC_LOG_LEVEL=INFO +# Console format: 'default' (human-readable text) or 'json' (for log aggregators +# like Loki / ELK / CloudWatch). +KC_LOG_CONSOLE_OUTPUT=default +# Docker json-file log rotation (caps disk usage on long-lived hosts). +DOCKER_LOG_MAX_SIZE=10m +DOCKER_LOG_MAX_FILE=5 + # ============================================================================= # THEME CUSTOMISATION # Override the "Forgot Password?" link on the login page. From 1523bde30cd2905c92fd9862f2a9d5d4dd986b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Tue, 2 Jun 2026 16:11:08 +0200 Subject: [PATCH 07/14] docs: document logging & observability knobs in onboarding guide Add a "Logging & observability" section to docs/ONBOARDING.md covering KC_LOG_LEVEL / KC_LOG_CONSOLE_OUTPUT / DOCKER_LOG_MAX_* and how to use them (identify the running build via the startup banner, debug just io.tesobe, JSON logs for aggregators, health/metrics endpoints), plus the known WARN-noise/PII caveat and the operational workaround. --- docs/ONBOARDING.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs/ONBOARDING.md b/docs/ONBOARDING.md index 80b2973..34bec66 100644 --- a/docs/ONBOARDING.md +++ b/docs/ONBOARDING.md @@ -137,6 +137,41 @@ A full reset = remove the container **and** drop/recreate `keycloakdb`. --- +## 6. Logging & observability + +The deploy script wires a few logging/maintenance knobs (all set in `.env`, no +rebuild needed unless noted): + +| Variable | Default | Purpose | +|----------|---------|---------| +| `KC_LOG_LEVEL` | `INFO` | Root log level. Supports category overrides, e.g. `INFO,io.tesobe:DEBUG` to debug only the OBP provider, or `io.tesobe:ERROR` to mute its noise. | +| `KC_LOG_CONSOLE_OUTPUT` | `default` | `default` = human text; `json` = structured logs for aggregators (Loki / ELK / CloudWatch). | +| `DOCKER_LOG_MAX_SIZE` | `10m` | Max size of each container log file before rotation. | +| `DOCKER_LOG_MAX_FILE` | `5` | Number of rotated log files kept (caps disk usage). | + +Common tasks: + +- **Identify the running build.** Every container prints a banner at startup — + the JAR checksum + build timestamp baked into the image: + ```bash + docker logs obp-keycloak-local | grep -A2 'OBP Keycloak Provider build' + ``` +- **Debug just the OBP provider** without flooding everything else: + ``` + KC_LOG_LEVEL=INFO,io.tesobe:DEBUG # in .env, then redeploy + ``` +- **Ship to a log aggregator:** `KC_LOG_CONSOLE_OUTPUT=json`. +- **Health & metrics** (already enabled): `https://localhost:9000/health/ready` + and `https://localhost:9000/metrics` (Prometheus format — point a scraper at it). + +> ⚠️ **Known log-noise caveat:** the provider currently emits routine activity +> (e.g. `isValid() … password validation SUCCESSFUL`, `FEDERATED STORAGE DETECTED`) +> at **WARN**, and logs user names/emails at INFO/WARN. Until that's fixed in the +> provider code, you can quiet it operationally with `KC_LOG_LEVEL=…,io.tesobe:ERROR`. +> Don't treat WARN volume as a health signal yet. + +--- + ## Troubleshooting | Symptom | Cause / fix | From a989bc4c760ff0a7ce26f8400a82ccf63c209504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Tue, 2 Jun 2026 16:12:31 +0200 Subject: [PATCH 08/14] docs: point development/README to the logging & observability section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a note in the Direct Docker Commands block linking to ONBOARDING.md §6 so the log-level/format, rotation, and build-banner knobs are discoverable from the development scripts README. --- development/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/development/README.md b/development/README.md index 57a39a2..5ab03ff 100644 --- a/development/README.md +++ b/development/README.md @@ -180,6 +180,10 @@ docker rm obp-keycloak-local docker ps --filter name=obp-keycloak-local ``` +> **Tuning log level/format, rotation, and identifying the running build:** +> see [Logging & observability](../docs/ONBOARDING.md#6-logging--observability) +> (`KC_LOG_LEVEL`, `KC_LOG_CONSOLE_OUTPUT`, `DOCKER_LOG_MAX_*`, startup build banner). + --- ## Themed Deployments From 049abe6080cf5f0d78903d3a065dc011cc8209af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Tue, 2 Jun 2026 16:24:40 +0200 Subject: [PATCH 09/14] =?UTF-8?q?fix(provider):=20correct=20log=20levels?= =?UTF-8?q?=20=E2=80=94=20demote=20routine=20activity=20off=20WARN,=20cut?= =?UTF-8?q?=20PII?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The provider logged per-request/by-design activity at WARN (e.g. isValid() markers, "password validation SUCCESSFUL", "FEDERATED STORAGE DETECTED", every read-only "OPERATION DISABLED" setter) and printed names/emails at INFO. That made WARN useless for alerting and leaked PII into logs. Demote routine tracing and read-only no-ops to DEBUG, and move name/email lines to DEBUG. Genuinely actionable conditions stay at WARN/ERROR: invalid ID format, user-not-found-by-id, OBP HTTP errors / 500 retries / null responses, interrupts, and admin-token failures. Behaviour is unchanged — log levels only. Use KC_LOG_LEVEL=...,io.tesobe:DEBUG to restore the verbose tracing when needed. --- .../java/io/tesobe/model/UserAdapter.java | 42 +++++++++---------- .../providers/KcUserStorageProvider.java | 32 +++++++------- .../io/tesobe/providers/OBPApiClient.java | 14 +++---- 3 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/main/java/io/tesobe/model/UserAdapter.java b/src/main/java/io/tesobe/model/UserAdapter.java index 4a02705..0ca6403 100644 --- a/src/main/java/io/tesobe/model/UserAdapter.java +++ b/src/main/java/io/tesobe/model/UserAdapter.java @@ -38,7 +38,7 @@ public UserAdapter( ) { super(session, realm, model); this.entity = entity; - log.infof( + log.debugf( "UserAdapter created for user: %s with database values - firstName: '%s', lastName: '%s', email: '%s'", entity.getUsername(), entity.getFirstName(), @@ -57,7 +57,7 @@ public UserAdapter( // entity.getId() is already a String (UUID), no conversion needed this.keycloakId = StorageId.keycloakId(model, entity.getId()); - log.infof( + log.debugf( "UserAdapter initialized at %d for user: %s (user_id: %s)", System.currentTimeMillis(), getUsername(), @@ -146,7 +146,7 @@ public String getSalt() { // Password setters - disabled for read-only approach public void setPassword(String password) { - log.warnf( + log.debugf( "OPERATION DISABLED: setPassword() called for user %s. " + "Database is read-only. Use external tools to update passwords.", getUsername() @@ -155,7 +155,7 @@ public void setPassword(String password) { } public void setSalt(String salt) { - log.warnf( + log.debugf( "OPERATION DISABLED: setSalt() called for user %s. " + "Database is read-only. Use external tools to update passwords.", getUsername() @@ -198,7 +198,7 @@ public String getFirstAttribute(String name) { // and log a warning if it does String federatedValue = super.getFirstAttribute(name); if (federatedValue != null) { - log.warnf( + log.debugf( "FEDERATED STORAGE LEAK: Attribute %s='%s' found in federated storage for user %s but not in database. Returning null to enforce database-only policy.", name, federatedValue, @@ -223,7 +223,7 @@ public Map> getAttributes() { // Check what federated storage contains before we return database-only values Map> federatedAttributes = super.getAttributes(); if (!federatedAttributes.isEmpty()) { - log.warnf( + log.debugf( "FEDERATED STORAGE DETECTED: Found %d federated attributes for user %s: %s", federatedAttributes.size(), getUsername(), @@ -301,7 +301,7 @@ public List getAttribute(String name) { @Override public void setUsername(String username) { - log.warnf( + log.debugf( "OPERATION DISABLED: setUsername() called for user %s. " + "Database is read-only. Use external tools to update user data.", getUsername() @@ -311,7 +311,7 @@ public void setUsername(String username) { @Override public void setEmail(String email) { - log.warnf( + log.debugf( "OPERATION DISABLED: setEmail() called for user %s. " + "Database is read-only. Use external tools to update user data.", getUsername() @@ -321,7 +321,7 @@ public void setEmail(String email) { @Override public void setFirstName(String firstName) { - log.warnf( + log.debugf( "OPERATION DISABLED: setFirstName() called for user %s. " + "Database is read-only. Use external tools to update user data.", getUsername() @@ -331,7 +331,7 @@ public void setFirstName(String firstName) { @Override public void setLastName(String lastName) { - log.warnf( + log.debugf( "OPERATION DISABLED: setLastName() called for user %s. " + "Database is read-only. Use external tools to update user data.", getUsername() @@ -341,7 +341,7 @@ public void setLastName(String lastName) { @Override public void setEmailVerified(boolean verified) { - log.warnf( + log.debugf( "OPERATION DISABLED: setEmailVerified() called for user %s. " + "Database is read-only. Use external tools to update user data.", getUsername() @@ -351,7 +351,7 @@ public void setEmailVerified(boolean verified) { @Override public void setEnabled(boolean enabled) { - log.warnf( + log.debugf( "OPERATION DISABLED: setEnabled() called for user %s. " + "Database is read-only. Use external tools to update user data.", getUsername() @@ -361,7 +361,7 @@ public void setEnabled(boolean enabled) { @Override public void setSingleAttribute(String name, String value) { - log.warnf( + log.debugf( "OPERATION DISABLED: setSingleAttribute(%s, %s) called for user %s. " + "Database is read-only. Use external tools to update user data.", name, @@ -373,7 +373,7 @@ public void setSingleAttribute(String name, String value) { @Override public void setAttribute(String name, List values) { - log.warnf( + log.debugf( "OPERATION DISABLED: setAttribute(%s, %s) called for user %s. " + "Database is read-only. Use external tools to update user data.", name, @@ -385,7 +385,7 @@ public void setAttribute(String name, List values) { @Override public void removeAttribute(String name) { - log.warnf( + log.debugf( "OPERATION DISABLED: removeAttribute(%s) called for user %s. " + "Database is read-only. Use external tools to update user data.", name, @@ -486,7 +486,7 @@ public Stream getClientRoleMappingsStream(ClientModel client) { */ private void clearFederatedStorageAttributes() { try { - log.infof( + log.debugf( "CLEARING FEDERATED STORAGE for user: %s - Database values: firstName='%s', lastName='%s', email='%s'", getUsername(), entity.getFirstName(), @@ -506,7 +506,7 @@ private void clearFederatedStorageAttributes() { for (String attrName : coreAttributes) { // Check what's currently in federated storage before clearing String federatedValue = super.getFirstAttribute(attrName); - log.infof( + log.debugf( "Attribute %s: federated='%s', database='%s' for user %s", attrName, federatedValue, @@ -516,14 +516,14 @@ private void clearFederatedStorageAttributes() { // Remove from federated storage - this calls the parent's method to actually clear it super.removeAttribute(attrName); - log.infof( + log.debugf( "Removed %s from federated storage for user %s", attrName, getUsername() ); } - log.infof( + log.debugf( "FEDERATED STORAGE CLEARED for user: %s - Database is now source of truth", getUsername() ); @@ -545,7 +545,7 @@ private void clearFederatedStorageAttributes() { */ public void forceRefreshFromDatabase() { try { - log.infof( + log.debugf( "FORCING REFRESH from database for user: %s (user_id: %s)", getUsername(), entity.getId() @@ -571,7 +571,7 @@ public void forceRefreshFromDatabase() { super.removeAttribute(attr); } - log.infof("Force refresh completed for user: %s", getUsername()); + log.debugf("Force refresh completed for user: %s", getUsername()); } catch (Exception e) { log.errorf( "Failed to force refresh for user %s: %s", diff --git a/src/main/java/io/tesobe/providers/KcUserStorageProvider.java b/src/main/java/io/tesobe/providers/KcUserStorageProvider.java index bb09ad0..c4057ce 100644 --- a/src/main/java/io/tesobe/providers/KcUserStorageProvider.java +++ b/src/main/java/io/tesobe/providers/KcUserStorageProvider.java @@ -43,7 +43,7 @@ public KcUserStorageProvider( this.session = session; this.model = model; this.apiClient = apiClient; - log.info("OBP User Storage Provider initialized (API mode)"); + log.debug("OBP User Storage Provider initialized (API mode)"); } // ------------------------------------------------------------------------- @@ -52,7 +52,7 @@ public KcUserStorageProvider( @Override public void close() { - log.info("OBP User Storage Provider closed"); + log.debug("OBP User Storage Provider closed"); } @Override @@ -84,7 +84,7 @@ public void onCache(RealmModel realm, CachedUserModel user, UserModel delegate) @Override public UserModel getUserById(RealmModel realm, String id) { String externalId = StorageId.externalId(id); - log.infof("getUserById() called: %s (external: %s)", id, externalId); + log.debugf("getUserById() called: %s (external: %s)", id, externalId); try { KcUserEntity entity = apiClient.getUserById(externalId); if (entity == null) { @@ -100,10 +100,10 @@ public UserModel getUserById(RealmModel realm, String id) { @Override public UserModel getUserByUsername(RealmModel realm, String username) { - log.infof("getUserByUsername() called: %s", username); + log.debugf("getUserByUsername() called: %s", username); KcUserEntity entity = apiClient.getUserByUsername(username); if (entity == null) { - log.infof("User not found by username: %s", username); + log.debugf("User not found by username: %s", username); return null; } return new UserAdapter(session, realm, model, entity); @@ -111,7 +111,7 @@ public UserModel getUserByUsername(RealmModel realm, String username) { @Override public UserModel getUserByEmail(RealmModel realm, String email) { - log.warnf("getUserByEmail() called for '%s' — email-based lookup is not supported " + + log.debugf("getUserByEmail() called for '%s' — email-based lookup is not supported " + "in OBP API mode. Returning null.", email); return null; } @@ -148,47 +148,47 @@ public boolean supportsCredentialType(String credentialType) { @Override public boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType) { boolean supported = supportsCredentialType(credentialType); - log.warnf("isConfiguredFor() — user: %s, credentialType: %s → %b", + log.debugf("isConfiguredFor() — user: %s, credentialType: %s → %b", user.getUsername(), credentialType, supported); return supported; } @Override public boolean isValid(RealmModel realm, UserModel user, CredentialInput input) { - log.warnf(">>> isValid() called for user: %s, credentialType: %s <<<", + log.debugf(">>> isValid() called for user: %s, credentialType: %s <<<", user.getUsername(), input.getType()); if (!supportsCredentialType(input.getType())) { - log.warnf("isValid() — unsupported credential type: %s for user: %s", + log.debugf("isValid() — unsupported credential type: %s for user: %s", input.getType(), user.getUsername()); return false; } String rawPassword = input.getChallengeResponse(); if (rawPassword == null || rawPassword.trim().isEmpty()) { - log.warnf("isValid() — empty or null password for user: %s", user.getUsername()); + log.debugf("isValid() — empty or null password for user: %s", user.getUsername()); return false; } boolean valid = apiClient.verifyUserCredentials(user.getUsername(), rawPassword) != null; if (valid) { - log.warnf("isValid() — password validation SUCCESSFUL for user: %s", user.getUsername()); + log.debugf("isValid() — password validation SUCCESSFUL for user: %s", user.getUsername()); } else { - log.warnf("isValid() — password validation FAILED for user: %s", user.getUsername()); + log.debugf("isValid() — password validation FAILED for user: %s", user.getUsername()); } return valid; } @Override public boolean updateCredential(RealmModel realm, UserModel user, CredentialInput input) { - log.warnf("updateCredential() called for user '%s' — password updates are not supported. " + + log.debugf("updateCredential() called for user '%s' — password updates are not supported. " + "Use OBP to change passwords.", user.getUsername()); return false; } @Override public void disableCredentialType(RealmModel realm, UserModel user, String credentialType) { - log.warnf("disableCredentialType() called for user '%s', type '%s' — not supported.", + log.debugf("disableCredentialType() called for user '%s', type '%s' — not supported.", user.getUsername(), credentialType); } @@ -216,7 +216,7 @@ public Stream searchForUserStream( Integer first, Integer max ) { - log.infof("searchForUserStream() with params: %s", params); + log.debugf("searchForUserStream() with params: %s", params); if (params == null || params.isEmpty()) { return getAllUsers(realm, first, max); @@ -267,7 +267,7 @@ public Stream searchForUserByUserAttributeStream( private Stream getAllUsers(RealmModel realm, Integer first, Integer max) { int offset = first != null && first >= 0 ? first : 0; int limit = max != null && max >= 0 ? max : 0; - log.infof("getAllUsers() for synchronisation: offset=%d, limit=%d", offset, limit); + log.debugf("getAllUsers() for synchronisation: offset=%d, limit=%d", offset, limit); List entities = apiClient.listUsers(offset, limit); return entities.stream() diff --git a/src/main/java/io/tesobe/providers/OBPApiClient.java b/src/main/java/io/tesobe/providers/OBPApiClient.java index 283d715..68a77a1 100644 --- a/src/main/java/io/tesobe/providers/OBPApiClient.java +++ b/src/main/java/io/tesobe/providers/OBPApiClient.java @@ -106,10 +106,10 @@ public boolean testConnection() { * Requires CanGetAnyUser role on the admin account. */ public KcUserEntity getUserByUsername(String username) { - log.infof("getUserByUsername() via OBP API: %s", username); + log.debugf("getUserByUsername() via OBP API: %s", username); String path = "/obp/v6.0.0/users/provider/" + encode(config.getAuthUserProvider()) + "/username/" + username; - log.infof("getUserByUsername() resolved path: %s", path); + log.debugf("getUserByUsername() resolved path: %s", path); return getUserFromPath(path); } @@ -118,7 +118,7 @@ public KcUserEntity getUserByUsername(String username) { * Requires CanGetAnyUser role on the admin account. */ public KcUserEntity getUserById(String userId) { - log.infof("getUserById() via OBP API: %s", userId); + log.debugf("getUserById() via OBP API: %s", userId); return getUserFromPath("/obp/v6.0.0/users/user-id/" + encode(userId)); } @@ -180,7 +180,7 @@ public List listUsers(int offset, int limit) { private static final long VERIFY_RETRY_DELAY_MS = 300; public KcUserEntity verifyUserCredentials(String username, String password) { - log.infof("verifyUserCredentials() via OBP API for user: %s", username); + log.debugf("verifyUserCredentials() via OBP API for user: %s", username); try { ObjectNode body = mapper.createObjectNode(); body.put("username", username); @@ -222,7 +222,7 @@ public KcUserEntity verifyUserCredentials(String username, String password) { return null; } - log.infof("Credential verification SUCCESSFUL for user: %s", username); + log.debugf("Credential verification SUCCESSFUL for user: %s", username); return entity; } catch (InterruptedException e) { Thread.currentThread().interrupt(); @@ -242,7 +242,7 @@ public KcUserEntity verifyUserCredentials(String username, String password) { * Fetches OIDC client details. Requires CanGetOidcClient role. */ public JsonNode getOidcClient(String clientId) { - log.infof("getOidcClient() via OBP API: %s", clientId); + log.debugf("getOidcClient() via OBP API: %s", clientId); try { HttpResponse resp = callWithRetry( "GET", "/obp/v6.0.0/oidc/clients/" + encode(clientId), null); @@ -293,7 +293,7 @@ private KcUserEntity getUserFromPath(String path) { try { HttpResponse resp = callWithRetry("GET", path, null); if (resp == null || resp.statusCode() != 200) { - log.infof("getUserFromPath('%s') returned HTTP %s — %s", + log.debugf("getUserFromPath('%s') returned HTTP %s — %s", path, resp != null ? resp.statusCode() : "null", resp != null ? resp.body() : ""); From 3bfc741eb553c03eefeee91f1926c8381d8cdd98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Wed, 3 Jun 2026 15:49:56 +0200 Subject: [PATCH 10/14] ci: make build workflow fork-resilient MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On forks without the DOCKER_HUB_ORGANIZATION repo variable, the image tag became docker.io//obp-keycloak:... (empty org) and `docker build` failed instantly with "invalid reference format" — so every push showed a red build. - Default the org to a placeholder ('obp') via `vars.DOCKER_HUB_ORGANIZATION || 'obp'` so the tag is always valid and the build runs (validates the Dockerfile). - Gate the push/sign steps on a real org being set (DEPLOY_CONTAINERS == 'true' && DOCKER_HUB_ORGANIZATION != '') so the placeholder is never published. Upstream (org variable set) is unaffected — the fallback only applies when unset. --- .github/workflows/build_container.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_container.yml b/.github/workflows/build_container.yml index 7e9577c..7043279 100644 --- a/.github/workflows/build_container.yml +++ b/.github/workflows/build_container.yml @@ -3,7 +3,11 @@ name: Build and publish container main - themed on: [push, workflow_dispatch] env: - DOCKER_HUB_ORGANIZATION: ${{ vars.DOCKER_HUB_ORGANIZATION }} + # Fall back to a placeholder org on forks that haven't set the + # DOCKER_HUB_ORGANIZATION repo variable, so the image tag stays valid and the + # build still runs (validates) instead of failing with "invalid reference + # format". Publishing is separately gated below on a real org being configured. + DOCKER_HUB_ORGANIZATION: ${{ vars.DOCKER_HUB_ORGANIZATION || 'obp' }} DOCKER_HUB_REPOSITORY: obp-keycloak jobs: @@ -28,7 +32,7 @@ jobs: echo Building container image for branch ${{ github.ref }} done fi - name: Push container image - if: vars.DEPLOY_CONTAINERS == 'true' + if: vars.DEPLOY_CONTAINERS == 'true' && vars.DOCKER_HUB_ORGANIZATION != '' run: | echo "${{ secrets.DOCKER_HUB_TOKEN }}" | docker login -u "${{ secrets.DOCKER_HUB_USERNAME }}" --password-stdin docker.io @@ -37,11 +41,11 @@ jobs: - uses: sigstore/cosign-installer@main - name: Write signing key to disk (only needed for `cosign sign --key`) - if: vars.DEPLOY_CONTAINERS == 'true' + if: vars.DEPLOY_CONTAINERS == 'true' && vars.DOCKER_HUB_ORGANIZATION != '' run: echo "${{ secrets.COSIGN_PRIVATE_KEY }}" > cosign.key - name: Sign container image - if: vars.DEPLOY_CONTAINERS == 'true' + if: vars.DEPLOY_CONTAINERS == 'true' && vars.DOCKER_HUB_ORGANIZATION != '' run: | cosign sign -y --key cosign.key \ From 583d2d0ba711954fffac38f510d7ff983660875e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Wed, 3 Jun 2026 16:01:41 +0200 Subject: [PATCH 11/14] =?UTF-8?q?fix(theme):=20obp-dark=20=E2=80=94=20coll?= =?UTF-8?q?apse=20language=20dropdown=20so=20it=20stops=20blocking=20the?= =?UTF-8?q?=20form?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit obp-dark sets `styles=css/styles.css`, which replaces (not appends to) the parent keycloak theme's `styles=css/login.css`. That parent stylesheet is what keeps the locale menu collapsed (#kc-locale ul { display:none }, shown on hover). Without it the language
    rendered fully expanded and overlapped the username/password fields, so credentials could not be entered once i18n was enabled. Add the collapse behaviour to obp-dark's stylesheet (display:none by default, shown on hover/focus-within, absolutely positioned with z-index above the form), styled for dark mode. --- .../obp-dark/login/resources/css/styles.css | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/themes/obp-dark/login/resources/css/styles.css b/themes/obp-dark/login/resources/css/styles.css index eb7fcef..8daea49 100644 --- a/themes/obp-dark/login/resources/css/styles.css +++ b/themes/obp-dark/login/resources/css/styles.css @@ -91,4 +91,51 @@ body { .obp-version { opacity: 0.7; font-size: 0.7rem; +} + +/* --------------------------------------------------------------------------- + * Language selector dropdown + * + * This theme sets `styles=css/styles.css`, which REPLACES the parent keycloak + * theme's `styles=css/login.css` rather than appending to it. That parent + * stylesheet is what normally keeps the locale menu collapsed + * (#kc-locale ul { display: none }) and opens it only on hover. Without it the + * language
      renders expanded and overlaps the login form, so credentials + * cannot be entered. Re-add the collapse behaviour here, styled for dark mode. + * ------------------------------------------------------------------------- */ +#kc-locale { + position: relative; + z-index: 50; +} + +#kc-locale ul { + display: none; + position: absolute; + top: 100%; + right: 0; + min-width: 120px; + margin: 0; + padding: 0; + list-style: none; + background-color: #0a0917; + border: 1px solid #222; + z-index: 100; +} + +#kc-locale-dropdown:hover ul, +#kc-locale-dropdown:focus-within ul { + display: block; +} + +#kc-locale-dropdown a { + display: block; + padding: 6px 12px; + color: #aaa; + text-align: right; + text-decoration: none; +} + +#kc-locale-dropdown a:hover { + background-color: #1a1830; + color: #fff; } \ No newline at end of file From 2fea6fbf89c09e2504048b5b001bd95c97ac2ce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Wed, 3 Jun 2026 16:18:06 +0200 Subject: [PATCH 12/14] style(theme): align obp-dark palette with the OBP portal and polish controls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adopt the OBP API sandbox portal's "obptheme" dark palette (converted from its OKLCH design tokens) and tidy the login controls: - documented palette as CSS variables: navy/purple primary surfaces (bg #0a0917, card #141423, border #23242f), near-white text (#fafafa / muted #a1a1a1), and the OBP green accent (#54b167 / hover #78bf86). - Sign In button, links, and input focus now use the OBP green accent. - float the language selector to the top-right of the card and style its toggle like the form's input controls (dark bg, matching border, caret, green hover); dropdown gets rounded corners + shadow. - fix the password-visibility (eye) icon contrast — was dark-on-dark; now muted light with a green hover. --- .../obp-dark/login/resources/css/styles.css | 148 +++++++++++++----- 1 file changed, 111 insertions(+), 37 deletions(-) diff --git a/themes/obp-dark/login/resources/css/styles.css b/themes/obp-dark/login/resources/css/styles.css index 8daea49..50b7c0e 100644 --- a/themes/obp-dark/login/resources/css/styles.css +++ b/themes/obp-dark/login/resources/css/styles.css @@ -1,8 +1,27 @@ +/* OBP Keycloak Dark Theme + * + * Palette sourced from the OBP API sandbox portal, theme "obptheme" in dark mode + * (https://apisandbox-portal.openbankproject.com — ). The portal's "primary" scale is a desaturated navy/purple + * surface ramp; "secondary" is the OBP green accent. OKLCH source values were + * converted to sRGB hex. + */ +:root { + --obp-bg: #0a0917; /* primary-950 — page background */ + --obp-card: #141423; /* primary-800 — elevated login card */ + --obp-input: #0a0917; /* primary-950 — recessed input fields */ + --obp-border: #23242f; /* primary-500 — subtle borders */ + --obp-text: #fafafa; /* surface-50 — primary text */ + --obp-text-muted: #a1a1a1; /* surface-400 — labels / secondary */ + --obp-accent: #54b167; /* secondary-500 — OBP green (CTA/links) */ + --obp-accent-hov: #78bf86; /* secondary-400 — accent hover */ +} + @media (min-width: 768px) { .login-pf-page .card-pf { max-width: 38%; margin-inline: auto; - color: #aaa; + color: var(--obp-text-muted); } } @@ -11,81 +30,100 @@ } .pf-c-form__label-text { - color: #aaa; + color: var(--obp-text-muted); } .login-pf body { - background: #030303; + background: var(--obp-bg); } body { - color: #000; + color: var(--obp-text); } .card-pf { - background: #000; + background: var(--obp-card); + /* Positioning context for the locale selector floated to the top-right below */ + position: relative; } .pf-c-input-group { - --pf-c-input-group--BackgroundColor: #fff; + --pf-c-input-group--BackgroundColor: var(--obp-input); } .pf-c-form-control { - --pf-c-form-control--BorderTopColor: #0a0917; - --pf-c-form-control--BorderRightColor: #0a0917; - --pf-c-form-control--BorderBottomColor: #0a0917; - --pf-c-form-control--BorderLeftColor: #0a0917; - --pf-c-form-control--BackgroundColor: #0a0917; + --pf-c-form-control--BorderTopColor: var(--obp-border); + --pf-c-form-control--BorderRightColor: var(--obp-border); + --pf-c-form-control--BorderBottomColor: var(--obp-border); + --pf-c-form-control--BorderLeftColor: var(--obp-border); + --pf-c-form-control--BackgroundColor: var(--obp-input); --pf-c-form-control--Height: 49px; + --pf-c-form-control--hover--BorderBottomColor: var(--obp-accent); + color: var(--obp-text); } -.pf-c-form-control { - --pf-c-form-control--hover--BorderBottomColor: #336841; -} - -.pf-c-form-control { - color: #aaaaaa; +/* Primary action (Sign In) — OBP green */ +.pf-c-button.pf-m-primary { + color: var(--obp-bg); + background-color: var(--obp-accent); } .pf-c-button.pf-m-primary:hover { - --pf-c-button--m-primary--Color: #000; - --pf-c-button--m-primary--BackgroundColor: #b5b5b5; + --pf-c-button--m-primary--Color: var(--obp-bg); + --pf-c-button--m-primary--BackgroundColor: var(--obp-accent-hov); + background-color: var(--obp-accent-hov); } +/* Password-visibility toggle inside the input group */ .pf-c-button.pf-m-control { - background-color: #000; + background-color: var(--obp-input); border: unset; + /* Make the eye icon visible on the dark input (PatternFly defaults it dark) */ + color: var(--obp-text-muted); +} + +.pf-c-button.pf-m-control:hover, +.pf-c-button.pf-m-control:focus { + color: var(--obp-accent); + background-color: var(--obp-input); +} + +.pf-c-button.pf-m-control i, +.pf-c-button.pf-m-control svg { + color: inherit; + fill: currentColor; } .pf-c-button.pf-m-control::after { - border-color: #0a0917; + border-color: var(--obp-border); } -.pf-c-button.pf-m-primary { - color: #000; - background-color: #fff; +/* Links (Forgot password, Register) */ +.login-pf-page a { + color: var(--obp-accent); } -.pf-c-button:hover { - background-color: #b5b5b5 ; +.login-pf-page a:hover { + color: var(--obp-accent-hov); } .obp-dark-footer { margin-top: 1.5rem; padding-top: 1rem; - border-top: 1px solid #222; + border-top: 1px solid var(--obp-border); text-align: center; } .obp-provider-info { - color: #777; + color: var(--obp-text-muted); font-size: 0.8rem; margin-bottom: 0.4rem; } .obp-copyright { - color: #555; + color: var(--obp-text-muted); font-size: 0.75rem; + opacity: 0.7; } .obp-version { @@ -104,21 +142,57 @@ body { * cannot be entered. Re-add the collapse behaviour here, styled for dark mode. * ------------------------------------------------------------------------- */ #kc-locale { - position: relative; + /* Float the language selector to the top-right of the card (the parent + keycloak login.css normally does this, but it isn't loaded here). */ + position: absolute; + top: 0.75rem; + right: 1rem; + width: auto; + text-align: right; z-index: 50; } +/* Toggle button — styled like the form's input controls */ +#kc-current-locale-link { + display: inline-flex; + align-items: center; + background-color: var(--obp-input); + color: var(--obp-text-muted); + border: 1px solid var(--obp-border); + border-radius: 3px; + padding: 6px 10px; + font-size: 0.85rem; + line-height: 1.4; + cursor: pointer; +} + +#kc-current-locale-link:hover, +#kc-locale-dropdown:focus-within #kc-current-locale-link { + border-color: var(--obp-accent); + color: var(--obp-text); +} + +#kc-current-locale-link::after { + content: "\25be"; /* ▾ */ + margin-left: 0.4rem; + font-size: 0.7em; + opacity: 0.8; +} + #kc-locale ul { display: none; position: absolute; top: 100%; right: 0; min-width: 120px; - margin: 0; + margin: 0.25rem 0 0; padding: 0; list-style: none; - background-color: #0a0917; - border: 1px solid #222; + background-color: var(--obp-card); + border: 1px solid var(--obp-border); + border-radius: 3px; + box-shadow: 0 6px 16px rgba(0, 0, 0, 0.5); + overflow: hidden; z-index: 100; } @@ -130,12 +204,12 @@ body { #kc-locale-dropdown a { display: block; padding: 6px 12px; - color: #aaa; + color: var(--obp-text-muted); text-align: right; text-decoration: none; } #kc-locale-dropdown a:hover { - background-color: #1a1830; - color: #fff; -} \ No newline at end of file + background-color: var(--obp-border); + color: var(--obp-text); +} From 1a90738ee6c9790b77fb04bc3f89f0608ee779c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Thu, 4 Jun 2026 15:58:08 +0200 Subject: [PATCH 13/14] fix(provider): drop UserRegistrationProvider so IdP broker logins work The OBP provider implemented UserRegistrationProvider but threw UnsupportedOperationException from addUser/removeUser. On first-broker login (e.g. Google OIDC), Keycloak's UserStorageManager routes user creation to registration-capable federation providers before its own DB, so the throw aborted the flow with IDENTITY_PROVIDER_FIRST_LOGIN_ERROR. Removing the capability makes UserStorageManager fall through to Keycloak's local store, which materializes and links the brokered identity. OBP users remain read-only via lookup/query/credential validation; they were never creatable or deletable through Keycloak. --- .../providers/KcUserStorageProvider.java | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/src/main/java/io/tesobe/providers/KcUserStorageProvider.java b/src/main/java/io/tesobe/providers/KcUserStorageProvider.java index c4057ce..03883c4 100644 --- a/src/main/java/io/tesobe/providers/KcUserStorageProvider.java +++ b/src/main/java/io/tesobe/providers/KcUserStorageProvider.java @@ -23,7 +23,6 @@ public class KcUserStorageProvider implements UserStorageProvider, UserLookupProvider, - UserRegistrationProvider, UserQueryProvider, CredentialInputUpdater, CredentialInputValidator, @@ -116,26 +115,6 @@ public UserModel getUserByEmail(RealmModel realm, String email) { return null; } - // ------------------------------------------------------------------------- - // Registration (disabled — OBP API is read-only from Keycloak's perspective) - // ------------------------------------------------------------------------- - - @Override - public UserModel addUser(RealmModel realm, String username) { - log.errorf("addUser() called for username '%s' — user creation is not supported. " + - "Users must be created in OBP directly.", username); - throw new UnsupportedOperationException( - "User creation is not supported. Users must be created through OBP."); - } - - @Override - public boolean removeUser(RealmModel realm, UserModel user) { - log.warnf("removeUser() called for '%s' — user deletion is not supported.", - user.getUsername()); - throw new UnsupportedOperationException( - "User deletion is not supported. Users must be removed through OBP."); - } - // ------------------------------------------------------------------------- // Credential support // ------------------------------------------------------------------------- From 79ead7b5dc46a1485ea8bda431bf9fa673968985 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Mon, 29 Jun 2026 14:14:34 +0200 Subject: [PATCH 14/14] docs(readme): explain Identity Provider brokering and local IdP user storage Document that brokered IdP users (e.g. Google OIDC) are stored in Keycloak's own database, since this provider is intentionally not a UserRegistrationProvider. Clarifies the read-only OBP federation vs. local IdP user management distinction. --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index 84cd33c..18dcb70 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,26 @@ Click the [User federation](https://localhost:8443/admin/master/console/#/master ![KC providers](/docs/images/providers.png?raw=true "KC providers") +## Identity Provider brokering (e.g. Google OIDC) + +Keycloak can also broker external identity providers (Google, etc.) alongside this +federation provider. The two are complementary: + +- **User federation** (this provider) sources existing **OBP** users for lookup and + password authentication. +- **Identity providers** let users sign in through an external IdP. + +On a user's *first* broker login, Keycloak materializes a local user and links the +external identity to it. This provider is intentionally **not** a +`UserRegistrationProvider`, so Keycloak stores brokered IdP users in **its own +database** rather than attempting to create them in OBP. OBP users remain read-only +(see [Provider Features](#provider-features)); brokered IdP users are managed in +Keycloak. + +> If this provider advertised user registration, the first-broker-login flow would +> route user creation to it and fail with `IDENTITY_PROVIDER_FIRST_LOGIN_ERROR`, +> since OBP user creation is not supported from Keycloak. + ## Documentation - [docs/ONBOARDING.md](docs/ONBOARDING.md) — local development onboarding (fresh-start guide)