Skip to content

Feature/38310 tls client auth idp brokering - #51414

Closed
eryx12o45 wants to merge 13 commits into
keycloak:mainfrom
eryx12o45:feature/38310-tls-client-auth-idp-brokering
Closed

Feature/38310 tls client auth idp brokering#51414
eryx12o45 wants to merge 13 commits into
keycloak:mainfrom
eryx12o45:feature/38310-tls-client-auth-idp-brokering

Conversation

@eryx12o45

Copy link
Copy Markdown

Closes #38310

Copilot AI balanced review requested due to automatic review settings August 4, 2026 06:40
@eryx12o45
eryx12o45 requested review from a team as code owners August 4, 2026 06:40
@eryx12o45
eryx12o45 marked this pull request as draft August 4, 2026 06:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds RFC 8705 tls_client_auth support for OIDC identity-provider brokering, allowing realm key-provider certificates to authenticate outbound broker requests.

Changes:

  • Adds per-IdP certificate resolution, mTLS SSL context creation, and certificate-authenticated backchannel requests.
  • Extends the Admin UI, validation, documentation, and release notes with the new authentication method.
  • Adds unit and integration coverage for configuration, certificate resolution, SSL context creation, and HTTP client lifecycle.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java Adds mTLS token, refresh, user-info, and introspection requests.
services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java Uses the mTLS-capable client for logout and user-info calls.
services/src/main/java/org/keycloak/broker/oidc/OAuth2IdentityProviderConfig.java Adds certificate-provider configuration and validation.
services/src/main/java/org/keycloak/broker/oidc/mtls/IdpClientCertificateResolver.java Resolves enabled realm certificate keys.
services/src/main/java/org/keycloak/broker/oidc/mtls/IdpMtlsSslContextProvider.java Builds an SSL context from realm key material.
server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttp.java Adds owned-client completion behavior.
server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttpRequest.java Closes dedicated clients after request completion.
server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttpResponse.java Runs completion cleanup after consuming responses.
js/apps/admin-ui/src/identity-providers/add/OIDCAuthentication.tsx Adds the mTLS authentication and certificate-provider controls.
js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties Adds UI labels and help text.
services/src/test/java/org/keycloak/broker/oidc/OAuth2IdentityProviderConfigTest.java Tests configuration detection and validation.
services/src/test/java/org/keycloak/broker/oidc/mtls/IdpClientCertificateResolverTest.java Tests certificate-key resolution.
services/src/test/java/org/keycloak/broker/oidc/mtls/IdpMtlsSslContextProviderTest.java Tests SSL context construction.
server-spi-private/src/test/java/org/keycloak/http/simple/SimpleHttpOwnedClientTest.java Tests dedicated HTTP client cleanup.
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/OidcTlsClientAuthBrokerConfigTest.java Tests Admin API configuration acceptance and rejection.
docs/documentation/server_admin/topics/identity-broker/oidc.adoc Documents mTLS identity-provider configuration.
docs/documentation/release_notes/topics/26_7_0.adoc Announces the new brokering capability.

