From dbcb3151a95d8fa0b8c60f231316c6f8822429c0 Mon Sep 17 00:00:00 2001 From: mposolda Date: Thu, 17 Oct 2024 19:30:52 +0200 Subject: [PATCH] Align admin console for client for backchannel and frontchannel logout closes #10138 Signed-off-by: mposolda Co-authored-by: Erik Jan de Wit Signed-off-by: Marek Posolda --- .../clients/oidc/con-basic-settings.adoc | 6 +++-- .../manage/clients/CreateClientPage.ts | 25 +++++++++++++++---- .../admin/messages/messages_en.properties | 5 +++- .../admin-ui/src/clients/add/LogoutPanel.tsx | 20 +++++++++++++-- 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/docs/documentation/server_admin/topics/clients/oidc/con-basic-settings.adoc b/docs/documentation/server_admin/topics/clients/oidc/con-basic-settings.adoc index da3ada2e2a..442ce36ea0 100644 --- a/docs/documentation/server_admin/topics/clients/oidc/con-basic-settings.adoc +++ b/docs/documentation/server_admin/topics/clients/oidc/con-basic-settings.adoc @@ -94,10 +94,12 @@ There will be also one item on the consent screen about this client itself. [[_front-channel-logout]] *Front channel logout*:: If *Front Channel Logout* is enabled, the application should be able to log out users through the front channel as per link:https://openid.net/specs/openid-connect-frontchannel-1_0.html[OpenID Connect Front-Channel Logout] specification. If enabled, you should also provide the `Front-Channel Logout URL`. -*Front-channel logout URL*:: URL that will be used by {project_name} to send logout requests to clients through the front-channel. +*Front-channel logout URL*:: URL that will be used by {project_name} to send logout requests to clients through the front-channel. If not provided, it defaults to the Home URL. This option is applicable just if `Front channel logout` option is ON. + +*Front-channel logout session required*:: Specifies whether a sid (session ID) and iss (issuer) parameters are included in the Logout request when the Front-channel Logout URL is used. [[_back-channel-logout-url]] -*Backchannel logout URL*:: URL that will cause the client to log itself out when a logout request is sent to this realm (via end_session_endpoint). If omitted, no logout requests are sent to the client. +*Backchannel logout URL*:: URL that will cause the client to log itself out when a logout request is sent to this realm (via end_session_endpoint). The logout is done by sending logout token as specified in the OIDC Backchannel logout specification. If omitted, the logout request might be sent to the specified `Admin URL` (if configured) in the format specific to {project_name} adapters. If even `Admin URL` is not configured, no logout request will be sent to the client. This option is applicable just if `Front channel logout` option is OFF. *Backchannel logout session required*:: Specifies whether a session ID Claim is included in the Logout Token when the *Backchannel Logout URL* is used. diff --git a/js/apps/admin-ui/cypress/support/pages/admin-ui/manage/clients/CreateClientPage.ts b/js/apps/admin-ui/cypress/support/pages/admin-ui/manage/clients/CreateClientPage.ts index ea98ef58ed..523753b7fb 100644 --- a/js/apps/admin-ui/cypress/support/pages/admin-ui/manage/clients/CreateClientPage.ts +++ b/js/apps/admin-ui/cypress/support/pages/admin-ui/manage/clients/CreateClientPage.ts @@ -45,8 +45,11 @@ export default class CreateClientPage extends CommonPage { '[for="kc-frontchannelLogout-switch"] > .pf-v5-c-switch__toggle'; #frontChannelLogoutSwitchInput = "#kc-frontchannelLogout-switch"; #frontChannelLogoutInput = "frontchannelLogoutUrl"; + #frontChannelLogoutSessionRequiredSwitchInput = + "#attributes\\.frontchannel🍺logout🍺session🍺required"; #backChannelLogoutInput = "backchannelLogoutUrl"; - #backChannelLogoutRequiredSwitchInput = "#backchannelLogoutSessionRequired"; + #backChannelLogoutSessionRequiredSwitchInput = + "#backchannelLogoutSessionRequired"; #backChannelLogoutRevoqueSwitch = '.pf-v5-c-form__group-control [for="backchannelLogoutRevokeOfflineSessions"] > .pf-v5-c-switch__toggle'; #backChannelLogoutRevoqueSwitchInput = @@ -268,17 +271,29 @@ export default class CreateClientPage extends CommonPage { } checkLogoutSettingsElements() { - cy.get(this.#backChannelLogoutRevoqueSwitch).scrollIntoView(); + cy.get(this.#frontChannelLogoutSessionRequiredSwitchInput).scrollIntoView(); cy.get(this.#frontChannelLogoutSwitchInput).should("not.be.disabled"); cy.findByTestId(this.#frontChannelLogoutInput).should("not.be.disabled"); + cy.get(this.#frontChannelLogoutSessionRequiredSwitchInput).should( + "not.be.disabled", + ); + cy.findByTestId(this.#backChannelLogoutInput).should("not.exist"); + cy.get(this.#backChannelLogoutSessionRequiredSwitchInput).should( + "not.exist", + ); + cy.get(this.#backChannelLogoutRevoqueSwitchInput).should("not.exist"); + + cy.get(this.#frontChannelLogoutSwitch).click(); + cy.findByTestId(this.#frontChannelLogoutInput).should("not.exist"); + cy.get(this.#frontChannelLogoutSessionRequiredSwitchInput).should( + "not.exist", + ); cy.findByTestId(this.#backChannelLogoutInput).should("not.be.disabled"); - cy.get(this.#backChannelLogoutRequiredSwitchInput).should( + cy.get(this.#backChannelLogoutSessionRequiredSwitchInput).should( "not.be.disabled", ); cy.get(this.#backChannelLogoutRevoqueSwitchInput).should("not.be.disabled"); - cy.get(this.#frontChannelLogoutSwitch).click(); - cy.findByTestId(this.#frontChannelLogoutInput).should("not.exist"); cy.get(this.#frontChannelLogoutSwitch).click(); cy.findByTestId(this.#frontChannelLogoutInput).should("not.be.disabled"); diff --git a/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties b/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties index aad98e85ab..f6673e436a 100644 --- a/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties +++ b/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties @@ -471,7 +471,7 @@ eventTypes.TOKEN_EXCHANGE.description=Token exchange continue=Continue editProvider=Edit provider included.client.audience.label=Included Client Audience -backchannelLogoutUrlHelp=URL that will cause the client to log itself out when a logout request is sent to this realm (via end_session_endpoint). If omitted, no logout request will be sent to the client is this case. +backchannelLogoutUrlHelp=URL that will cause the client to log itself out when a logout request is sent to this realm (via end_session_endpoint). The logout is done by sending logout token as specified in the OIDC Backchannel logout specification. If omitted, the logout request might be sent to the specified 'Admin URL' (if configured) in the format specific to Keycloak/RH-SSO adapters. If even 'Admin URL' is not configured, no logout request will be sent to the client. updateScopeSuccess=Authorization scope successfully updated userInfoResponseEncryptionKeyManagementAlgorithmHelp=JWA Algorithm used for key management in encrypting User Info Endpoint responses. This option is needed if you want encrypted User Info Endpoint responses. If left empty, User Info Endpoint responses are not encrypted. authnContextDeclRefsHelp=Ordered list of requested AuthnContext DeclRefs. @@ -1011,6 +1011,8 @@ useRealmRolesMappingHelp=If true, then LDAP role mappings will be mapped to real forwardParameters=Forwarded query parameters isAccessTokenJWTHelp=The Access Token received from the Identity Provider is a JWT and its claims will be accessible for mappers. frontchannelLogoutUrl=Front-channel logout URL +frontchannelLogoutSessionRequired=Front-channel logout session required +frontchannelLogoutSessionRequiredHelp=Specifying whether a sid (session ID) and iss (issuer) parameters are included in the Logout request when the Front-channel Logout URL is used. testConnectionHint.withoutEmailAction=Configure e-mail address webAuthnUpdateError=Could not update webauthn policies due to {{error}} paginationHelp=Whether the LDAP server supports pagination @@ -2490,6 +2492,7 @@ contentSecurityPolicy=Content-Security-Policy client-uris-must-match.tooltip=If on, all Client URIs (Redirect URIs and others) are allowed just if they match some trusted host or domain. off=Off frontchannelLogoutHelp=When true, logout requires a browser redirect to client. When false, server performs a background invocation for logout. +frontchannelLogoutOIDCHelp=When true, logout requires a browser to send the request to the client to configured Front-channel logout URL as specified in the OIDC Front-channel logout specification. When false, server can perform a background invocation for logout as long as either the Backchannel-logout URL is configured or Admin URL is configured. updateSuccess=Provider successfully updated hide=Hide isMandatoryInLdapHelp=If true, attribute is mandatory in LDAP. Hence if there is no value in Keycloak DB, the empty value will be set to be propagated to LDAP. diff --git a/js/apps/admin-ui/src/clients/add/LogoutPanel.tsx b/js/apps/admin-ui/src/clients/add/LogoutPanel.tsx index c95d47a62d..ac08cb5718 100644 --- a/js/apps/admin-ui/src/clients/add/LogoutPanel.tsx +++ b/js/apps/admin-ui/src/clients/add/LogoutPanel.tsx @@ -3,6 +3,7 @@ import { Controller, useFormContext } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { HelpItem, TextControl } from "@keycloak/keycloak-ui-shared"; +import { DefaultSwitchControl } from "../../components/SwitchControl"; import { FixedButtonsGroup } from "../../components/form/FixedButtonGroup"; import { FormAccess } from "../../components/form/FormAccess"; import { useAccess } from "../../context/access/Access"; @@ -29,6 +30,10 @@ export const LogoutPanel = ({ const protocol = watch("protocol"); const frontchannelLogout = watch("frontchannelLogout"); + const frontchannelLogoutTooltip = + protocol === "openid-connect" + ? "frontchannelLogoutOIDCHelp" + : "frontchannelLogoutHelp"; return ( } @@ -78,7 +83,18 @@ export const LogoutPanel = ({ }} /> )} - {protocol === "openid-connect" && ( + {protocol === "openid-connect" && frontchannelLogout && ( + ( + "attributes.frontchannel.logout.session.required", + )} + defaultValue="true" + label={t("frontchannelLogoutSessionRequired")} + labelIcon={t("frontchannelLogoutSessionRequiredHelp")} + stringify + /> + )} + {protocol === "openid-connect" && !frontchannelLogout && ( <>