Transient users: Consents (#24496)

closes #24494
This commit is contained in:
Hynek Mlnařík 2023-11-10 11:18:27 +01:00 committed by GitHub
parent 6963364514
commit 0ceaed0e2e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 490 additions and 86 deletions

View file

@ -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<String> 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<String> 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<String> getGrantedClientScopesIds() {
return grantedClientScopesIds;
}
public void removeGrantedClientScopesId(String clientScopeId) {
if (grantedClientScopesIds == null) {
return;
}
if (grantedClientScopesIds.remove(clientScopeId)) {
this.lastUpdatedDate = Time.currentTimeMillis();
}
}
public void setGrantedClientScopesIds(Set<String> 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;
}
}

View file

@ -19,11 +19,14 @@ package org.keycloak.models.light;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
import org.keycloak.common.Profile.Feature; import org.keycloak.common.Profile.Feature;
import org.keycloak.common.util.Base64; import org.keycloak.common.util.Base64;
import org.keycloak.models.ClientScopeModel;
import org.keycloak.models.GroupModel; import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelException;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.SubjectCredentialManager; import org.keycloak.models.SubjectCredentialManager;
import org.keycloak.models.UserConsentModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.UserModel.RequiredAction; import org.keycloak.models.UserModel.RequiredAction;
import org.keycloak.storage.adapter.AbstractInMemoryUserAdapter; import org.keycloak.storage.adapter.AbstractInMemoryUserAdapter;
@ -33,10 +36,13 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.JsonIncludeProperties; import com.fasterxml.jackson.annotation.JsonIncludeProperties;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.logging.Level; import java.util.stream.Collectors;
import java.util.logging.Logger; import java.util.stream.Stream;
/** /**
* *
@ -52,6 +58,7 @@ import java.util.logging.Logger;
"attributes", "attributes",
"requiredActions", "requiredActions",
"federationLink", "federationLink",
"consents",
"serviceAccountClientLink", "serviceAccountClientLink",
"readonly" "readonly"
}) })
@ -62,6 +69,8 @@ public class LightweightUserAdapter extends AbstractInMemoryUserAdapter {
public static final String ID_PREFIX = "lightweight-"; public static final String ID_PREFIX = "lightweight-";
private final Set<LightweightConsentEntity> consents = new HashSet<>();
public static boolean isLightweightUser(UserModel user) { public static boolean isLightweightUser(UserModel user) {
return Profile.isFeatureEnabled(Feature.TRANSIENT_USERS) && user instanceof LightweightUserAdapter; return Profile.isFeatureEnabled(Feature.TRANSIENT_USERS) && user instanceof LightweightUserAdapter;
} }
@ -116,115 +125,115 @@ public class LightweightUserAdapter extends AbstractInMemoryUserAdapter {
@Override @Override
public void deleteRoleMapping(RoleModel role) { public void deleteRoleMapping(RoleModel role) {
super.deleteRoleMapping(role); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody super.deleteRoleMapping(role);
update(); update();
} }
@Override @Override
public void grantRole(RoleModel role) { public void grantRole(RoleModel role) {
super.grantRole(role); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody super.grantRole(role);
update(); update();
} }
@Override @Override
public void setServiceAccountClientLink(String clientInternalId) { public void setServiceAccountClientLink(String clientInternalId) {
super.setServiceAccountClientLink(clientInternalId); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody super.setServiceAccountClientLink(clientInternalId);
update(); update();
} }
@Override @Override
public void setFederationLink(String link) { public void setFederationLink(String link) {
super.setFederationLink(link); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody super.setFederationLink(link);
update(); update();
} }
@Override @Override
public void leaveGroup(GroupModel group) { public void leaveGroup(GroupModel group) {
super.leaveGroup(group); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody super.leaveGroup(group);
update(); update();
} }
@Override @Override
public void joinGroup(GroupModel group) { public void joinGroup(GroupModel group) {
super.joinGroup(group); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody super.joinGroup(group);
update(); update();
} }
@Override @Override
public void setEmailVerified(boolean verified) { public void setEmailVerified(boolean verified) {
super.setEmailVerified(verified); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody super.setEmailVerified(verified);
update(); update();
} }
@Override @Override
public void removeRequiredAction(RequiredAction action) { public void removeRequiredAction(RequiredAction action) {
super.removeRequiredAction(action); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody super.removeRequiredAction(action);
update(); update();
} }
@Override @Override
public void addRequiredAction(RequiredAction action) { public void addRequiredAction(RequiredAction action) {
super.addRequiredAction(action); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody super.addRequiredAction(action);
update(); update();
} }
@Override @Override
public void removeRequiredAction(String action) { public void removeRequiredAction(String action) {
super.removeRequiredAction(action); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody super.removeRequiredAction(action);
update(); update();
} }
@Override @Override
public void addRequiredAction(String action) { public void addRequiredAction(String action) {
super.addRequiredAction(action); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody super.addRequiredAction(action);
update(); update();
} }
@Override @Override
public void removeAttribute(String name) { public void removeAttribute(String name) {
super.removeAttribute(name); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody super.removeAttribute(name);
update(); update();
} }
@Override @Override
public void setAttribute(String name, List<String> values) { public void setAttribute(String name, List<String> values) {
super.setAttribute(name, values); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody super.setAttribute(name, values);
update(); update();
} }
@Override @Override
public void setSingleAttribute(String name, String value) { 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(); update();
} }
@Override @Override
public void setEnabled(boolean enabled) { public void setEnabled(boolean enabled) {
super.setEnabled(enabled); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody super.setEnabled(enabled);
update(); update();
} }
@Override @Override
public void setCreatedTimestamp(Long timestamp) { public void setCreatedTimestamp(Long timestamp) {
super.setCreatedTimestamp(timestamp); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody super.setCreatedTimestamp(timestamp);
update(); update();
} }
@Override @Override
public void setReadonly(boolean flag) { public void setReadonly(boolean flag) {
super.setReadonly(flag); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody super.setReadonly(flag);
update(); update();
} }
@Override @Override
public void addDefaults() { public void addDefaults() {
super.addDefaults(); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody super.addDefaults();
update(); update();
} }
@Override @Override
public void setUsername(String username) { public void setUsername(String username) {
super.setUsername(username); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/OverriddenMethodBody super.setUsername(username);
update(); update();
} }
@ -236,4 +245,56 @@ public class LightweightUserAdapter extends AbstractInMemoryUserAdapter {
updateHandler.accept(this); 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<UserConsentModel> getConsentsStream() {
return consents.stream()
.map(lce -> LightweightConsentEntity.toModel(realm, lce));
}
} }

View file

@ -82,6 +82,7 @@ import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.Urls; import org.keycloak.services.Urls;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.AuthenticationSessionManager; import org.keycloak.services.managers.AuthenticationSessionManager;
import org.keycloak.services.managers.UserConsentManager;
import org.keycloak.services.managers.UserSessionCrossDCManager; import org.keycloak.services.managers.UserSessionCrossDCManager;
import org.keycloak.services.managers.UserSessionManager; import org.keycloak.services.managers.UserSessionManager;
import org.keycloak.services.resources.IdentityBrokerService; import org.keycloak.services.resources.IdentityBrokerService;
@ -744,7 +745,7 @@ public class TokenManager {
return true; 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 return requestedClientScopes
.filter(ClientScopeModel::isDisplayOnConsentScreen) .filter(ClientScopeModel::isDisplayOnConsentScreen)

View file

@ -51,6 +51,7 @@ import org.keycloak.services.CorsErrorResponseException;
import org.keycloak.services.clientpolicy.ClientPolicyException; import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.clientpolicy.context.TokenRevokeContext; import org.keycloak.services.clientpolicy.context.TokenRevokeContext;
import org.keycloak.services.clientpolicy.context.TokenRevokeResponseContext; import org.keycloak.services.clientpolicy.context.TokenRevokeResponseContext;
import org.keycloak.services.managers.UserConsentManager;
import org.keycloak.services.managers.UserSessionCrossDCManager; import org.keycloak.services.managers.UserSessionCrossDCManager;
import org.keycloak.services.managers.UserSessionManager; import org.keycloak.services.managers.UserSessionManager;
import org.keycloak.services.resources.Cors; import org.keycloak.services.resources.Cors;
@ -241,7 +242,7 @@ public class TokenRevocationEndpoint {
} }
private void revokeClient() { 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())) { if (TokenUtil.TOKEN_TYPE_OFFLINE.equals(token.getType())) {
new UserSessionManager(session).revokeOfflineToken(user, client); new UserSessionManager(session).revokeOfflineToken(user, client);
} }

View file

@ -55,6 +55,7 @@ import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.Urls; import org.keycloak.services.Urls;
import org.keycloak.services.clientpolicy.ClientPolicyException; import org.keycloak.services.clientpolicy.ClientPolicyException;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.UserConsentManager;
import org.keycloak.services.resources.Cors; import org.keycloak.services.resources.Cors;
import org.keycloak.services.util.DefaultClientSessionContext; import org.keycloak.services.util.DefaultClientSessionContext;
import org.keycloak.sessions.AuthenticationSessionModel; import org.keycloak.sessions.AuthenticationSessionModel;
@ -268,10 +269,10 @@ public class CibaGrantType {
} }
// authorization (consent) // authorization (consent)
UserConsentModel grantedConsent = session.users().getConsentByClient(realm, user.getId(), client.getId()); UserConsentModel grantedConsent = UserConsentManager.getConsentByClient(session, realm, user, client.getId());
if (grantedConsent == null) { if (grantedConsent == null) {
grantedConsent = new UserConsentModel(client); grantedConsent = new UserConsentModel(client);
session.users().addConsent(realm, user.getId(), grantedConsent); UserConsentManager.addConsent(session, realm, user, grantedConsent);
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
grantedConsent.getGrantedClientScopes().forEach(i->logger.tracef("CIBA Grant :: Consent granted. %s", i.getName())); grantedConsent.getGrantedClientScopes().forEach(i->logger.tracef("CIBA Grant :: Consent granted. %s", i.getName()));
} }
@ -288,7 +289,7 @@ public class CibaGrantType {
} }
if (updateConsentRequired) { if (updateConsentRequired) {
session.users().updateConsent(realm, user.getId(), grantedConsent); UserConsentManager.updateConsent(session, realm, user, grantedConsent);
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
grantedConsent.getGrantedClientScopes().forEach(i->logger.tracef("CIBA Grant :: Consent updated. %s", i.getName())); grantedConsent.getGrantedClientScopes().forEach(i->logger.tracef("CIBA Grant :: Consent updated. %s", i.getName()));
} }

View file

@ -1150,7 +1150,7 @@ public class AuthenticationManager {
final UserModel user = authSession.getAuthenticatedUser(); final UserModel user = authSession.getAuthenticatedUser();
final ClientModel client = authSession.getClient(); final ClientModel client = authSession.getClient();
return session.users().getConsentByClient(realm, user.getId(), client.getId()); return UserConsentManager.getConsentByClient(session, realm, user, client.getId());
} }
} }

View file

@ -20,8 +20,13 @@ package org.keycloak.services.managers;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelException;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserConsentModel;
import org.keycloak.models.UserModel; 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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -38,7 +43,7 @@ public class UserConsentManager {
*/ */
public static boolean revokeConsentToClient(KeycloakSession session, ClientModel client, UserModel user) { public static boolean revokeConsentToClient(KeycloakSession session, ClientModel client, UserModel user) {
RealmModel realm = session.getContext().getRealm(); 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); boolean revokedOfflineToken = new UserSessionManager(session).revokeOfflineToken(user, client);
if (revokedConsent) { if (revokedConsent) {
@ -48,4 +53,95 @@ public class UserConsentManager {
return revokedConsent || revokedOfflineToken; 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<UserConsentModel> 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);
}
}
} }