Comment thread js/apps/admin-ui/src/identity-providers/add/OIDCAuthentication.tsx Outdated
Comment on lines +69 to +72
@Override
@Test
public void testLogInAsUserInIDP() {
// Intentionally left blank — see class javadoc. No live handshake in the standard profile.

@eryx12o45 eryx12o45 Aug 4, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

server-side certificate selection + SSLContext are unit-tested (IdpMtlsSslContextProviderTest, OAuth2IdentityProviderConfigTest); the live-handshake-test needs a new framework-infrastructure (a HttpsServer with setNeedClientAuth(true), filled from ManagedCertificates) and is documented as follow-up.

@eryx12o45
eryx12o45 force-pushed the feature/38310-tls-client-auth-idp-brokering branch 2 times, most recently from 615371b to c2c17d1 Compare August 4, 2026 09:08
@eryx12o45
eryx12o45 marked this pull request as ready for review August 5, 2026 14:25
Copilot AI review requested due to automatic review settings August 5, 2026 14:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 1 comment.

Suppressed comments (4)

services/src/main/java/org/keycloak/broker/oidc/OAuth2IdentityProviderConfig.java:308

  • This overload bypasses legacy validate(RealmModel) overrides in subclasses. For example, GoogleIdentityProviderConfig's issuer check and the generic OAuth provider's required-claim checks no longer run now that RepresentationToModel calls only this overload; dispatch through validate(realm) before the common checks (or migrate every existing override).
    public void validate(KeycloakSession session, RealmModel realm) {

services/src/main/java/org/keycloak/connections/httpclient/DefaultHttpClientFactory.java:206

  • With the supported disable-trust-manager=true setting, configureBuilder sets the disable flag and HttpClientBuilder.build() replaces this supplied SSL context with a new context initialized with null key managers (HttpClientBuilder.java:270-275). The resulting mTLS client never presents the selected certificate, so tls_client_auth fails; preserve the custom key managers when applying the passthrough trust manager.
        if (sslContext != null) {
            builder.sslContext(sslContext);

server-spi-private/src/main/java/org/keycloak/http/simple/SimpleHttpRequest.java:258

  • The owned client is closed only when client.execute throws, but createHttpRequest, form/entity creation, and header configuration can all throw before this try (for example for an invalid URL or a POST with no content). Those failures leak the dedicated client; widen the cleanup guard to cover the entire request-construction path.
        try {
            return new SimpleHttpResponse(client.execute(httpRequest), maxConsumedResponseSize, objectMapper, this::onCloseRequest);
        } catch (IOException | RuntimeException e) {
            onCloseRequest();
            throw e;

services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java:746

  • This overload resets max-consumed-response-size to the hard-coded 10 MB default, unlike SimpleHttp.create(session), so every mTLS backchannel request ignores the operator's configured response-size limit. Carry HttpClientProvider.getMaxConsumedResponseSize() onto the owned client.
        return SimpleHttp.create(buildMtlsHttpClient(), CLOSE_CLIENT);

Copilot AI review requested due to automatic review settings August 5, 2026 15:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 1 comment.

Suppressed comments (4)

services/src/main/java/org/keycloak/broker/oidc/OAuth2IdentityProviderConfig.java:309

  • Calling the new overload here bypasses existing subclasses that override only validate(RealmModel). In particular, the anonymous config in OAuth2IdentityProviderFactory.java:59-75 will no longer reject missing user-info/claim settings, so invalid generic OAuth IdPs can now be persisted; invoke the legacy overload before the new session-dependent checks (or keep the shared checks in that overload).
    public void validate(KeycloakSession session, RealmModel realm) {
        SslRequired sslRequired = realm.getSslRequired();

services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java:746

  • This overload initializes SimpleHttp with DEFAULT_MAX_CONSUMED_RESPONSE_SIZE, so mTLS responses ignore the provider's configured max-consumed-response-size while non-mTLS requests honor it. Carry the provider limit onto the owned-client request as well.
        return SimpleHttp.create(buildMtlsHttpClient(), CLOSE_CLIENT);

js/apps/admin-ui/src/identity-providers/add/OIDCAuthentication.tsx:53

  • Swallowing the expected 403 leaves certKeyProviderOptions empty, so an administrator with manage-identity-providers but not view-realm can select tls_client_auth but cannot supply its required key provider and every save is rejected. Either expose the eligible providers through an endpoint authorized for IdP management or clearly require/report the additional permission instead of silently rendering an unusable form.
      try {
        const keysMetadata = await adminClient.realms.getKeys({ realm });
        return keysMetadata.keys ?? [];
      } catch (error) {
        console.warn(

js/apps/admin-ui/src/identity-providers/add/OIDCAuthentication.tsx:68

  • The keys endpoint includes DISABLED keys, but this filter offers every entry with a certificate; selecting a disabled provider then deterministically fails the server-side isEnabled() validation. Filter the options to the ACTIVE/PASSIVE statuses accepted by IdpClientCertificateResolver.
      if (k.certificate && k.providerId && !seen.has(k.providerId)) {

Copilot AI review requested due to automatic review settings August 5, 2026 16:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 27 out of 27 changed files in this pull request and generated no new comments.

Suppressed comments (3)

services/src/main/java/org/keycloak/broker/oidc/OAuth2IdentityProviderConfig.java:309

  • Changing this override to the session-aware overload bypasses existing validate(RealmModel) overrides in subclasses. For example, the generic OAuth provider's required user-info/claim checks and GoogleIdentityProviderConfig's issuer validation no longer run during create/update; dispatch the legacy overload before the new session-dependent checks.
    public void validate(KeycloakSession session, RealmModel realm) {
        SslRequired sslRequired = realm.getSslRequired();

services/src/main/java/org/keycloak/broker/oidc/AbstractOAuth2IdentityProvider.java:742

  • This SimpleHttp.create overload always uses DEFAULT_MAX_CONSUMED_RESPONSE_SIZE, so mTLS backchannel calls ignore the server's configured response-size limit that SimpleHttp.create(session) honors. Carry the provider limit over to avoid changing the memory bound only for tls_client_auth requests.
        return SimpleHttp.create(buildMtlsHttpClient(), CLOSE_CLIENT);

js/apps/admin-ui/src/identity-providers/add/OIDCAuthentication.tsx:68

  • The selector includes DISABLED certificate keys, while IdpClientCertificateResolver only accepts ACTIVE or PASSIVE keys. Selecting such an offered provider therefore guarantees that create/update is rejected; filter options by enabled status.
      if (k.certificate && k.providerId && !seen.has(k.providerId)) {

vmuzikar and others added 9 commits August 6, 2026 07:54
- Closes: keycloak#38310

Signed-off-by: Sebastian Pfahl <eryx@gmx.net>
Closes keycloak#51388

Signed-off-by: Peter Zaoral <pzaoral@redhat.com>
Closes keycloak#50785

Signed-off-by: Stefan Guilhen <sguilhen@redhat.com>
Signed-off-by: Stefan Guilhen <sguilhen@redhat.com>
Signed-off-by: Stefan Guilhen <sguilhen@redhat.com>
Signed-off-by: Stefan Guilhen <sguilhen@redhat.com>
* Added default non-endpoint methods

fixes: keycloak#50221
Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

* changed types

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>

---------

Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
Updated RolePermissions.isRealmAdminRole() to explicitly check that the role belongs to the master realm before blocking it. This ensures that application realms can use and manage custom roles named admin or create-realm without being flagged as protected roles.

Closes keycloak#51323

Signed-off-by: alehhu <159355663+alehhu@users.noreply.github.com>
Closes keycloak#51156

Signed-off-by: Stefan Guilhen <sguilhen@redhat.com>
ahus1 and others added 4 commits August 6, 2026 07:56
Signed-off-by: Sebastian Pfahl <eryx@gmx.net>
)

Closes: keycloak#48216

Signed-off-by: Michal Vavřík <dev@michalvavrik.net>
…k#51309)

* Close account console mobile nav after selecting a page

If you have ever used Keycloak's Account Console on mobile, you probably
noticed some UI/UX annoyances. For example, if you open the main menu,
click on another category (e.g. Signing-in), the new page will be loaded
in the brackground, but you sont immediately notice since the page is
still overlayed by the main menu and you have to realize that you have
to close it manually to continue.

This patch fixes that issue. It appeared onn narrow viewports (phones,
or a desktop browser window resized below PatternFly's 1200px
breakpoint).

Signed-off-by: Lars Kiesow <lkiesow@uos.de>

* Add Playwright test for mobile nav auto-close

This tests that on narrow viewports the sidebar nav is an overlay, and
it must close after selecting a page instead of staying on top of the
newly loaded content. A second test guards that desktop viewports keep
the persistent sidebar open, so a future change can't silently drop the
width check.

Signed-off-by: Lars Kiesow <lkiesow@uos.de>

---------

Signed-off-by: Lars Kiesow <lkiesow@uos.de>
Signed-off-by: Sebastian Pfahl <eryx@gmx.net>
@eryx12o45
eryx12o45 force-pushed the feature/38310-tls-client-auth-idp-brokering branch from 129d98d to 1e4e8d8 Compare August 6, 2026 05:57
@eryx12o45
eryx12o45 marked this pull request as draft August 6, 2026 06:02
@eryx12o45 eryx12o45 closed this Aug 6, 2026
@eryx12o45
eryx12o45 deleted the feature/38310-tls-client-auth-idp-brokering branch August 6, 2026 09:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support using tls_client_auth when brokering external IDP

10 participants