From 0ceaed0e2ed91802c9f72d38bb7f7e6eea0cf7d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hynek=20Mlna=C5=99=C3=ADk?= Date: Fri, 10 Nov 2023 11:18:27 +0100 Subject: [PATCH] Transient users: Consents (#24496) closes #24494 --- .../light/LightweightConsentEntity.java | 169 ++++++++++++++++++ .../models/light/LightweightUserAdapter.java | 103 ++++++++--- .../keycloak/protocol/oidc/TokenManager.java | 3 +- .../endpoints/TokenRevocationEndpoint.java | 3 +- .../oidc/grants/ciba/CibaGrantType.java | 7 +- .../managers/AuthenticationManager.java | 2 +- .../services/managers/UserConsentManager.java | 98 +++++++++- .../resources/LoginActionsService.java | 7 +- .../resources/account/AccountRestService.java | 12 +- .../resources/admin/UserResource.java | 2 +- .../KcOidcBrokerTransientSessionsTest.java | 72 ++++++++ .../testsuite/model/UserConsentModelTest.java | 49 ++--- .../UserConsentWithUserStorageModelTest.java | 49 ++--- 13 files changed, 490 insertions(+), 86 deletions(-) create mode 100644 server-spi-private/src/main/java/org/keycloak/models/light/LightweightConsentEntity.java diff --git a/server-spi-private/src/main/java/org/keycloak/models/light/LightweightConsentEntity.java b/server-spi-private/src/main/java/org/keycloak/models/light/LightweightConsentEntity.java new file mode 100644 index 0000000000..f9b59766b3 --- /dev/null +++ b/server-spi-private/src/main/java/org/keycloak/models/light/LightweightConsentEntity.java @@ -0,0 +1,169 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.keycloak.models.light; + +import org.keycloak.common.util.Time; +import org.keycloak.models.ClientModel; +import org.keycloak.models.ClientScopeModel; +import org.keycloak.models.ModelException; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserConsentModel; +import org.keycloak.models.utils.KeycloakModelUtils; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +/** + * + * @author hmlnarik + */ +class LightweightConsentEntity { + + private String clientId; + private Long createdDate; + private Set grantedClientScopesIds; + private Long lastUpdatedDate; + + public static LightweightConsentEntity fromModel(UserConsentModel model) { + long currentTime = Time.currentTimeMillis(); + + LightweightConsentEntity consentEntity = new LightweightConsentEntity(); + consentEntity.setClientId(model.getClient().getId()); + consentEntity.setCreatedDate(currentTime); + consentEntity.setLastUpdatedDate(currentTime); + + model.getGrantedClientScopes() + .stream() + .map(ClientScopeModel::getId) + .forEach(consentEntity::addGrantedClientScopesId); + + return consentEntity; + } + + public static UserConsentModel toModel(RealmModel realm, LightweightConsentEntity entity) { + if (entity == null) { + return null; + } + + ClientModel client = realm.getClientById(entity.getClientId()); + if (client == null) { + throw new ModelException("Client with id " + entity.getClientId() + " is not available"); + } + UserConsentModel model = new UserConsentModel(client); + model.setCreatedDate(entity.getCreatedDate()); + model.setLastUpdatedDate(entity.getLastUpdatedDate()); + + Set grantedClientScopesIds = entity.getGrantedClientScopesIds(); + + if (grantedClientScopesIds != null && !grantedClientScopesIds.isEmpty()) { + grantedClientScopesIds.stream() + .map(scopeId -> KeycloakModelUtils.findClientScopeById(realm, client, scopeId)) + .filter(Objects::nonNull) + .forEach(model::addGrantedClientScope); + } + + return model; + } + + @Override + public int hashCode() { + return Objects.hash(clientId, grantedClientScopesIds, lastUpdatedDate); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final LightweightConsentEntity other = (LightweightConsentEntity) obj; + return Objects.equals(this.clientId, other.clientId) + && Objects.equals(this.lastUpdatedDate, other.lastUpdatedDate) + && Objects.equals(this.grantedClientScopesIds, other.grantedClientScopesIds); + } + + @Override + public String toString() { + return String.format("%s@%08x", "LightweightConsentEntity", System.identityHashCode(this)); + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public Long getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(Long createdDate) { + this.createdDate = createdDate; + } + + public Set getGrantedClientScopesIds() { + return grantedClientScopesIds; + } + + public void removeGrantedClientScopesId(String clientScopeId) { + if (grantedClientScopesIds == null) { + return; + } + if (grantedClientScopesIds.remove(clientScopeId)) { + this.lastUpdatedDate = Time.currentTimeMillis(); + } + } + + public void setGrantedClientScopesIds(Set clientScopeIds) { + clientScopeIds = clientScopeIds == null ? null : new HashSet<>(clientScopeIds); + if (clientScopeIds != null) { + clientScopeIds.removeIf(Objects::isNull); + if (clientScopeIds.isEmpty()) { + clientScopeIds = null; + } + } + grantedClientScopesIds = clientScopeIds; + this.lastUpdatedDate = Time.currentTimeMillis(); + } + + public void addGrantedClientScopesId(String clientScopeId) { + if (clientScopeId == null) { + return; + } + if (grantedClientScopesIds == null) { + grantedClientScopesIds = new HashSet<>(); + } + grantedClientScopesIds.add(clientScopeId); + this.lastUpdatedDate = Time.currentTimeMillis(); + } + + public Long getLastUpdatedDate() { + return lastUpdatedDate; + } + + public void setLastUpdatedDate(Long lastUpdatedDate) { + this.lastUpdatedDate = lastUpdatedDate; + } + +} diff --git a/server-spi-private/src/main/java/org/keycloak/models/light/LightweightUserAdapter.java b/server-spi-private/src/main/java/org/keycloak/models/light/LightweightUserAdapter.java index c241e74a30..fb233b2926 100644 --- a/server-spi-private/src/main/java/org/keycloak/models/light/LightweightUserAdapter.java +++ b/server-spi-private/src/main/java/org/keycloak/models/light/LightweightUserAdapter.java @@ -19,11 +19,14 @@ package org.keycloak.models.light; import org.keycloak.common.Profile; import org.keycloak.common.Profile.Feature; import org.keycloak.common.util.Base64; +import org.keycloak.models.ClientScopeModel; import org.keycloak.models.GroupModel; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.ModelException; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleModel; import org.keycloak.models.SubjectCredentialManager; +import org.keycloak.models.UserConsentModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserModel.RequiredAction; import org.keycloak.storage.adapter.AbstractInMemoryUserAdapter; @@ -33,10 +36,13 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; import com.fasterxml.jackson.annotation.JsonIncludeProperties; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.HashSet; import java.util.List; +import java.util.Objects; +import java.util.Set; import java.util.function.Consumer; -import java.util.logging.Level; -import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * @@ -52,6 +58,7 @@ import java.util.logging.Logger; "attributes", "requiredActions", "federationLink", + "consents", "serviceAccountClientLink", "readonly" }) @@ -62,6 +69,8 @@ public class LightweightUserAdapter extends AbstractInMemoryUserAdapter { public static final String ID_PREFIX = "lightweight-"; + private final Set consents = new HashSet<>(); + public static boolean isLightweightUser(UserModel user) { return Profile.isFeatureEnabled(Feature.TRANSIENT_USERS) && user instanceof LightweightUserAdapter; } @@ -116,115 +125,115 @@ public class LightweightUserAdapter extends AbstractInMemoryUserAdapter { @Override public void deleteRoleMapping(RoleModel role) { - super.deleteRoleMapping(role); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.deleteRoleMapping(role); update(); } @Override public void grantRole(RoleModel role) { - super.grantRole(role); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.grantRole(role); update(); } @Override public void setServiceAccountClientLink(String clientInternalId) { - super.setServiceAccountClientLink(clientInternalId); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.setServiceAccountClientLink(clientInternalId); update(); } @Override public void setFederationLink(String link) { - super.setFederationLink(link); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.setFederationLink(link); update(); } @Override public void leaveGroup(GroupModel group) { - super.leaveGroup(group); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.leaveGroup(group); update(); } @Override public void joinGroup(GroupModel group) { - super.joinGroup(group); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.joinGroup(group); update(); } @Override public void setEmailVerified(boolean verified) { - super.setEmailVerified(verified); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.setEmailVerified(verified); update(); } @Override public void removeRequiredAction(RequiredAction action) { - super.removeRequiredAction(action); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.removeRequiredAction(action); update(); } @Override public void addRequiredAction(RequiredAction action) { - super.addRequiredAction(action); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.addRequiredAction(action); update(); } @Override public void removeRequiredAction(String action) { - super.removeRequiredAction(action); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.removeRequiredAction(action); update(); } @Override public void addRequiredAction(String action) { - super.addRequiredAction(action); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.addRequiredAction(action); update(); } @Override public void removeAttribute(String name) { - super.removeAttribute(name); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.removeAttribute(name); update(); } @Override public void setAttribute(String name, List values) { - super.setAttribute(name, values); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.setAttribute(name, values); update(); } @Override public void setSingleAttribute(String name, String value) { - super.setSingleAttribute(name, value); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.setSingleAttribute(name, value); update(); } @Override public void setEnabled(boolean enabled) { - super.setEnabled(enabled); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.setEnabled(enabled); update(); } @Override public void setCreatedTimestamp(Long timestamp) { - super.setCreatedTimestamp(timestamp); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.setCreatedTimestamp(timestamp); update(); } @Override public void setReadonly(boolean flag) { - super.setReadonly(flag); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.setReadonly(flag); update(); } @Override public void addDefaults() { - super.addDefaults(); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.addDefaults(); update(); } @Override public void setUsername(String username) { - super.setUsername(username); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody + super.setUsername(username); update(); } @@ -236,4 +245,56 @@ public class LightweightUserAdapter extends AbstractInMemoryUserAdapter { updateHandler.accept(this); } + public void addConsent(UserConsentModel consent) { + if (consent != null) { + consents.add(LightweightConsentEntity.fromModel(consent)); + update(); + } + } + + public UserConsentModel getConsentByClient(String clientInternalId) { + return LightweightConsentEntity.toModel(realm, getConsentEntityByClient(clientInternalId)); + } + + public boolean revokeConsentForClient(String clientInternalId) { + if (clientInternalId != null) { + final boolean res = consents.removeIf(lce -> clientInternalId.equals(lce.getClientId())); + if (res) { + update(); + } + return res; + } + return false; + } + + public void updateConsent(UserConsentModel consent) { + if (consent == null) { + return; + } + + String clientId = consent.getClient() == null + ? null + : consent.getClient().getId(); + LightweightConsentEntity userConsentEntity = getConsentEntityByClient(clientId); + + userConsentEntity.setGrantedClientScopesIds( + consent.getGrantedClientScopes().stream() + .map(ClientScopeModel::getId) + .collect(Collectors.toSet()) + ); + update(); + } + + LightweightConsentEntity getConsentEntityByClient(String clientId) { + return consents.stream().filter(lce -> Objects.equals(clientId, lce.getClientId())) + .findFirst() + .orElse(null); + } + + public Stream getConsentsStream() { + return consents.stream() + .map(lce -> LightweightConsentEntity.toModel(realm, lce)); + } + + } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java index 421b491207..2c894b04a6 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java @@ -82,6 +82,7 @@ import org.keycloak.services.ErrorResponseException; import org.keycloak.services.Urls; import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationSessionManager; +import org.keycloak.services.managers.UserConsentManager; import org.keycloak.services.managers.UserSessionCrossDCManager; import org.keycloak.services.managers.UserSessionManager; import org.keycloak.services.resources.IdentityBrokerService; @@ -744,7 +745,7 @@ public class TokenManager { return true; } - UserConsentModel grantedConsent = session.users().getConsentByClient(client.getRealm(), user.getId(), client.getId()); + UserConsentModel grantedConsent = UserConsentManager.getConsentByClient(session, client.getRealm(), user, client.getId()); return requestedClientScopes .filter(ClientScopeModel::isDisplayOnConsentScreen) diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenRevocationEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenRevocationEndpoint.java index 981d9266c8..f02456aa7e 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenRevocationEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenRevocationEndpoint.java @@ -51,6 +51,7 @@ import org.keycloak.services.CorsErrorResponseException; import org.keycloak.services.clientpolicy.ClientPolicyException; import org.keycloak.services.clientpolicy.context.TokenRevokeContext; import org.keycloak.services.clientpolicy.context.TokenRevokeResponseContext; +import org.keycloak.services.managers.UserConsentManager; import org.keycloak.services.managers.UserSessionCrossDCManager; import org.keycloak.services.managers.UserSessionManager; import org.keycloak.services.resources.Cors; @@ -241,7 +242,7 @@ public class TokenRevocationEndpoint { } private void revokeClient() { - session.users().revokeConsentForClient(realm, user.getId(), client.getId()); + UserConsentManager.revokeConsentForClient(session, realm, user, client.getId()); if (TokenUtil.TOKEN_TYPE_OFFLINE.equals(token.getType())) { new UserSessionManager(session).revokeOfflineToken(user, client); } diff --git a/services/src/main/java/org/keycloak/protocol/oidc/grants/ciba/CibaGrantType.java b/services/src/main/java/org/keycloak/protocol/oidc/grants/ciba/CibaGrantType.java index a7c866a8a5..ee3bbe6411 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/grants/ciba/CibaGrantType.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/grants/ciba/CibaGrantType.java @@ -55,6 +55,7 @@ import org.keycloak.services.ErrorResponseException; import org.keycloak.services.Urls; import org.keycloak.services.clientpolicy.ClientPolicyException; import org.keycloak.services.managers.AuthenticationManager; +import org.keycloak.services.managers.UserConsentManager; import org.keycloak.services.resources.Cors; import org.keycloak.services.util.DefaultClientSessionContext; import org.keycloak.sessions.AuthenticationSessionModel; @@ -268,10 +269,10 @@ public class CibaGrantType { } // authorization (consent) - UserConsentModel grantedConsent = session.users().getConsentByClient(realm, user.getId(), client.getId()); + UserConsentModel grantedConsent = UserConsentManager.getConsentByClient(session, realm, user, client.getId()); if (grantedConsent == null) { grantedConsent = new UserConsentModel(client); - session.users().addConsent(realm, user.getId(), grantedConsent); + UserConsentManager.addConsent(session, realm, user, grantedConsent); if (logger.isTraceEnabled()) { grantedConsent.getGrantedClientScopes().forEach(i->logger.tracef("CIBA Grant :: Consent granted. %s", i.getName())); } @@ -288,7 +289,7 @@ public class CibaGrantType { } if (updateConsentRequired) { - session.users().updateConsent(realm, user.getId(), grantedConsent); + UserConsentManager.updateConsent(session, realm, user, grantedConsent); if (logger.isTraceEnabled()) { grantedConsent.getGrantedClientScopes().forEach(i->logger.tracef("CIBA Grant :: Consent updated. %s", i.getName())); } 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 c4da75fd8b..6b5e225d3d 100755 --- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java @@ -1150,7 +1150,7 @@ public class AuthenticationManager { final UserModel user = authSession.getAuthenticatedUser(); final ClientModel client = authSession.getClient(); - return session.users().getConsentByClient(realm, user.getId(), client.getId()); + return UserConsentManager.getConsentByClient(session, realm, user, client.getId()); } } diff --git a/services/src/main/java/org/keycloak/services/managers/UserConsentManager.java b/services/src/main/java/org/keycloak/services/managers/UserConsentManager.java index 8099e90e6b..fac68442ce 100644 --- a/services/src/main/java/org/keycloak/services/managers/UserConsentManager.java +++ b/services/src/main/java/org/keycloak/services/managers/UserConsentManager.java @@ -20,8 +20,13 @@ package org.keycloak.services.managers; import org.keycloak.models.ClientModel; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.ModelException; import org.keycloak.models.RealmModel; +import org.keycloak.models.UserConsentModel; import org.keycloak.models.UserModel; +import org.keycloak.models.light.LightweightUserAdapter; +import java.util.stream.Stream; +import static org.keycloak.models.light.LightweightUserAdapter.isLightweightUser; /** * @author Marek Posolda @@ -38,7 +43,7 @@ public class UserConsentManager { */ public static boolean revokeConsentToClient(KeycloakSession session, ClientModel client, UserModel user) { RealmModel realm = session.getContext().getRealm(); - boolean revokedConsent = session.users().revokeConsentForClient(realm, user.getId(), client.getId()); + boolean revokedConsent = revokeConsentForClient(session, realm, user, client.getId()); boolean revokedOfflineToken = new UserSessionManager(session).revokeOfflineToken(user, client); if (revokedConsent) { @@ -48,4 +53,95 @@ public class UserConsentManager { return revokedConsent || revokedOfflineToken; } + + /** + * Add user consent for the user. + * + * @param realm a reference to the realm + * @param user user. Must not be {@code null} + * @param consent all details corresponding to the granted consent + * + * @throws ModelException If there is no user with userId + */ + public static void addConsent(KeycloakSession session, RealmModel realm, UserModel user, UserConsentModel consent) { + if (isLightweightUser(user)) { + LightweightUserAdapter lua = (LightweightUserAdapter) user; + lua.addConsent(consent); + } else { + session.users().addConsent(realm, user.getId(), consent); + } + } + + /** + * Returns UserConsentModel given by a user for the client with clientInternalId + * + * @param realm a reference to the realm + * @param user user. Must not be {@code null} + * @param clientInternalId id of the client + * @return consent given by the user to the client or {@code null} if no consent or user exists + * + * @throws ModelException when there are more consents fulfilling specified parameters + */ + public static UserConsentModel getConsentByClient(KeycloakSession session, RealmModel realm, UserModel user, String clientInternalId) { + if (isLightweightUser(user)) { + LightweightUserAdapter lua = (LightweightUserAdapter) user; + return lua.getConsentByClient(clientInternalId); + } else { + return session.users().getConsentByClient(realm, user.getId(), clientInternalId); + } + } + + /** + * Obtains the consents associated with the user + * + * @param realm a reference to the realm. + * @param user user. Must not be {@code null} + * @return a non-null {@link Stream} of consents associated with the user. + */ + public static Stream getConsentsStream(KeycloakSession session, RealmModel realm, UserModel user) { + if (isLightweightUser(user)) { + LightweightUserAdapter lua = (LightweightUserAdapter) user; + return lua.getConsentsStream(); + } else { + return session.users().getConsentsStream(realm, user.getId()); + } + } + + /** + * Update client scopes in the stored user consent + * + * @param realm a reference to the realm + * @param user user. Must not be {@code null} + * @param consent new details of the user consent + * + * @throws ModelException when consent doesn't exist for the userId + */ + public static void updateConsent(KeycloakSession session, RealmModel realm, UserModel user, UserConsentModel consent) { + if (isLightweightUser(user)) { + LightweightUserAdapter lua = (LightweightUserAdapter) user; + lua.updateConsent(consent); + } else { + session.users().updateConsent(realm, user.getId(), consent); + } + } + + /** + * Remove a user consent given by the user and client id + * + * @param realm a reference to the realm + * @param user user. Must not be {@code null} + * @param clientInternalId id of the client + * @return {@code true} if the consent was removed, {@code false} otherwise + * + * TODO: Make this method return Boolean so that store can return "I don't know" answer, this can be used for example in async stores + */ + public static boolean revokeConsentForClient(KeycloakSession session, RealmModel realm, UserModel user, String clientInternalId) { + if (isLightweightUser(user)) { + LightweightUserAdapter lua = (LightweightUserAdapter) user; + return lua.revokeConsentForClient(clientInternalId); + } else { + return session.users().revokeConsentForClient(realm, user.getId(), clientInternalId); + } + } + } diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java index 27b9a23f59..8e34da5dc7 100755 --- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java +++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java @@ -82,6 +82,7 @@ import org.keycloak.services.Urls; import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationSessionManager; import org.keycloak.services.managers.ClientSessionCode; +import org.keycloak.services.managers.UserConsentManager; import org.keycloak.services.messages.Messages; import org.keycloak.services.util.AuthenticationFlowURLHelper; import org.keycloak.services.util.BrowserHistoryHelper; @@ -962,10 +963,10 @@ public class LoginActionsService { return response; } - UserConsentModel grantedConsent = session.users().getConsentByClient(realm, user.getId(), client.getId()); + UserConsentModel grantedConsent = UserConsentManager.getConsentByClient(session, realm, user, client.getId()); if (grantedConsent == null) { grantedConsent = new UserConsentModel(client); - session.users().addConsent(realm, user.getId(), grantedConsent); + UserConsentManager.addConsent(session, realm, user, grantedConsent); } // Update may not be required if all clientScopes were already granted (May happen for example with prompt=consent) @@ -984,7 +985,7 @@ public class LoginActionsService { } if (updateConsentRequired) { - session.users().updateConsent(realm, user.getId(), grantedConsent); + UserConsentManager.updateConsent(session, realm, user, grantedConsent); } event.detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED); diff --git a/services/src/main/java/org/keycloak/services/resources/account/AccountRestService.java b/services/src/main/java/org/keycloak/services/resources/account/AccountRestService.java index a48c7fbae2..43a416411b 100755 --- a/services/src/main/java/org/keycloak/services/resources/account/AccountRestService.java +++ b/services/src/main/java/org/keycloak/services/resources/account/AccountRestService.java @@ -314,7 +314,7 @@ public class AccountRestService { throw ErrorResponse.error("No client with clientId: " + clientId + " found.", Response.Status.NOT_FOUND); } - UserConsentModel consent = session.users().getConsentByClient(realm, user.getId(), client.getId()); + UserConsentModel consent = UserConsentManager.getConsentByClient(session, realm, user, client.getId()); if (consent == null) { return Response.noContent().build(); } @@ -403,17 +403,17 @@ public class AccountRestService { try { UserConsentModel grantedConsent = createConsent(client, consent); - if (session.users().getConsentByClient(realm, user.getId(), client.getId()) == null) { - session.users().addConsent(realm, user.getId(), grantedConsent); + if (UserConsentManager.getConsentByClient(session, realm, user, client.getId()) == null) { + UserConsentManager.addConsent(session, realm, user, grantedConsent); event.event(EventType.GRANT_CONSENT); } else { - session.users().updateConsent(realm, user.getId(), grantedConsent); + UserConsentManager.updateConsent(session, realm, user, grantedConsent); event.event(EventType.UPDATE_CONSENT); } event.detail(Details.GRANTED_CLIENT,client.getClientId()); String scopeString = grantedConsent.getGrantedClientScopes().stream().map(cs->cs.getName()).collect(Collectors.joining(" ")); event.detail(Details.SCOPE, scopeString).success(); - grantedConsent = session.users().getConsentByClient(realm, user.getId(), client.getId()); + grantedConsent = UserConsentManager.getConsentByClient(session, realm, user, client.getId()); return Response.ok(modelToRepresentation(grantedConsent)).build(); } catch (IllegalArgumentException e) { throw ErrorResponse.error(e.getMessage(), Response.Status.BAD_REQUEST); @@ -490,7 +490,7 @@ public class AccountRestService { .collect(Collectors.toSet())); Map consentModels = new HashMap<>(); - clients.addAll(session.users().getConsentsStream(realm, user.getId()) + clients.addAll(UserConsentManager.getConsentsStream(session, realm, user) .peek(consent -> consentModels.put(consent.getClient().getClientId(), consent)) .map(UserConsentModel::getClient) .collect(Collectors.toSet())); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java index eebbc1cc41..366029c8ad 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java @@ -525,7 +525,7 @@ public class UserResource { Set offlineClients = new UserSessionManager(session).findClientsWithOfflineToken(realm, user); Set clientsWithUserConsents = new HashSet<>(); - List userConsents = session.users().getConsentsStream(realm, user.getId()) + List userConsents = UserConsentManager.getConsentsStream(session, realm, user) // collect clients with explicit user consents for later filtering .peek(ucm -> clientsWithUserConsents.add(ucm.getClient())) .collect(Collectors.toList()); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTransientSessionsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTransientSessionsTest.java index f17eec1f26..922d0615f8 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTransientSessionsTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerTransientSessionsTest.java @@ -49,9 +49,11 @@ import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.UserRepresentation; +import org.keycloak.representations.idm.UserSessionRepresentation; import org.keycloak.testsuite.Assert; import org.keycloak.testsuite.AssertEvents; import org.keycloak.testsuite.arquillian.annotation.EnableFeature; +import org.keycloak.testsuite.updaters.ClientAttributeUpdater; import org.keycloak.testsuite.updaters.Creator; import org.keycloak.testsuite.util.AccountHelper; import org.keycloak.testsuite.util.OAuthClient; @@ -74,14 +76,18 @@ import java.util.stream.Collectors; import org.junit.Rule; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.aMapWithSize; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.keycloak.testsuite.broker.BrokerTestConstants.CLIENT_ID; import static org.keycloak.testsuite.broker.BrokerTestConstants.REALM_CONS_NAME; import static org.keycloak.testsuite.broker.BrokerTestConstants.REALM_PROV_NAME; import static org.keycloak.testsuite.broker.BrokerTestTools.getConsumerRoot; @@ -468,6 +474,72 @@ public final class KcOidcBrokerTransientSessionsTest extends AbstractAdvancedBro Assert.assertTrue("Should be logged in", driver.getTitle().endsWith("AUTH_RESPONSE")); } + // Based on ConsentsTest.testConsents, modified to use consumer realm instead + @Test + public void testConsents() throws Exception { + try (var c = ClientAttributeUpdater.forClient(adminClient, bc.consumerRealmName(), CONSUMER_BROKER_APP_CLIENT_ID).setConsentRequired(true).update()) { + oauth.clientId(CONSUMER_BROKER_APP_CLIENT_ID); + oauth.realm(bc.consumerRealmName()); + oauth.doLoginSocial(bc.getIDPAlias(), bc.getUserLogin(), bc.getUserPassword()); + events.clear(); + oauth.updateAccountInformation(bc.getUserLogin(), bc.getUserEmail()); + WaitUtils.waitForPageToLoad(); + consentPage.assertCurrent(); + consentPage.confirm(); + + EventRepresentation loginEvent; + do { + loginEvent = events.poll(); + } while (loginEvent != null && ! Objects.equals(EventType.LOGIN.name(), loginEvent.getType())); + + assertThat(loginEvent, notNullValue()); + assertThat(loginEvent.getClientId(), is(CONSUMER_BROKER_APP_CLIENT_ID)); + assertThat(loginEvent.getUserId(), Matchers.containsString(LightweightUserAdapter.ID_PREFIX)); + + final String lwUserId = loginEvent.getUserId(); + + final UserResource userResource = adminClient.realm(bc.consumerRealmName()).users().get(lwUserId); + List> consents = userResource.getConsents(); + assertThat("There should be one consent", consents, hasSize(1)); + + Map consent = consents.get(0); + Assert.assertEquals("Consent should be given to " + CONSUMER_BROKER_APP_CLIENT_ID, CONSUMER_BROKER_APP_CLIENT_ID, consent.get("clientId")); + + // list sessions. Single client should be in user session + List sessions = userResource.getUserSessions(); + assertThat("There should be one active session", sessions, hasSize(1)); + assertThat("There should be one client in user session", sessions.get(0).getClients(), aMapWithSize(1)); + + // Try SSO relogging into the app before revoking consent. + oauth.clientId(CONSUMER_BROKER_APP_CLIENT_ID); + oauth.openLoginForm(); + assertThat("Should be logged in", driver.getTitle(), containsString("AUTH_RESPONSE")); + + // revoke consent + userResource.revokeConsent(CONSUMER_BROKER_APP_CLIENT_ID); + + // list consents + consents = userResource.getConsents(); + assertThat("There should be no consents", consents, empty()); + + // list sessions + sessions = userResource.getUserSessions(); + assertThat("There should be one active session", sessions, hasSize(1)); + assertThat("There should be no client in user session", sessions.get(0).getClients(), aMapWithSize(0)); + + // Try relogging into the app after consent was revoked. + oauth.clientId(CONSUMER_BROKER_APP_CLIENT_ID); + oauth.openLoginForm(); + + WaitUtils.waitForPageToLoad(); + consentPage.assertCurrent(); + consentPage.confirm(); + + WaitUtils.waitForPageToLoad(); + assertThat("Should be logged in", driver.getTitle(), containsString("AUTH_RESPONSE")); + } + } + @Test public void testUserInfoEndpoint() throws Exception { EventRepresentation loginEvent = loginWithBrokerUsingOAuthClient(CONSUMER_BROKER_APP_CLIENT_ID); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/model/UserConsentModelTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/model/UserConsentModelTest.java index fb5e17a5be..9778ac26b0 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/model/UserConsentModelTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/model/UserConsentModelTest.java @@ -35,6 +35,7 @@ import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.protocol.oidc.OIDCLoginProtocol; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.services.managers.RealmManager; +import org.keycloak.services.managers.UserConsentManager; import org.keycloak.storage.client.ClientStorageProviderModel; import org.keycloak.testsuite.AbstractTestRealmKeycloakTest; import org.keycloak.testsuite.ProfileAssume; @@ -122,23 +123,23 @@ public class UserConsentModelTest extends AbstractTestRealmKeycloakTest { UserConsentModel johnFooGrant = new UserConsentModel(fooClient); johnFooGrant.addGrantedClientScope(fooScope); - realmManager.getSession().users().addConsent(realm, john.getId(), johnFooGrant); + UserConsentManager.addConsent(realmManager.getSession(), realm, john, johnFooGrant); UserConsentModel johnBarGrant = new UserConsentModel(barClient); johnBarGrant.addGrantedClientScope(barScope); // Update should fail as grant doesn't yet exists try { - realmManager.getSession().users().updateConsent(realm, john.getId(), johnBarGrant); + UserConsentManager.updateConsent(realmManager.getSession(), realm, john, johnBarGrant); Assert.fail("Not expected to end here"); } catch (ModelException expected) { } - realmManager.getSession().users().addConsent(realm, john.getId(), johnBarGrant); + UserConsentManager.addConsent(realmManager.getSession(), realm, john, johnBarGrant); UserConsentModel maryFooGrant = new UserConsentModel(fooClient); maryFooGrant.addGrantedClientScope(fooScope); - realmManager.getSession().users().addConsent(realm, mary.getId(), maryFooGrant); + UserConsentManager.addConsent(realmManager.getSession(), realm, mary, maryFooGrant); ClientStorageProviderModel clientStorage = new ClientStorageProviderModel(); clientStorage.setProviderId(HardcodedClientStorageProviderFactory.PROVIDER_ID); @@ -153,7 +154,7 @@ public class UserConsentModelTest extends AbstractTestRealmKeycloakTest { Assert.assertNotNull(hardcodedClient); UserConsentModel maryHardcodedGrant = new UserConsentModel(hardcodedClient); - realmManager.getSession().users().addConsent(realm, mary.getId(), maryHardcodedGrant); + UserConsentManager.addConsent(realmManager.getSession(), realm, mary, maryHardcodedGrant); realmId = realm.getId(); }); } @@ -173,32 +174,32 @@ public class UserConsentModelTest extends AbstractTestRealmKeycloakTest { UserModel john = currentSession.users().getUserByUsername(realm, "john"); UserModel mary = currentSession.users().getUserByUsername(realm, "mary"); - UserConsentModel johnFooConsent = currentSession.users().getConsentByClient(realm, john.getId(), fooClient.getId()); + UserConsentModel johnFooConsent = UserConsentManager.getConsentByClient(currentSession, realm, john, fooClient.getId()); Assert.assertEquals(johnFooConsent.getGrantedClientScopes().size(), 1); Assert.assertTrue(isClientScopeGranted(realm, "foo", johnFooConsent)); Assert.assertNotNull("Created Date should be set", johnFooConsent.getCreatedDate()); Assert.assertNotNull("Last Updated Date should be set", johnFooConsent.getLastUpdatedDate()); - UserConsentModel johnBarConsent = currentSession.users().getConsentByClient(realm, john.getId(), barClient.getId()); + UserConsentModel johnBarConsent = UserConsentManager.getConsentByClient(currentSession, realm, john, barClient.getId()); Assert.assertEquals(johnBarConsent.getGrantedClientScopes().size(), 1); Assert.assertTrue(isClientScopeGranted(realm, "bar", johnBarConsent)); Assert.assertNotNull("Created Date should be set", johnBarConsent.getCreatedDate()); Assert.assertNotNull("Last Updated Date should be set", johnBarConsent.getLastUpdatedDate()); - UserConsentModel maryConsent = currentSession.users().getConsentByClient(realm, mary.getId(), fooClient.getId()); + UserConsentModel maryConsent = UserConsentManager.getConsentByClient(currentSession, realm, mary, fooClient.getId()); Assert.assertEquals(maryConsent.getGrantedClientScopes().size(), 1); Assert.assertTrue(isClientScopeGranted(realm, "foo", maryConsent)); Assert.assertNotNull("Created Date should be set", maryConsent.getCreatedDate()); Assert.assertNotNull("Last Updated Date should be set", maryConsent.getLastUpdatedDate()); ClientModel hardcodedClient = currentSession.clients().getClientByClientId(realm, "hardcoded-client"); - UserConsentModel maryHardcodedConsent = currentSession.users().getConsentByClient(realm, mary.getId(), hardcodedClient.getId()); + UserConsentModel maryHardcodedConsent = UserConsentManager.getConsentByClient(currentSession, realm, mary, hardcodedClient.getId()); Assert.assertEquals(maryHardcodedConsent.getGrantedClientScopes().size(), 0); Assert.assertNotNull("Created Date should be set", maryHardcodedConsent.getCreatedDate()); Assert.assertNotNull("Last Updated Date should be set", maryHardcodedConsent.getLastUpdatedDate()); - Assert.assertNull(currentSession.users().getConsentByClient(realm, mary.getId(), barClient.getId())); - Assert.assertNull(currentSession.users().getConsentByClient(realm, john.getId(), hardcodedClient.getId())); + Assert.assertNull(UserConsentManager.getConsentByClient(currentSession, realm, mary, barClient.getId())); + Assert.assertNull(UserConsentManager.getConsentByClient(currentSession, realm, john, hardcodedClient.getId())); }); } @@ -215,11 +216,11 @@ public class UserConsentModelTest extends AbstractTestRealmKeycloakTest { UserModel john = currentSession.users().getUserByUsername(realm, "john"); UserModel mary = currentSession.users().getUserByUsername(realm, "mary"); - Assert.assertEquals(2, currentSession.users().getConsentsStream(realm, john.getId()).count()); + Assert.assertEquals(2, UserConsentManager.getConsentsStream(currentSession, realm, john).count()); ClientModel hardcodedClient = currentSession.clients().getClientByClientId(realm, "hardcoded-client"); - List maryConsents = currentSession.users().getConsentsStream(realm, mary.getId()) + List maryConsents = UserConsentManager.getConsentsStream(currentSession, realm, mary) .collect(Collectors.toList()); Assert.assertEquals(2, maryConsents.size()); UserConsentModel maryConsent = maryConsents.get(0); @@ -249,14 +250,14 @@ public class UserConsentModelTest extends AbstractTestRealmKeycloakTest { ClientModel fooClient = realm.getClientByClientId("foo-client"); UserModel john = currentSession.users().getUserByUsername(realm, "john"); - UserConsentModel johnConsent = currentSession.users().getConsentByClient(realm, john.getId(), fooClient.getId()); + UserConsentModel johnConsent = UserConsentManager.getConsentByClient(currentSession, realm, john, fooClient.getId()); Assert.assertEquals(1, johnConsent.getGrantedClientScopes().size()); // Remove foo protocol mapper from johnConsent ClientScopeModel fooScope = KeycloakModelUtils.getClientScopeByName(realm, "foo"); johnConsent.getGrantedClientScopes().remove(fooScope); - currentSession.users().updateConsent(realm, john.getId(), johnConsent); + UserConsentManager.updateConsent(currentSession, realm, john, johnConsent); }); KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession removalTestSession2) -> { @@ -265,7 +266,7 @@ public class UserConsentModelTest extends AbstractTestRealmKeycloakTest { ClientModel fooClient = realm.getClientByClientId("foo-client"); UserModel john = currentSession.users().getUserByUsername(realm, "john"); - UserConsentModel johnConsent = currentSession.users().getConsentByClient(realm, john.getId(), fooClient.getId()); + UserConsentModel johnConsent = UserConsentManager.getConsentByClient(currentSession, realm, john, fooClient.getId()); Assert.assertEquals(johnConsent.getGrantedClientScopes().size(), 0); Assert.assertTrue("Created date should be less than last updated date", johnConsent.getCreatedDate() < johnConsent.getLastUpdatedDate()); @@ -284,9 +285,9 @@ public class UserConsentModelTest extends AbstractTestRealmKeycloakTest { UserModel john = currentSession.users().getUserByUsername(realm, "john"); UserModel mary = currentSession.users().getUserByUsername(realm, "mary"); - currentSession.users().revokeConsentForClient(realm, john.getId(), fooClient.getId()); + UserConsentManager.revokeConsentForClient(currentSession, realm, john, fooClient.getId()); ClientModel hardcodedClient = currentSession.clients().getClientByClientId(realm, "hardcoded-client"); - currentSession.users().revokeConsentForClient(realm, mary.getId(), hardcodedClient.getId()); + UserConsentManager.revokeConsentForClient(currentSession, realm, mary, hardcodedClient.getId()); }); KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession sessionRT2) -> { @@ -297,9 +298,9 @@ public class UserConsentModelTest extends AbstractTestRealmKeycloakTest { ClientModel hardcodedClient = currentSession.clients().getClientByClientId(realm, "hardcoded-client"); UserModel john = currentSession.users().getUserByUsername(realm, "john"); - Assert.assertNull(currentSession.users().getConsentByClient(realm, john.getId(), fooClient.getId())); + Assert.assertNull(UserConsentManager.getConsentByClient(currentSession, realm, john, fooClient.getId())); UserModel mary = currentSession.users().getUserByUsername(realm, "mary"); - Assert.assertNull(currentSession.users().getConsentByClient(realm, mary.getId(), hardcodedClient.getId())); + Assert.assertNull(UserConsentManager.getConsentByClient(currentSession, realm, mary, hardcodedClient.getId())); }); } @@ -337,7 +338,7 @@ public class UserConsentModelTest extends AbstractTestRealmKeycloakTest { ClientModel fooClient = realm.getClientByClientId("foo-client"); UserModel john = currentSession.users().getUserByUsername(realm, "john"); - UserConsentModel johnConsent = currentSession.users().getConsentByClient(realm, john.getId(), fooClient.getId()); + UserConsentModel johnConsent = UserConsentManager.getConsentByClient(currentSession, realm, john, fooClient.getId()); Assert.assertEquals(johnConsent.getGrantedClientScopes().size(), 0); }); @@ -369,11 +370,11 @@ public class UserConsentModelTest extends AbstractTestRealmKeycloakTest { UserModel john = currentSession.users().getUserByUsername(realm, "john"); ClientModel barClient = realm.getClientByClientId("bar-client"); - UserConsentModel johnFooConsent = currentSession.users().getConsentByClient(realm, john.getId(), fooClient.getId()); + UserConsentModel johnFooConsent = UserConsentManager.getConsentByClient(currentSession, realm, john, fooClient.getId()); Assert.assertEquals(johnFooConsent.getGrantedClientScopes().size(), 1); Assert.assertTrue(isClientScopeGranted(realm, "foo", johnFooConsent)); - Assert.assertNull(currentSession.users().getConsentByClient(realm, john.getId(), barClientID.get())); + Assert.assertNull(UserConsentManager.getConsentByClient(currentSession, realm, john, barClientID.get())); }); } @@ -396,7 +397,7 @@ public class UserConsentModelTest extends AbstractTestRealmKeycloakTest { Assert.assertNull(hardcodedClient); UserModel mary = currentSession.users().getUserByUsername(realm, "mary"); - Assert.assertEquals(1, currentSession.users().getConsentsStream(realm, mary.getId()).count()); + Assert.assertEquals(1, UserConsentManager.getConsentsStream(currentSession, realm, mary).count()); }); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/model/UserConsentWithUserStorageModelTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/model/UserConsentWithUserStorageModelTest.java index e40dbd07ab..2f76b67910 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/model/UserConsentWithUserStorageModelTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/model/UserConsentWithUserStorageModelTest.java @@ -35,6 +35,7 @@ import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.protocol.oidc.OIDCLoginProtocol; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.services.managers.RealmManager; +import org.keycloak.services.managers.UserConsentManager; import org.keycloak.storage.UserStorageProviderModel; import org.keycloak.storage.client.ClientStorageProviderModel; import org.keycloak.testsuite.AbstractTestRealmKeycloakTest; @@ -124,23 +125,23 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo UserConsentModel johnFooGrant = new UserConsentModel(fooClient); johnFooGrant.addGrantedClientScope(fooScope); - realmManager.getSession().users().addConsent(realm, john.getId(), johnFooGrant); + UserConsentManager.addConsent(realmManager.getSession(), realm, john, johnFooGrant); UserConsentModel johnBarGrant = new UserConsentModel(barClient); johnBarGrant.addGrantedClientScope(barScope); // Update should fail as grant doesn't yet exists try { - currentSession.users().updateConsent(realm, john.getId(), johnBarGrant); + UserConsentManager.updateConsent(currentSession, realm, john, johnBarGrant); Assert.fail("Not expected to end here"); } catch (ModelException expected) { } - realmManager.getSession().users().addConsent(realm, john.getId(), johnBarGrant); + UserConsentManager.addConsent(realmManager.getSession(), realm, john, johnBarGrant); UserConsentModel maryFooGrant = new UserConsentModel(fooClient); maryFooGrant.addGrantedClientScope(fooScope); - realmManager.getSession().users().addConsent(realm, mary.getId(), maryFooGrant); + UserConsentManager.addConsent(realmManager.getSession(), realm, mary, maryFooGrant); ClientStorageProviderModel clientStorage = new ClientStorageProviderModel(); clientStorage.setProviderId(HardcodedClientStorageProviderFactory.PROVIDER_ID); @@ -155,7 +156,7 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo Assert.assertNotNull(hardcodedClient); UserConsentModel maryHardcodedGrant = new UserConsentModel(hardcodedClient); - realmManager.getSession().users().addConsent(realm, mary.getId(), maryHardcodedGrant); + UserConsentManager.addConsent(realmManager.getSession(), realm, mary, maryHardcodedGrant); }); } @@ -173,32 +174,32 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo UserModel john = currentSessionCT.users().getUserByUsername(realm, "john"); UserModel mary = currentSessionCT.users().getUserByUsername(realm, "mary"); - UserConsentModel johnFooConsent = currentSession.users().getConsentByClient(realm, john.getId(), fooClient.getId()); + UserConsentModel johnFooConsent = UserConsentManager.getConsentByClient(currentSession, realm, john, fooClient.getId()); Assert.assertEquals(johnFooConsent.getGrantedClientScopes().size(), 1); Assert.assertTrue(isClientScopeGranted(realm, "foo", johnFooConsent)); Assert.assertNotNull("Created Date should be set", johnFooConsent.getCreatedDate()); Assert.assertNotNull("Last Updated Date should be set", johnFooConsent.getLastUpdatedDate()); - UserConsentModel johnBarConsent = currentSession.users().getConsentByClient(realm, john.getId(), barClient.getId()); + UserConsentModel johnBarConsent = UserConsentManager.getConsentByClient(currentSession, realm, john, barClient.getId()); Assert.assertEquals(johnBarConsent.getGrantedClientScopes().size(), 1); Assert.assertTrue(isClientScopeGranted(realm, "bar", johnBarConsent)); Assert.assertNotNull("Created Date should be set", johnBarConsent.getCreatedDate()); Assert.assertNotNull("Last Updated Date should be set", johnBarConsent.getLastUpdatedDate()); - UserConsentModel maryConsent = currentSession.users().getConsentByClient(realm, mary.getId(), fooClient.getId()); + UserConsentModel maryConsent = UserConsentManager.getConsentByClient(currentSession, realm, mary, fooClient.getId()); Assert.assertEquals(maryConsent.getGrantedClientScopes().size(), 1); Assert.assertTrue(isClientScopeGranted(realm, "foo", maryConsent)); Assert.assertNotNull("Created Date should be set", maryConsent.getCreatedDate()); Assert.assertNotNull("Last Updated Date should be set", maryConsent.getLastUpdatedDate()); ClientModel hardcodedClient = currentSessionCT.clients().getClientByClientId(realm, "hardcoded-client"); - UserConsentModel maryHardcodedConsent = currentSession.users().getConsentByClient(realm, mary.getId(), hardcodedClient.getId()); + UserConsentModel maryHardcodedConsent = UserConsentManager.getConsentByClient(currentSession, realm, mary, hardcodedClient.getId()); Assert.assertEquals(maryHardcodedConsent.getGrantedClientScopes().size(), 0); Assert.assertNotNull("Created Date should be set", maryHardcodedConsent.getCreatedDate()); Assert.assertNotNull("Last Updated Date should be set", maryHardcodedConsent.getLastUpdatedDate()); - Assert.assertNull(currentSession.users().getConsentByClient(realm, mary.getId(), barClient.getId())); - Assert.assertNull(currentSession.users().getConsentByClient(realm, john.getId(), hardcodedClient.getId())); + Assert.assertNull(UserConsentManager.getConsentByClient(currentSession, realm, mary, barClient.getId())); + Assert.assertNull(UserConsentManager.getConsentByClient(currentSession, realm, john, hardcodedClient.getId())); }); } @@ -215,11 +216,11 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo UserModel john = currentSessionACT.users().getUserByUsername(realm, "john"); UserModel mary = currentSessionACT.users().getUserByUsername(realm, "mary"); - Assert.assertEquals(2, currentSession.users().getConsentsStream(realm, john.getId()).count()); + Assert.assertEquals(2, UserConsentManager.getConsentsStream(currentSession, realm, john).count()); ClientModel hardcodedClient = currentSessionACT.clients().getClientByClientId(realm, "hardcoded-client"); - List maryConsents = currentSession.users().getConsentsStream(realm, mary.getId()) + List maryConsents = UserConsentManager.getConsentsStream(currentSession, realm, mary) .collect(Collectors.toList()); Assert.assertEquals(2, maryConsents.size()); UserConsentModel maryConsent = maryConsents.get(0); @@ -249,14 +250,14 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo ClientModel fooClient = realm.getClientByClientId("foo-client"); UserModel john = currentSession.users().getUserByUsername(realm, "john"); - UserConsentModel johnConsent = currentSession.users().getConsentByClient(realm, john.getId(), fooClient.getId()); + UserConsentModel johnConsent = UserConsentManager.getConsentByClient(currentSession, realm, john, fooClient.getId()); Assert.assertEquals(1, johnConsent.getGrantedClientScopes().size()); // Remove foo protocol mapper from johnConsent ClientScopeModel fooScope = KeycloakModelUtils.getClientScopeByName(realm, "foo"); johnConsent.getGrantedClientScopes().remove(fooScope); - currentSession.users().updateConsent(realm, john.getId(), johnConsent); + UserConsentManager.updateConsent(currentSession, realm, john, johnConsent); }); KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession sessionScopeRemoval2) -> { @@ -265,7 +266,7 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo ClientModel fooClient = realm.getClientByClientId("foo-client"); UserModel john = currentSession.users().getUserByUsername(realm, "john"); - UserConsentModel johnConsent = currentSession.users().getConsentByClient(realm, john.getId(), fooClient.getId()); + UserConsentModel johnConsent = UserConsentManager.getConsentByClient(currentSession, realm, john, fooClient.getId()); Assert.assertEquals(johnConsent.getGrantedClientScopes().size(), 0); Assert.assertTrue("Created date should be less than last updated date", johnConsent.getCreatedDate() < johnConsent.getLastUpdatedDate()); @@ -284,9 +285,9 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo UserModel john = currentSession.users().getUserByUsername(realm, "john"); UserModel mary = currentSession.users().getUserByUsername(realm, "mary"); - currentSession.users().revokeConsentForClient(realm, john.getId(), fooClient.getId()); + UserConsentManager.revokeConsentForClient(currentSession, realm, john, fooClient.getId()); ClientModel hardcodedClient = currentSession.clients().getClientByClientId(realm, "hardcoded-client"); - currentSession.users().revokeConsentForClient(realm, mary.getId(), hardcodedClient.getId()); + UserConsentManager.revokeConsentForClient(currentSession, realm, mary, hardcodedClient.getId()); }); KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession sessionRevoke2) -> { @@ -297,10 +298,10 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo ClientModel hardcodedClient = currentSession.clients().getClientByClientId(realm, "hardcoded-client"); UserModel john = currentSession.users().getUserByUsername(realm, "john"); - Assert.assertNull(currentSession.users().getConsentByClient(realm, john.getId(), fooClient.getId())); + Assert.assertNull(UserConsentManager.getConsentByClient(currentSession, realm, john, fooClient.getId())); UserModel mary = currentSession.users().getUserByUsername(realm, "mary"); - Assert.assertNull(currentSession.users().getConsentByClient(realm, mary.getId(), hardcodedClient.getId())); + Assert.assertNull(UserConsentManager.getConsentByClient(currentSession, realm, mary, hardcodedClient.getId())); }); } @@ -339,7 +340,7 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo ClientModel fooClient = realm.getClientByClientId("foo-client"); UserModel john = currentSession.users().getUserByUsername(realm, "john"); - UserConsentModel johnConsent = currentSession.users().getConsentByClient(realm, john.getId(), fooClient.getId()); + UserConsentModel johnConsent = UserConsentManager.getConsentByClient(currentSession, realm, john, fooClient.getId()); Assert.assertEquals(johnConsent.getGrantedClientScopes().size(), 0); }); @@ -371,11 +372,11 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo UserModel john = realmManager.getSession().users().getUserByUsername(realm, "john"); - UserConsentModel johnFooConsent = realmManager.getSession().users().getConsentByClient(realm, john.getId(), fooClient.getId()); + UserConsentModel johnFooConsent = UserConsentManager.getConsentByClient(realmManager.getSession(), realm, john, fooClient.getId()); Assert.assertEquals(johnFooConsent.getGrantedClientScopes().size(), 1); Assert.assertTrue(isClientScopeGranted(realm, "foo", johnFooConsent)); - Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, john.getId(), barClientID.get())); + Assert.assertNull(UserConsentManager.getConsentByClient(realmManager.getSession(), realm, john, barClientID.get())); }); } @@ -398,7 +399,7 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo Assert.assertNull(hardcodedClient); UserModel mary = currentSession.users().getUserByUsername(realm, "mary"); - Assert.assertEquals(1, currentSession.users().getConsentsStream(realm, mary.getId()).count()); + Assert.assertEquals(1, UserConsentManager.getConsentsStream(currentSession, realm, mary).count()); }); }