From bcb193054d8c89a2e3802d6023a56b04ba4f91f9 Mon Sep 17 00:00:00 2001 From: Pedro Igor Date: Wed, 27 Nov 2024 10:23:10 -0300 Subject: [PATCH] Resolve scopes from bearer tokens when processing requests to the Account API Closes #35357 Signed-off-by: Pedro Igor --- .../server_admin/topics/users/user-profile.adoc | 4 ++-- .../java/org/keycloak/models/KeycloakContext.java | 5 +++++ .../keycloak/services/DefaultKeycloakContext.java | 12 ++++++++++++ .../services/managers/AuthenticationManager.java | 10 ++++++++++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/docs/documentation/server_admin/topics/users/user-profile.adoc b/docs/documentation/server_admin/topics/users/user-profile.adoc index 3b7e247deb4f..c4343efe7de5 100644 --- a/docs/documentation/server_admin/topics/users/user-profile.adoc +++ b/docs/documentation/server_admin/topics/users/user-profile.adoc @@ -167,8 +167,8 @@ Enabled when:: Enables or disables an attribute. If set to `Always`, the attribute is available from any user profile context. If set to `Scopes are requested`, the attribute is only available when the client acting on behalf of the user is requesting a set of one or more scopes. You can use this option to dynamically enforce certain attributes depending on the client scopes -being requested. For the account and administration consoles, scopes are not evaluated and the attribute is always enabled. -That is because filtering attributes by scopes only works when running authentication flows. +being requested. For the administration console, scopes are not evaluated and the attribute is always enabled. +That is because filtering attributes by scopes only works when running end-user authentication flows. Required:: Set the conditions to mark an attribute as required. If disabled, the attribute is optional. diff --git a/server-spi/src/main/java/org/keycloak/models/KeycloakContext.java b/server-spi/src/main/java/org/keycloak/models/KeycloakContext.java index 064c11193404..bc862f746f85 100755 --- a/server-spi/src/main/java/org/keycloak/models/KeycloakContext.java +++ b/server-spi/src/main/java/org/keycloak/models/KeycloakContext.java @@ -17,6 +17,7 @@ package org.keycloak.models; +import org.keycloak.Token; import org.keycloak.common.ClientConnection; import org.keycloak.http.HttpRequest; import org.keycloak.http.HttpResponse; @@ -108,4 +109,8 @@ default Locale resolveLocale(UserModel user, Theme.Type themeType) { UserSessionModel getUserSession(); void setUserSession(UserSessionModel session); + + Token getBearerToken(); + + void setBearerToken(Token token); } diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakContext.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakContext.java index 3e41964113a4..5a019b54ec61 100755 --- a/services/src/main/java/org/keycloak/services/DefaultKeycloakContext.java +++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakContext.java @@ -18,6 +18,7 @@ package org.keycloak.services; import jakarta.ws.rs.core.HttpHeaders; +import org.keycloak.Token; import org.keycloak.common.ClientConnection; import org.keycloak.http.HttpRequest; import org.keycloak.http.HttpResponse; @@ -60,6 +61,7 @@ public abstract class DefaultKeycloakContext implements KeycloakContext { private HttpRequest request; private HttpResponse response; private ClientConnection clientConnection; + private Token bearerToken; public DefaultKeycloakContext(KeycloakSession session) { this.session = session; @@ -222,4 +224,14 @@ public UserSessionModel getUserSession() { public void setUserSession(UserSessionModel userSession) { this.userSession = userSession; } + + @Override + public void setBearerToken(Token token) { + this.bearerToken = token; + } + + @Override + public Token getBearerToken() { + return bearerToken; + } } diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java index b0012ed9177b..3146a493854e 100755 --- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java @@ -17,6 +17,8 @@ package org.keycloak.services.managers; import org.jboss.logging.Logger; +import org.keycloak.Token; +import org.keycloak.TokenCategory; import org.keycloak.broker.provider.IdentityBrokerException; import org.keycloak.cookie.CookieProvider; import org.keycloak.cookie.CookieType; @@ -1537,6 +1539,7 @@ public static AuthResult verifyIdentityToken(KeycloakSession session, RealmModel } context.setUserSession(offlineUserSession); context.setClient(client); + context.setBearerToken(token); return new AuthResult(user, offlineUserSession, token, client); } } @@ -1568,6 +1571,7 @@ public static AuthResult verifyIdentityToken(KeycloakSession session, RealmModel return null; } context.setClient(client); + context.setBearerToken(token); } context.setUserSession(userSession); @@ -1683,6 +1687,12 @@ public static String getRequestedScopes(KeycloakSession session) { public static String getRequestedScopes(KeycloakSession session, ClientModel client) { KeycloakContext context = session.getContext(); + Token bearerToken = context.getBearerToken(); + + if (bearerToken != null && TokenCategory.ACCESS.equals(bearerToken.getCategory())) { + return AccessToken.class.cast(bearerToken).getScope(); + } + AuthenticationSessionModel authenticationSession = context.getAuthenticationSession(); if (authenticationSession != null) {