View file

@ -82,6 +82,7 @@ import org.keycloak.services.Urls;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.AuthenticationSessionManager; import org.keycloak.services.managers.AuthenticationSessionManager;
import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.managers.UserConsentManager;
import org.keycloak.services.messages.Messages; import org.keycloak.services.messages.Messages;
import org.keycloak.services.util.AuthenticationFlowURLHelper; import org.keycloak.services.util.AuthenticationFlowURLHelper;
import org.keycloak.services.util.BrowserHistoryHelper; import org.keycloak.services.util.BrowserHistoryHelper;
@ -962,10 +963,10 @@ public class LoginActionsService {
return response; return response;
} }
UserConsentModel grantedConsent = session.users().getConsentByClient(realm, user.getId(), client.getId()); UserConsentModel grantedConsent = UserConsentManager.getConsentByClient(session, realm, user, client.getId());
if (grantedConsent == null) { if (grantedConsent == null) {
grantedConsent = new UserConsentModel(client); 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) // 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) { if (updateConsentRequired) {
session.users().updateConsent(realm, user.getId(), grantedConsent); UserConsentManager.updateConsent(session, realm, user, grantedConsent);
} }
event.detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED); event.detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED);

View file

@ -314,7 +314,7 @@ public class AccountRestService {
throw ErrorResponse.error("No client with clientId: " + clientId + " found.", Response.Status.NOT_FOUND); 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) { if (consent == null) {
return Response.noContent().build(); return Response.noContent().build();
} }
@ -403,17 +403,17 @@ public class AccountRestService {
try { try {
UserConsentModel grantedConsent = createConsent(client, consent); UserConsentModel grantedConsent = createConsent(client, consent);
if (session.users().getConsentByClient(realm, user.getId(), client.getId()) == null) { if (UserConsentManager.getConsentByClient(session, realm, user, client.getId()) == null) {
session.users().addConsent(realm, user.getId(), grantedConsent); UserConsentManager.addConsent(session, realm, user, grantedConsent);
event.event(EventType.GRANT_CONSENT); event.event(EventType.GRANT_CONSENT);
} else { } else {
session.users().updateConsent(realm, user.getId(), grantedConsent); UserConsentManager.updateConsent(session, realm, user, grantedConsent);
event.event(EventType.UPDATE_CONSENT); event.event(EventType.UPDATE_CONSENT);
} }
event.detail(Details.GRANTED_CLIENT,client.getClientId()); event.detail(Details.GRANTED_CLIENT,client.getClientId());
String scopeString = grantedConsent.getGrantedClientScopes().stream().map(cs->cs.getName()).collect(Collectors.joining(" ")); String scopeString = grantedConsent.getGrantedClientScopes().stream().map(cs->cs.getName()).collect(Collectors.joining(" "));
event.detail(Details.SCOPE, scopeString).success(); 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(); return Response.ok(modelToRepresentation(grantedConsent)).build();
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw ErrorResponse.error(e.getMessage(), Response.Status.BAD_REQUEST); throw ErrorResponse.error(e.getMessage(), Response.Status.BAD_REQUEST);
@ -490,7 +490,7 @@ public class AccountRestService {
.collect(Collectors.toSet())); .collect(Collectors.toSet()));
Map<String, UserConsentModel> consentModels = new HashMap<>(); Map<String, UserConsentModel> 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)) .peek(consent -> consentModels.put(consent.getClient().getClientId(), consent))
.map(UserConsentModel::getClient) .map(UserConsentModel::getClient)
.collect(Collectors.toSet())); .collect(Collectors.toSet()));

View file

@ -525,7 +525,7 @@ public class UserResource {
Set<ClientModel> offlineClients = new UserSessionManager(session).findClientsWithOfflineToken(realm, user); Set<ClientModel> offlineClients = new UserSessionManager(session).findClientsWithOfflineToken(realm, user);
Set<ClientModel> clientsWithUserConsents = new HashSet<>(); Set<ClientModel> clientsWithUserConsents = new HashSet<>();
List<UserConsentModel> userConsents = session.users().getConsentsStream(realm, user.getId()) List<UserConsentModel> userConsents = UserConsentManager.getConsentsStream(session, realm, user)
// collect clients with explicit user consents for later filtering // collect clients with explicit user consents for later filtering
.peek(ucm -> clientsWithUserConsents.add(ucm.getClient())) .peek(ucm -> clientsWithUserConsents.add(ucm.getClient()))
.collect(Collectors.toList()); .collect(Collectors.toList());

View file

@ -49,9 +49,11 @@ import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.UserSessionRepresentation;
import org.keycloak.testsuite.Assert; import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.AssertEvents; import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.arquillian.annotation.EnableFeature; import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
import org.keycloak.testsuite.updaters.ClientAttributeUpdater;
import org.keycloak.testsuite.updaters.Creator; import org.keycloak.testsuite.updaters.Creator;
import org.keycloak.testsuite.util.AccountHelper; import org.keycloak.testsuite.util.AccountHelper;
import org.keycloak.testsuite.util.OAuthClient; import org.keycloak.testsuite.util.OAuthClient;
@ -74,14 +76,18 @@ import java.util.stream.Collectors;
import org.junit.Rule; import org.junit.Rule;
import static org.hamcrest.MatcherAssert.assertThat; 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.empty;
import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; 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_CONS_NAME;
import static org.keycloak.testsuite.broker.BrokerTestConstants.REALM_PROV_NAME; import static org.keycloak.testsuite.broker.BrokerTestConstants.REALM_PROV_NAME;
import static org.keycloak.testsuite.broker.BrokerTestTools.getConsumerRoot; 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")); 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<Map<String, Object>> consents = userResource.getConsents();
assertThat("There should be one consent", consents, hasSize(1));
Map<String, Object> 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<UserSessionRepresentation> 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 @Test
public void testUserInfoEndpoint() throws Exception { public void testUserInfoEndpoint() throws Exception {
EventRepresentation loginEvent = loginWithBrokerUsingOAuthClient(CONSUMER_BROKER_APP_CLIENT_ID); EventRepresentation loginEvent = loginWithBrokerUsingOAuthClient(CONSUMER_BROKER_APP_CLIENT_ID);

View file

@ -35,6 +35,7 @@ import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.oidc.OIDCLoginProtocol; import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.UserConsentManager;
import org.keycloak.storage.client.ClientStorageProviderModel; import org.keycloak.storage.client.ClientStorageProviderModel;
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest; import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
import org.keycloak.testsuite.ProfileAssume; import org.keycloak.testsuite.ProfileAssume;
@ -122,23 +123,23 @@ public class UserConsentModelTest extends AbstractTestRealmKeycloakTest {
UserConsentModel johnFooGrant = new UserConsentModel(fooClient); UserConsentModel johnFooGrant = new UserConsentModel(fooClient);
johnFooGrant.addGrantedClientScope(fooScope); johnFooGrant.addGrantedClientScope(fooScope);
realmManager.getSession().users().addConsent(realm, john.getId(), johnFooGrant); UserConsentManager.addConsent(realmManager.getSession(), realm, john, johnFooGrant);
UserConsentModel johnBarGrant = new UserConsentModel(barClient); UserConsentModel johnBarGrant = new UserConsentModel(barClient);
johnBarGrant.addGrantedClientScope(barScope); johnBarGrant.addGrantedClientScope(barScope);
// Update should fail as grant doesn't yet exists // Update should fail as grant doesn't yet exists
try { try {
realmManager.getSession().users().updateConsent(realm, john.getId(), johnBarGrant); UserConsentManager.updateConsent(realmManager.getSession(), realm, john, johnBarGrant);
Assert.fail("Not expected to end here"); Assert.fail("Not expected to end here");
} catch (ModelException expected) { } catch (ModelException expected) {
} }
realmManager.getSession().users().addConsent(realm, john.getId(), johnBarGrant); UserConsentManager.addConsent(realmManager.getSession(), realm, john, johnBarGrant);
UserConsentModel maryFooGrant = new UserConsentModel(fooClient); UserConsentModel maryFooGrant = new UserConsentModel(fooClient);
maryFooGrant.addGrantedClientScope(fooScope); maryFooGrant.addGrantedClientScope(fooScope);
realmManager.getSession().users().addConsent(realm, mary.getId(), maryFooGrant); UserConsentManager.addConsent(realmManager.getSession(), realm, mary, maryFooGrant);
ClientStorageProviderModel clientStorage = new ClientStorageProviderModel(); ClientStorageProviderModel clientStorage = new ClientStorageProviderModel();
clientStorage.setProviderId(HardcodedClientStorageProviderFactory.PROVIDER_ID); clientStorage.setProviderId(HardcodedClientStorageProviderFactory.PROVIDER_ID);
@ -153,7 +154,7 @@ public class UserConsentModelTest extends AbstractTestRealmKeycloakTest {
Assert.assertNotNull(hardcodedClient); Assert.assertNotNull(hardcodedClient);
UserConsentModel maryHardcodedGrant = new UserConsentModel(hardcodedClient); UserConsentModel maryHardcodedGrant = new UserConsentModel(hardcodedClient);
realmManager.getSession().users().addConsent(realm, mary.getId(), maryHardcodedGrant); UserConsentManager.addConsent(realmManager.getSession(), realm, mary, maryHardcodedGrant);
realmId = realm.getId(); realmId = realm.getId();
}); });
} }
@ -173,32 +174,32 @@ public class UserConsentModelTest extends AbstractTestRealmKeycloakTest {
UserModel john = currentSession.users().getUserByUsername(realm, "john"); UserModel john = currentSession.users().getUserByUsername(realm, "john");
UserModel mary = currentSession.users().getUserByUsername(realm, "mary"); 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.assertEquals(johnFooConsent.getGrantedClientScopes().size(), 1);
Assert.assertTrue(isClientScopeGranted(realm, "foo", johnFooConsent)); Assert.assertTrue(isClientScopeGranted(realm, "foo", johnFooConsent));
Assert.assertNotNull("Created Date should be set", johnFooConsent.getCreatedDate()); Assert.assertNotNull("Created Date should be set", johnFooConsent.getCreatedDate());
Assert.assertNotNull("Last Updated Date should be set", johnFooConsent.getLastUpdatedDate()); 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.assertEquals(johnBarConsent.getGrantedClientScopes().size(), 1);
Assert.assertTrue(isClientScopeGranted(realm, "bar", johnBarConsent)); Assert.assertTrue(isClientScopeGranted(realm, "bar", johnBarConsent));
Assert.assertNotNull("Created Date should be set", johnBarConsent.getCreatedDate()); Assert.assertNotNull("Created Date should be set", johnBarConsent.getCreatedDate());
Assert.assertNotNull("Last Updated Date should be set", johnBarConsent.getLastUpdatedDate()); 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.assertEquals(maryConsent.getGrantedClientScopes().size(), 1);
Assert.assertTrue(isClientScopeGranted(realm, "foo", maryConsent)); Assert.assertTrue(isClientScopeGranted(realm, "foo", maryConsent));
Assert.assertNotNull("Created Date should be set", maryConsent.getCreatedDate()); Assert.assertNotNull("Created Date should be set", maryConsent.getCreatedDate());
Assert.assertNotNull("Last Updated Date should be set", maryConsent.getLastUpdatedDate()); Assert.assertNotNull("Last Updated Date should be set", maryConsent.getLastUpdatedDate());
ClientModel hardcodedClient = currentSession.clients().getClientByClientId(realm, "hardcoded-client"); 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.assertEquals(maryHardcodedConsent.getGrantedClientScopes().size(), 0);
Assert.assertNotNull("Created Date should be set", maryHardcodedConsent.getCreatedDate()); Assert.assertNotNull("Created Date should be set", maryHardcodedConsent.getCreatedDate());
Assert.assertNotNull("Last Updated Date should be set", maryHardcodedConsent.getLastUpdatedDate()); Assert.assertNotNull("Last Updated Date should be set", maryHardcodedConsent.getLastUpdatedDate());
Assert.assertNull(currentSession.users().getConsentByClient(realm, mary.getId(), barClient.getId())); Assert.assertNull(UserConsentManager.getConsentByClient(currentSession, realm, mary, barClient.getId()));
Assert.assertNull(currentSession.users().getConsentByClient(realm, john.getId(), hardcodedClient.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 john = currentSession.users().getUserByUsername(realm, "john");
UserModel mary = currentSession.users().getUserByUsername(realm, "mary"); 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"); ClientModel hardcodedClient = currentSession.clients().getClientByClientId(realm, "hardcoded-client");
List<UserConsentModel> maryConsents = currentSession.users().getConsentsStream(realm, mary.getId()) List<UserConsentModel> maryConsents = UserConsentManager.getConsentsStream(currentSession, realm, mary)
.collect(Collectors.toList()); .collect(Collectors.toList());
Assert.assertEquals(2, maryConsents.size()); Assert.assertEquals(2, maryConsents.size());
UserConsentModel maryConsent = maryConsents.get(0); UserConsentModel maryConsent = maryConsents.get(0);
@ -249,14 +250,14 @@ public class UserConsentModelTest extends AbstractTestRealmKeycloakTest {
ClientModel fooClient = realm.getClientByClientId("foo-client"); ClientModel fooClient = realm.getClientByClientId("foo-client");
UserModel john = currentSession.users().getUserByUsername(realm, "john"); 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()); Assert.assertEquals(1, johnConsent.getGrantedClientScopes().size());
// Remove foo protocol mapper from johnConsent // Remove foo protocol mapper from johnConsent
ClientScopeModel fooScope = KeycloakModelUtils.getClientScopeByName(realm, "foo"); ClientScopeModel fooScope = KeycloakModelUtils.getClientScopeByName(realm, "foo");
johnConsent.getGrantedClientScopes().remove(fooScope); johnConsent.getGrantedClientScopes().remove(fooScope);
currentSession.users().updateConsent(realm, john.getId(), johnConsent); UserConsentManager.updateConsent(currentSession, realm, john, johnConsent);
}); });
KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession removalTestSession2) -> { KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession removalTestSession2) -> {
@ -265,7 +266,7 @@ public class UserConsentModelTest extends AbstractTestRealmKeycloakTest {
ClientModel fooClient = realm.getClientByClientId("foo-client"); ClientModel fooClient = realm.getClientByClientId("foo-client");
UserModel john = currentSession.users().getUserByUsername(realm, "john"); 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.assertEquals(johnConsent.getGrantedClientScopes().size(), 0);
Assert.assertTrue("Created date should be less than last updated date", johnConsent.getCreatedDate() < johnConsent.getLastUpdatedDate()); 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 john = currentSession.users().getUserByUsername(realm, "john");
UserModel mary = currentSession.users().getUserByUsername(realm, "mary"); 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"); 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) -> { KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession sessionRT2) -> {
@ -297,9 +298,9 @@ public class UserConsentModelTest extends AbstractTestRealmKeycloakTest {
ClientModel hardcodedClient = currentSession.clients().getClientByClientId(realm, "hardcoded-client"); ClientModel hardcodedClient = currentSession.clients().getClientByClientId(realm, "hardcoded-client");
UserModel john = currentSession.users().getUserByUsername(realm, "john"); 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"); 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"); ClientModel fooClient = realm.getClientByClientId("foo-client");
UserModel john = currentSession.users().getUserByUsername(realm, "john"); 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.assertEquals(johnConsent.getGrantedClientScopes().size(), 0);
}); });
@ -369,11 +370,11 @@ public class UserConsentModelTest extends AbstractTestRealmKeycloakTest {
UserModel john = currentSession.users().getUserByUsername(realm, "john"); UserModel john = currentSession.users().getUserByUsername(realm, "john");
ClientModel barClient = realm.getClientByClientId("bar-client"); 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.assertEquals(johnFooConsent.getGrantedClientScopes().size(), 1);
Assert.assertTrue(isClientScopeGranted(realm, "foo", johnFooConsent)); 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); Assert.assertNull(hardcodedClient);
UserModel mary = currentSession.users().getUserByUsername(realm, "mary"); 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());
}); });
} }

View file

@ -35,6 +35,7 @@ import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.oidc.OIDCLoginProtocol; import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.UserConsentManager;
import org.keycloak.storage.UserStorageProviderModel; import org.keycloak.storage.UserStorageProviderModel;
import org.keycloak.storage.client.ClientStorageProviderModel; import org.keycloak.storage.client.ClientStorageProviderModel;
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest; import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
@ -124,23 +125,23 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo
UserConsentModel johnFooGrant = new UserConsentModel(fooClient); UserConsentModel johnFooGrant = new UserConsentModel(fooClient);
johnFooGrant.addGrantedClientScope(fooScope); johnFooGrant.addGrantedClientScope(fooScope);
realmManager.getSession().users().addConsent(realm, john.getId(), johnFooGrant); UserConsentManager.addConsent(realmManager.getSession(), realm, john, johnFooGrant);
UserConsentModel johnBarGrant = new UserConsentModel(barClient); UserConsentModel johnBarGrant = new UserConsentModel(barClient);
johnBarGrant.addGrantedClientScope(barScope); johnBarGrant.addGrantedClientScope(barScope);
// Update should fail as grant doesn't yet exists // Update should fail as grant doesn't yet exists
try { try {
currentSession.users().updateConsent(realm, john.getId(), johnBarGrant); UserConsentManager.updateConsent(currentSession, realm, john, johnBarGrant);
Assert.fail("Not expected to end here"); Assert.fail("Not expected to end here");
} catch (ModelException expected) { } catch (ModelException expected) {
} }
realmManager.getSession().users().addConsent(realm, john.getId(), johnBarGrant); UserConsentManager.addConsent(realmManager.getSession(), realm, john, johnBarGrant);
UserConsentModel maryFooGrant = new UserConsentModel(fooClient); UserConsentModel maryFooGrant = new UserConsentModel(fooClient);
maryFooGrant.addGrantedClientScope(fooScope); maryFooGrant.addGrantedClientScope(fooScope);
realmManager.getSession().users().addConsent(realm, mary.getId(), maryFooGrant); UserConsentManager.addConsent(realmManager.getSession(), realm, mary, maryFooGrant);
ClientStorageProviderModel clientStorage = new ClientStorageProviderModel(); ClientStorageProviderModel clientStorage = new ClientStorageProviderModel();
clientStorage.setProviderId(HardcodedClientStorageProviderFactory.PROVIDER_ID); clientStorage.setProviderId(HardcodedClientStorageProviderFactory.PROVIDER_ID);
@ -155,7 +156,7 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo
Assert.assertNotNull(hardcodedClient); Assert.assertNotNull(hardcodedClient);
UserConsentModel maryHardcodedGrant = new UserConsentModel(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 john = currentSessionCT.users().getUserByUsername(realm, "john");
UserModel mary = currentSessionCT.users().getUserByUsername(realm, "mary"); 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.assertEquals(johnFooConsent.getGrantedClientScopes().size(), 1);
Assert.assertTrue(isClientScopeGranted(realm, "foo", johnFooConsent)); Assert.assertTrue(isClientScopeGranted(realm, "foo", johnFooConsent));
Assert.assertNotNull("Created Date should be set", johnFooConsent.getCreatedDate()); Assert.assertNotNull("Created Date should be set", johnFooConsent.getCreatedDate());
Assert.assertNotNull("Last Updated Date should be set", johnFooConsent.getLastUpdatedDate()); 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.assertEquals(johnBarConsent.getGrantedClientScopes().size(), 1);
Assert.assertTrue(isClientScopeGranted(realm, "bar", johnBarConsent)); Assert.assertTrue(isClientScopeGranted(realm, "bar", johnBarConsent));
Assert.assertNotNull("Created Date should be set", johnBarConsent.getCreatedDate()); Assert.assertNotNull("Created Date should be set", johnBarConsent.getCreatedDate());
Assert.assertNotNull("Last Updated Date should be set", johnBarConsent.getLastUpdatedDate()); 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.assertEquals(maryConsent.getGrantedClientScopes().size(), 1);
Assert.assertTrue(isClientScopeGranted(realm, "foo", maryConsent)); Assert.assertTrue(isClientScopeGranted(realm, "foo", maryConsent));
Assert.assertNotNull("Created Date should be set", maryConsent.getCreatedDate()); Assert.assertNotNull("Created Date should be set", maryConsent.getCreatedDate());
Assert.assertNotNull("Last Updated Date should be set", maryConsent.getLastUpdatedDate()); Assert.assertNotNull("Last Updated Date should be set", maryConsent.getLastUpdatedDate());
ClientModel hardcodedClient = currentSessionCT.clients().getClientByClientId(realm, "hardcoded-client"); 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.assertEquals(maryHardcodedConsent.getGrantedClientScopes().size(), 0);
Assert.assertNotNull("Created Date should be set", maryHardcodedConsent.getCreatedDate()); Assert.assertNotNull("Created Date should be set", maryHardcodedConsent.getCreatedDate());
Assert.assertNotNull("Last Updated Date should be set", maryHardcodedConsent.getLastUpdatedDate()); Assert.assertNotNull("Last Updated Date should be set", maryHardcodedConsent.getLastUpdatedDate());
Assert.assertNull(currentSession.users().getConsentByClient(realm, mary.getId(), barClient.getId())); Assert.assertNull(UserConsentManager.getConsentByClient(currentSession, realm, mary, barClient.getId()));
Assert.assertNull(currentSession.users().getConsentByClient(realm, john.getId(), hardcodedClient.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 john = currentSessionACT.users().getUserByUsername(realm, "john");
UserModel mary = currentSessionACT.users().getUserByUsername(realm, "mary"); 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"); ClientModel hardcodedClient = currentSessionACT.clients().getClientByClientId(realm, "hardcoded-client");
List<UserConsentModel> maryConsents = currentSession.users().getConsentsStream(realm, mary.getId()) List<UserConsentModel> maryConsents = UserConsentManager.getConsentsStream(currentSession, realm, mary)
.collect(Collectors.toList()); .collect(Collectors.toList());
Assert.assertEquals(2, maryConsents.size()); Assert.assertEquals(2, maryConsents.size());
UserConsentModel maryConsent = maryConsents.get(0); UserConsentModel maryConsent = maryConsents.get(0);
@ -249,14 +250,14 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo
ClientModel fooClient = realm.getClientByClientId("foo-client"); ClientModel fooClient = realm.getClientByClientId("foo-client");
UserModel john = currentSession.users().getUserByUsername(realm, "john"); 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()); Assert.assertEquals(1, johnConsent.getGrantedClientScopes().size());
// Remove foo protocol mapper from johnConsent // Remove foo protocol mapper from johnConsent
ClientScopeModel fooScope = KeycloakModelUtils.getClientScopeByName(realm, "foo"); ClientScopeModel fooScope = KeycloakModelUtils.getClientScopeByName(realm, "foo");
johnConsent.getGrantedClientScopes().remove(fooScope); johnConsent.getGrantedClientScopes().remove(fooScope);
currentSession.users().updateConsent(realm, john.getId(), johnConsent); UserConsentManager.updateConsent(currentSession, realm, john, johnConsent);
}); });
KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession sessionScopeRemoval2) -> { KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession sessionScopeRemoval2) -> {
@ -265,7 +266,7 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo
ClientModel fooClient = realm.getClientByClientId("foo-client"); ClientModel fooClient = realm.getClientByClientId("foo-client");
UserModel john = currentSession.users().getUserByUsername(realm, "john"); 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.assertEquals(johnConsent.getGrantedClientScopes().size(), 0);
Assert.assertTrue("Created date should be less than last updated date", johnConsent.getCreatedDate() < johnConsent.getLastUpdatedDate()); 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 john = currentSession.users().getUserByUsername(realm, "john");
UserModel mary = currentSession.users().getUserByUsername(realm, "mary"); 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"); 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) -> { KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), (KeycloakSession sessionRevoke2) -> {
@ -297,10 +298,10 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo
ClientModel hardcodedClient = currentSession.clients().getClientByClientId(realm, "hardcoded-client"); ClientModel hardcodedClient = currentSession.clients().getClientByClientId(realm, "hardcoded-client");
UserModel john = currentSession.users().getUserByUsername(realm, "john"); 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"); 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"); ClientModel fooClient = realm.getClientByClientId("foo-client");
UserModel john = currentSession.users().getUserByUsername(realm, "john"); 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.assertEquals(johnConsent.getGrantedClientScopes().size(), 0);
}); });
@ -371,11 +372,11 @@ public class UserConsentWithUserStorageModelTest extends AbstractTestRealmKeyclo
UserModel john = realmManager.getSession().users().getUserByUsername(realm, "john"); 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.assertEquals(johnFooConsent.getGrantedClientScopes().size(), 1);
Assert.assertTrue(isClientScopeGranted(realm, "foo", johnFooConsent)); 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); Assert.assertNull(hardcodedClient);
UserModel mary = currentSession.users().getUserByUsername(realm, "mary"); 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());
}); });
} }