hynek db changes

This commit is contained in:
Bill Burke 2018-01-30 17:00:55 -05:00
parent 4a044fe867
commit a571781240
15 changed files with 411 additions and 77 deletions

View file

@ -54,6 +54,7 @@ import org.keycloak.storage.CacheableStorageProviderModel;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.UserStorageProvider;
import org.keycloak.storage.UserStorageProviderModel;
import org.keycloak.storage.client.ClientStorageProvider;
import java.util.Calendar;
import java.util.HashMap;
@ -853,7 +854,7 @@ public class UserCacheSession implements UserCache {
@Override
public void preRemove(RealmModel realm, ComponentModel component) {
if (!component.getProviderType().equals(UserStorageProvider.class.getName())) return;
if (!component.getProviderType().equals(UserStorageProvider.class.getName()) && !component.getProviderType().equals(ClientStorageProvider.class.getName())) return;
addRealmInvalidation(realm.getId()); // easier to just invalidate whole realm
getDelegate().preRemove(realm, component);

View file

@ -45,7 +45,9 @@ import org.keycloak.models.jpa.entities.UserConsentRoleEntity;
import org.keycloak.models.jpa.entities.UserEntity;
import org.keycloak.models.utils.DefaultRoles;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.UserStorageProvider;
import org.keycloak.storage.client.ClientStorageProvider;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
@ -194,7 +196,14 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
consentEntity = new UserConsentEntity();
consentEntity.setId(KeycloakModelUtils.generateId());
consentEntity.setUser(em.getReference(UserEntity.class, userId));
StorageId clientStorageId = new StorageId(clientId);
if (clientStorageId.isLocal()) {
consentEntity.setClientId(clientId);
} else {
consentEntity.setClientStorageProvider(clientStorageId.getProviderId());
consentEntity.setExternalClientId(clientStorageId.getExternalId());
}
consentEntity.setCreatedDate(currentTime);
consentEntity.setLastUpdatedDate(currentTime);
em.persist(consentEntity);
@ -246,9 +255,16 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
private UserConsentEntity getGrantedConsentEntity(String userId, String clientId) {
TypedQuery<UserConsentEntity> query = em.createNamedQuery("userConsentByUserAndClient", UserConsentEntity.class);
StorageId clientStorageId = new StorageId(clientId);
String queryName = clientStorageId.isLocal() ? "userConsentByUserAndClient" : "userConsentByUserAndExternalClient";
TypedQuery<UserConsentEntity> query = em.createNamedQuery(queryName, UserConsentEntity.class);
query.setParameter("userId", userId);
if (clientStorageId.isLocal()) {
query.setParameter("clientId", clientId);
} else {
query.setParameter("clientStorageProvider", clientStorageId.getProviderId());
query.setParameter("externalClientId", clientStorageId.getExternalId());
}
List<UserConsentEntity> results = query.getResultList();
if (results.size() > 1) {
throw new ModelException("More results found for user [" + userId + "] and client [" + clientId + "]");
@ -257,6 +273,7 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
} else {
return null;
}
}
private UserConsentModel toConsentModel(RealmModel realm, UserConsentEntity entity) {
@ -264,9 +281,16 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
return null;
}
ClientModel client = realm.getClientById(entity.getClientId());
StorageId clientStorageId = null;
if ( entity.getClientId() == null) {
clientStorageId = new StorageId(entity.getClientStorageProvider(), entity.getExternalClientId());
} else {
clientStorageId = new StorageId(entity.getClientId());
}
ClientModel client = realm.getClientById(clientStorageId.getId());
if (client == null) {
throw new ModelException("Client with id " + entity.getClientId() + " is not available");
throw new ModelException("Client with id " + clientStorageId.getId() + " is not available");
}
UserConsentModel model = new UserConsentModel(client);
model.setCreatedDate(entity.getCreatedDate());
@ -472,9 +496,32 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
@Override
public void preRemove(RealmModel realm, ClientModel client) {
em.createNamedQuery("deleteUserConsentProtMappersByClient").setParameter("clientId", client.getId()).executeUpdate();
em.createNamedQuery("deleteUserConsentRolesByClient").setParameter("clientId", client.getId()).executeUpdate();
em.createNamedQuery("deleteUserConsentsByClient").setParameter("clientId", client.getId()).executeUpdate();
StorageId clientStorageId = new StorageId(client.getId());
if (clientStorageId.isLocal()) {
em.createNamedQuery("deleteUserConsentProtMappersByClient")
.setParameter("clientId", client.getId())
.executeUpdate();
em.createNamedQuery("deleteUserConsentRolesByClient")
.setParameter("clientId", client.getId())
.executeUpdate();
em.createNamedQuery("deleteUserConsentsByClient")
.setParameter("clientId", client.getId())
.executeUpdate();
} else {
em.createNamedQuery("deleteUserConsentProtMappersByExternalClient")
.setParameter("clientStorageProvider", clientStorageId.getProviderId())
.setParameter("externalClientId",clientStorageId.getExternalId())
.executeUpdate();
em.createNamedQuery("deleteUserConsentRolesByExternalClient")
.setParameter("clientStorageProvider", clientStorageId.getProviderId())
.setParameter("externalClientId", clientStorageId.getExternalId())
.executeUpdate();
em.createNamedQuery("deleteUserConsentsByExternalClient")
.setParameter("clientStorageProvider", clientStorageId.getProviderId())
.setParameter("externalClientId", clientStorageId.getExternalId())
.executeUpdate();
}
}
@Override
@ -806,8 +853,24 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
@Override
public void preRemove(RealmModel realm, ComponentModel component) {
if (!component.getProviderType().equals(UserStorageProvider.class.getName())) return;
if (component.getProviderType().equals(UserStorageProvider.class.getName())) {
removeImportedUsers(realm, component.getId());
}
if (component.getProviderType().equals(ClientStorageProvider.class.getName())) {
removeConsentByClientStorageProvider(realm, component.getId());
}
}
protected void removeConsentByClientStorageProvider(RealmModel realm, String providerId) {
em.createNamedQuery("deleteUserConsentProtMappersByClientStorageProvider")
.setParameter("clientStorageProvider", providerId)
.executeUpdate();
em.createNamedQuery("deleteUserConsentRolesByClientStorageProvider")
.setParameter("clientStorageProvider", providerId)
.executeUpdate();
em.createNamedQuery("deleteUserConsentsByClientStorageProvider")
.setParameter("clientStorageProvider", providerId)
.executeUpdate();
}

View file

@ -43,11 +43,14 @@ import java.util.Collection;
})
@NamedQueries({
@NamedQuery(name="userConsentByUserAndClient", query="select consent from UserConsentEntity consent where consent.user.id = :userId and consent.clientId = :clientId"),
@NamedQuery(name="userConsentByUserAndExternalClient", query="select consent from UserConsentEntity consent where consent.user.id = :userId and consent.clientStorageProvider = :clientStorageProvider and consent.externalClientId = :externalClientId"),
@NamedQuery(name="userConsentsByUser", query="select consent from UserConsentEntity consent where consent.user.id = :userId"),
@NamedQuery(name="deleteUserConsentsByRealm", query="delete from UserConsentEntity consent where consent.user IN (select user from UserEntity user where user.realmId = :realmId)"),
@NamedQuery(name="deleteUserConsentsByRealmAndLink", query="delete from UserConsentEntity consent where consent.user IN (select u from UserEntity u where u.realmId=:realmId and u.federationLink=:link)"),
@NamedQuery(name="deleteUserConsentsByUser", query="delete from UserConsentEntity consent where consent.user = :user"),
@NamedQuery(name="deleteUserConsentsByClient", query="delete from UserConsentEntity consent where consent.clientId = :clientId"),
@NamedQuery(name="deleteUserConsentsByExternalClient", query="delete from UserConsentEntity consent where consent.clientStorageProvider = :clientStorageProvider and consent.externalClientId = :externalClientId"),
@NamedQuery(name="deleteUserConsentsByClientStorageProvider", query="delete from UserConsentEntity consent where consent.clientStorageProvider = :clientStorageProvider"),
})
public class UserConsentEntity {
@ -63,6 +66,12 @@ public class UserConsentEntity {
@Column(name="CLIENT_ID")
protected String clientId;
@Column(name="CLIENT_STORAGE_PROVIDER")
protected String clientStorageProvider;
@Column(name="EXTERNAL_CLIENT_ID")
protected String externalClientId;
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "userConsent")
Collection<UserConsentRoleEntity> grantedRoles = new ArrayList<UserConsentRoleEntity>();
@ -91,14 +100,6 @@ public class UserConsentEntity {
this.user = user;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public Collection<UserConsentRoleEntity> getGrantedRoles() {
return grantedRoles;
}
@ -131,6 +132,30 @@ public class UserConsentEntity {
this.lastUpdatedDate = lastUpdatedDate;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getClientStorageProvider() {
return clientStorageProvider;
}
public void setClientStorageProvider(String clientStorageProvider) {
this.clientStorageProvider = clientStorageProvider;
}
public String getExternalClientId() {
return externalClientId;
}
public void setExternalClientId(String externalClientId) {
this.externalClientId = externalClientId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;

View file

@ -38,7 +38,9 @@ import java.io.Serializable;
@NamedQuery(name="deleteUserConsentProtMappersByUser", query="delete from UserConsentProtocolMapperEntity csm where csm.userConsent IN (select consent from UserConsentEntity consent where consent.user = :user)"),
@NamedQuery(name="deleteUserConsentProtMappersByRealmAndLink", query="delete from UserConsentProtocolMapperEntity csm where csm.userConsent IN (select consent from UserConsentEntity consent where consent.user IN (select u from UserEntity u where u.realmId=:realmId and u.federationLink=:link))"),
@NamedQuery(name="deleteUserConsentProtMappersByProtocolMapper", query="delete from UserConsentProtocolMapperEntity csm where csm.protocolMapperId = :protocolMapperId)"),
@NamedQuery(name="deleteUserConsentProtMappersByClient", query="delete from UserConsentProtocolMapperEntity csm where csm.userConsent IN (select consent from UserConsentEntity consent where consent.clientId = :clientId))"),
@NamedQuery(name="deleteUserConsentProtMappersByClient", query="delete from UserConsentProtocolMapperEntity csm where csm.userConsent IN (select consent from UserConsentEntity consent where consent.clientId = :clientId)"),
@NamedQuery(name="deleteUserConsentProtMappersByExternalClient", query="delete from UserConsentProtocolMapperEntity csm where csm.userConsent IN (select consent from UserConsentEntity consent where consent.clientStorageProvider = :clientStorageProvider and consent.externalClientId = :externalClientId)"),
@NamedQuery(name="deleteUserConsentProtMappersByClientStorageProvider", query="delete from UserConsentProtocolMapperEntity csm where csm.userConsent IN (select consent from UserConsentEntity consent where consent.clientStorageProvider = :clientStorageProvider)"),
})
@Entity
@Table(name="USER_CONSENT_PROT_MAPPER")

View file

@ -38,6 +38,8 @@ import java.io.Serializable;
@NamedQuery(name="deleteUserConsentRolesByUser", query="delete from UserConsentRoleEntity grantedRole where grantedRole.userConsent IN (select consent from UserConsentEntity consent where consent.user = :user)"),
@NamedQuery(name="deleteUserConsentRolesByRole", query="delete from UserConsentRoleEntity grantedRole where grantedRole.roleId = :roleId)"),
@NamedQuery(name="deleteUserConsentRolesByClient", query="delete from UserConsentRoleEntity grantedRole where grantedRole.userConsent IN (select consent from UserConsentEntity consent where consent.clientId = :clientId)"),
@NamedQuery(name="deleteUserConsentRolesByExternalClient", query="delete from UserConsentRoleEntity grantedRole where grantedRole.userConsent IN (select consent from UserConsentEntity consent where consent.clientStorageProvider = :clientStorageProvider and consent.externalClientId = :externalClientId)"),
@NamedQuery(name="deleteUserConsentRolesByClientStorageProvider", query="delete from UserConsentRoleEntity grantedRole where grantedRole.userConsent IN (select consent from UserConsentEntity consent where consent.clientStorageProvider = :clientStorageProvider)"),
})
@Entity
@Table(name="USER_CONSENT_ROLE")

View file

@ -32,9 +32,11 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserConsentModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.jpa.entities.UserConsentEntity;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.UserStorageProvider;
import org.keycloak.storage.client.ClientStorageProvider;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import org.keycloak.storage.jpa.entity.BrokerLinkEntity;
import org.keycloak.storage.jpa.entity.FederatedUser;
@ -257,7 +259,13 @@ public class JpaUserFederatedStorageProvider implements
consentEntity = new FederatedUserConsentEntity();
consentEntity.setId(KeycloakModelUtils.generateId());
consentEntity.setUserId(userId);
StorageId clientStorageId = new StorageId(clientId);
if (clientStorageId.isLocal()) {
consentEntity.setClientId(clientId);
} else {
consentEntity.setClientStorageProvider(clientStorageId.getProviderId());
consentEntity.setExternalClientId(clientStorageId.getExternalId());
}
consentEntity.setRealmId(realm.getId());
consentEntity.setStorageProviderId(new StorageId(userId).getProviderId());
long currentTime = Time.currentTimeMillis();
@ -315,9 +323,16 @@ public class JpaUserFederatedStorageProvider implements
}
private FederatedUserConsentEntity getGrantedConsentEntity(String userId, String clientId) {
TypedQuery<FederatedUserConsentEntity> query = em.createNamedQuery("userFederatedConsentByUserAndClient", FederatedUserConsentEntity.class);
StorageId clientStorageId = new StorageId(clientId);
String queryName = clientStorageId.isLocal() ? "userFederatedConsentByUserAndClient" : "userFederatedConsentByUserAndExternalClient";
TypedQuery<FederatedUserConsentEntity> query = em.createNamedQuery(queryName, FederatedUserConsentEntity.class);
query.setParameter("userId", userId);
if (clientStorageId.isLocal()) {
query.setParameter("clientId", clientId);
} else {
query.setParameter("clientStorageProvider", clientStorageId.getProviderId());
query.setParameter("externalClientId", clientStorageId.getExternalId());
}
List<FederatedUserConsentEntity> results = query.getResultList();
if (results.size() > 1) {
throw new ModelException("More results found for user [" + userId + "] and client [" + clientId + "]");
@ -334,10 +349,14 @@ public class JpaUserFederatedStorageProvider implements
return null;
}
ClientModel client = realm.getClientById(entity.getClientId());
if (client == null) {
throw new ModelException("Client with id " + entity.getClientId() + " is not available");
StorageId clientStorageId = null;
if ( entity.getClientId() == null) {
clientStorageId = new StorageId(entity.getClientStorageProvider(), entity.getExternalClientId());
} else {
clientStorageId = new StorageId(entity.getClientId());
}
ClientModel client = realm.getClientById(clientStorageId.getId());
UserConsentModel model = new UserConsentModel(client);
model.setCreatedDate(entity.getCreatedDate());
model.setLastUpdatedDate(entity.getLastUpdatedDate());
@ -822,9 +841,26 @@ public class JpaUserFederatedStorageProvider implements
@Override
public void preRemove(RealmModel realm, ClientModel client) {
StorageId clientStorageId = new StorageId(client.getId());
if (clientStorageId.isLocal()) {
em.createNamedQuery("deleteFederatedUserConsentProtMappersByClient").setParameter("clientId", client.getId()).executeUpdate();
em.createNamedQuery("deleteFederatedUserConsentRolesByClient").setParameter("clientId", client.getId()).executeUpdate();
em.createNamedQuery("deleteFederatedUserConsentsByClient").setParameter("clientId", client.getId()).executeUpdate();
} else {
em.createNamedQuery("deleteFederatedUserConsentProtMappersByExternalClient")
.setParameter("clientStorageProvider", clientStorageId.getProviderId())
.setParameter("externalClientId",clientStorageId.getExternalId())
.executeUpdate();
em.createNamedQuery("deleteFederatedUserConsentRolesByExternalClient")
.setParameter("clientStorageProvider", clientStorageId.getProviderId())
.setParameter("externalClientId",clientStorageId.getExternalId())
.executeUpdate();
em.createNamedQuery("deleteFederatedUserConsentsByExternalClient")
.setParameter("clientStorageProvider", clientStorageId.getProviderId())
.setParameter("externalClientId",clientStorageId.getExternalId())
.executeUpdate();
}
}
@Override
@ -885,7 +921,7 @@ public class JpaUserFederatedStorageProvider implements
@Override
public void preRemove(RealmModel realm, ComponentModel model) {
if (!model.getProviderType().equals(UserStorageProvider.class.getName())) return;
if (model.getProviderType().equals(UserStorageProvider.class.getName())) {
em.createNamedQuery("deleteBrokerLinkByStorageProvider")
.setParameter("storageProviderId", model.getId())
@ -920,6 +956,18 @@ public class JpaUserFederatedStorageProvider implements
em.createNamedQuery("deleteFederatedUsersByStorageProvider")
.setParameter("storageProviderId", model.getId())
.executeUpdate();
} else if (model.getProviderType().equals(ClientStorageProvider.class.getName())) {
em.createNamedQuery("deleteFederatedUserConsentProtMappersByClientStorageProvider")
.setParameter("clientStorageProvider", model.getId())
.executeUpdate();
em.createNamedQuery("deleteFederatedUserConsentRolesByClientStorageProvider")
.setParameter("clientStorageProvider", model.getId())
.executeUpdate();
em.createNamedQuery("deleteFederatedUserConsentsByClientStorageProvider")
.setParameter("clientStorageProvider", model.getId())
.executeUpdate();
}
}
}

View file

@ -40,11 +40,14 @@ import java.util.Collection;
})
@NamedQueries({
@NamedQuery(name="userFederatedConsentByUserAndClient", query="select consent from FederatedUserConsentEntity consent where consent.userId = :userId and consent.clientId = :clientId"),
@NamedQuery(name="userFederatedConsentByUserAndExternalClient", query="select consent from FederatedUserConsentEntity consent where consent.userId = :userId and consent.clientStorageProvider = :clientStorageProvider and consent.externalClientId = :externalClientId"),
@NamedQuery(name="userFederatedConsentsByUser", query="select consent from FederatedUserConsentEntity consent where consent.userId = :userId"),
@NamedQuery(name="deleteFederatedUserConsentsByRealm", query="delete from FederatedUserConsentEntity consent where consent.realmId=:realmId"),
@NamedQuery(name="deleteFederatedUserConsentsByStorageProvider", query="delete from FederatedUserConsentEntity e where e.storageProviderId=:storageProviderId"),
@NamedQuery(name="deleteFederatedUserConsentsByUser", query="delete from FederatedUserConsentEntity consent where consent.userId = :userId and consent.realmId = :realmId"),
@NamedQuery(name="deleteFederatedUserConsentsByClient", query="delete from FederatedUserConsentEntity consent where consent.clientId = :clientId"),
@NamedQuery(name="deleteFederatedUserConsentsByExternalClient", query="delete from FederatedUserConsentEntity consent where consent.clientStorageProvider = :clientStorageProvider and consent.externalClientId = :externalClientId"),
@NamedQuery(name="deleteFederatedUserConsentsByClientStorageProvider", query="delete from FederatedUserConsentEntity consent where consent.clientStorageProvider = :clientStorageProvider"),
})
public class FederatedUserConsentEntity {
@ -65,6 +68,12 @@ public class FederatedUserConsentEntity {
@Column(name="CLIENT_ID")
protected String clientId;
@Column(name="CLIENT_STORAGE_PROVIDER")
protected String clientStorageProvider;
@Column(name="EXTERNAL_CLIENT_ID")
protected String externalClientId;
@Column(name = "CREATED_DATE")
private Long createdDate;
@ -119,6 +128,22 @@ public class FederatedUserConsentEntity {
this.clientId = clientId;
}
public String getClientStorageProvider() {
return clientStorageProvider;
}
public void setClientStorageProvider(String clientStorageProvider) {
this.clientStorageProvider = clientStorageProvider;
}
public String getExternalClientId() {
return externalClientId;
}
public void setExternalClientId(String externalClientId) {
this.externalClientId = externalClientId;
}
public Collection<FederatedUserConsentRoleEntity> getGrantedRoles() {
return grantedRoles;
}

View file

@ -39,6 +39,8 @@ import java.io.Serializable;
@NamedQuery(name="deleteFederatedUserConsentProtMappersByStorageProvider", query="delete from FederatedUserConsentProtocolMapperEntity csm where csm.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.storageProviderId = :storageProviderId)"),
@NamedQuery(name="deleteFederatedUserConsentProtMappersByProtocolMapper", query="delete from FederatedUserConsentProtocolMapperEntity csm where csm.protocolMapperId = :protocolMapperId"),
@NamedQuery(name="deleteFederatedUserConsentProtMappersByClient", query="delete from FederatedUserConsentProtocolMapperEntity csm where csm.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.clientId = :clientId)"),
@NamedQuery(name="deleteFederatedUserConsentProtMappersByExternalClient", query="delete from FederatedUserConsentProtocolMapperEntity csm where csm.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.clientStorageProvider = :clientStorageProvider and consent.externalClientId = :externalClientId)"),
@NamedQuery(name="deleteFederatedUserConsentProtMappersByClientStorageProvider", query="delete from FederatedUserConsentProtocolMapperEntity csm where csm.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.clientStorageProvider = :clientStorageProvider)"),
})
@Entity
@Table(name="FED_USER_CONSENT_PROT_MAPPER")

View file

@ -38,6 +38,8 @@ import java.io.Serializable;
@NamedQuery(name="deleteFederatedUserConsentRolesByStorageProvider", query="delete from FederatedUserConsentRoleEntity grantedRole where grantedRole.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.storageProviderId = :storageProviderId)"),
@NamedQuery(name="deleteFederatedUserConsentRolesByRole", query="delete from FederatedUserConsentRoleEntity grantedRole where grantedRole.roleId = :roleId"),
@NamedQuery(name="deleteFederatedUserConsentRolesByClient", query="delete from FederatedUserConsentRoleEntity grantedRole where grantedRole.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.clientId = :clientId)"),
@NamedQuery(name="deleteFederatedUserConsentRolesByExternalClient", query="delete from FederatedUserConsentRoleEntity grantedRole where grantedRole.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.clientStorageProvider = :clientStorageProvider and consent.externalClientId = :externalClientId)"),
@NamedQuery(name="deleteFederatedUserConsentRolesByClientStorageProvider", query="delete from FederatedUserConsentRoleEntity grantedRole where grantedRole.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.clientStorageProvider = :clientStorageProvider)"),
})
@Entity
@Table(name="FED_USER_CONSENT_ROLE")

View file

@ -41,8 +41,32 @@
<!-- Modify USER_CONSENT -->
<dropUniqueConstraint constraintName="UK_JKUWUVD56ONTGSUHOGM8UEWRT" tableName="USER_CONSENT"/>
<modifyDataType tableName="USER_CONSENT" columnName="CLIENT_ID" newDataType="VARCHAR(255)"/>
<addUniqueConstraint columnNames="CLIENT_ID, USER_ID" constraintName="UK_JKUWUVD56ONTGSUHOGM8UEWRT" tableName="USER_CONSENT"/>
<dropNotNullConstraint tableName="USER_CONSENT" columnName="CLIENT_ID" columnDataType="VARCHAR(36)"/>
<addColumn tableName="USER_CONSENT">
<column name="CLIENT_STORAGE_PROVIDER" type="VARCHAR(36)">
<constraints nullable="true"/>
</column>
<column name="EXTERNAL_CLIENT_ID" type="VARCHAR(255)">
<constraints nullable="true"/>
</column>
</addColumn>
<addUniqueConstraint columnNames="CLIENT_ID, CLIENT_STORAGE_PROVIDER, EXTERNAL_CLIENT_ID, USER_ID" constraintName="UK_JKUWUVD56ONTGSUHOGM8UEWRT" tableName="USER_CONSENT"/>
<!-- FED_USER_CONSENT -->
<addColumn tableName="FED_USER_CONSENT">
<column name="CLIENT_STORAGE_PROVIDER" type="VARCHAR(36)">
<constraints nullable="true"/>
</column>
<column name="EXTERNAL_CLIENT_ID" type="VARCHAR(255)">
<constraints nullable="true"/>
</column>
</addColumn>
<dropNotNullConstraint tableName="FED_USER_CONSENT" columnName="CLIENT_ID" columnDataType="VARCHAR(36)"/>
<createIndex tableName="FED_USER_CONSENT" indexName="IDX_FU_CNSNT_EXT">
<column name="USER_ID" type="VARCHAR(255)" />
<column name="CLIENT_STORAGE_PROVIDER" type="VARCHAR(36)" />
<column name="EXTERNAL_CLIENT_ID" type="VARCHAR(255)" />
</createIndex>
<!-- Modify CLIENT_NODE_REGISTRATIONS -->
<dropForeignKeyConstraint constraintName="FK4129723BA992F594" baseTableName="CLIENT"/>
@ -53,12 +77,5 @@
<modifyDataType tableName="OFFLINE_CLIENT_SESSION" columnName="CLIENT_ID" newDataType="VARCHAR(255)"/>
<addPrimaryKey columnNames="USER_SESSION_ID,CLIENT_ID, OFFLINE_FLAG" constraintName="CONSTRAINT_OFFL_CL_SES_PK3" tableName="OFFLINE_CLIENT_SESSION"/>
<!-- FED_USER_CONSENT -->
<dropIndex tableName="FED_USER_CONSENT" indexName="IDX_FU_CONSENT"/>
<modifyDataType tableName="FED_USER_CONSENT" columnName="CLIENT_ID" newDataType="VARCHAR(255)"/>
<createIndex tableName="FED_USER_CONSENT" indexName="IDX_FU_CONSENT">
<column name="USER_ID" type="VARCHAR(255)" />
<column name="CLIENT_ID" type="VARCHAR(36)" />
</createIndex>
</changeSet>
</databaseChangeLog>

View file

@ -40,6 +40,7 @@ import org.keycloak.models.cache.UserCache;
import org.keycloak.models.utils.ComponentUtil;
import org.keycloak.models.utils.ReadOnlyUserModelDelegate;
import org.keycloak.services.managers.UserStorageSyncManager;
import org.keycloak.storage.client.ClientStorageProvider;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import org.keycloak.storage.user.ImportedUserValidation;
import org.keycloak.storage.user.UserBulkUpdateProvider;
@ -696,6 +697,11 @@ public class UserStorageManager implements UserProvider, OnUserCache, OnCreateCo
@Override
public void preRemove(RealmModel realm, ComponentModel component) {
if (component.getProviderType().equals(ClientStorageProvider.class.getName())) {
localStorage().preRemove(realm, component);
if (getFederatedStorage() != null) getFederatedStorage().preRemove(realm, component);
return;
}
if (!component.getProviderType().equals(UserStorageProvider.class.getName())) return;
localStorage().preRemove(realm, component);
if (getFederatedStorage() != null) getFederatedStorage().preRemove(realm, component);

View file

@ -42,12 +42,14 @@ public class HardcodedClientStorageProvider implements ClientStorageProvider, Cl
protected ClientStorageProviderModel component;
protected String clientId;
protected String redirectUri;
protected boolean consent;
public HardcodedClientStorageProvider(KeycloakSession session, ClientStorageProviderModel component) {
this.session = session;
this.component = component;
this.clientId = component.getConfig().getFirst(HardcodedClientStorageProviderFactory.CLIENT_ID);
this.redirectUri = component.getConfig().getFirst(HardcodedClientStorageProviderFactory.REDIRECT_URI);
this.consent = "true".equals(component.getConfig().getFirst(HardcodedClientStorageProviderFactory.CONSENT));
}
@Override
@ -189,7 +191,7 @@ public class HardcodedClientStorageProvider implements ClientStorageProvider, Cl
@Override
public boolean isConsentRequired() {
return false;
return consent;
}
@Override

View file

@ -48,6 +48,7 @@ public class HardcodedClientStorageProviderFactory implements ClientStorageProvi
public static final String CLIENT_ID = "client_id";
public static final String REDIRECT_URI = "redirect_uri";
public static final String CONSENT = "consent";
static {
CONFIG_PROPERTIES = ProviderConfigurationBuilder.create()
@ -58,11 +59,17 @@ public class HardcodedClientStorageProviderFactory implements ClientStorageProvi
.defaultValue("hardcoded-client")
.add()
.property().name(REDIRECT_URI)
.type(ProviderConfigProperty.BOOLEAN_TYPE)
.type(ProviderConfigProperty.STRING_TYPE)
.label("Redirect Uri")
.helpText("Valid redirect uri. Only one allowed")
.defaultValue("http://localhost:8180/*")
.add()
.property().name(CONSENT)
.type(ProviderConfigProperty.BOOLEAN_TYPE)
.label("Consent Required")
.helpText("Is consent required")
.defaultValue("false")
.add()
.build();
}

View file

@ -20,6 +20,7 @@ package org.keycloak.testsuite.model;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ModelException;
import org.keycloak.models.ProtocolMapperModel;
@ -30,6 +31,8 @@ import org.keycloak.models.UserConsentModel;
import org.keycloak.models.UserModel;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.mappers.UserPropertyMapper;
import org.keycloak.storage.client.ClientStorageProviderModel;
import org.keycloak.testsuite.federation.HardcodedClientStorageProviderFactory;
import java.util.List;
@ -38,6 +41,8 @@ import java.util.List;
*/
public class UserConsentModelTest extends AbstractModelTest {
private ComponentModel clientStorageComponent;
@Before
public void setupEnv() {
RealmModel realm = realmManager.createRealm("original");
@ -87,6 +92,22 @@ public class UserConsentModelTest extends AbstractModelTest {
maryFooGrant.addGrantedProtocolMapper(fooMapper);
realmManager.getSession().users().addConsent(realm, mary.getId(), maryFooGrant);
ClientStorageProviderModel clientStorage = new ClientStorageProviderModel();
clientStorage.setProviderId(HardcodedClientStorageProviderFactory.PROVIDER_ID);
clientStorage.getConfig().putSingle(HardcodedClientStorageProviderFactory.CLIENT_ID, "hardcoded-client");
clientStorage.getConfig().putSingle(HardcodedClientStorageProviderFactory.REDIRECT_URI, "http://localhost:8081/*");
clientStorage.getConfig().putSingle(HardcodedClientStorageProviderFactory.CONSENT, "true");
clientStorage.setParentId(realm.getId());
clientStorageComponent = realm.addComponentModel(clientStorage);
ClientModel hardcodedClient = session.realms().getClientByClientId("hardcoded-client", realm);
Assert.assertNotNull(hardcodedClient);
UserConsentModel maryHardcodedGrant = new UserConsentModel(hardcodedClient);
realmManager.getSession().users().addConsent(realm, mary.getId(), maryHardcodedGrant);
commit();
}
@ -125,7 +146,15 @@ public class UserConsentModelTest extends AbstractModelTest {
Assert.assertNotNull("Created Date should be set", maryConsent.getCreatedDate());
Assert.assertNotNull("Last Updated Date should be set", maryConsent.getLastUpdatedDate());
ClientModel hardcodedClient = session.realms().getClientByClientId("hardcoded-client", realm);
UserConsentModel maryHardcodedConsent = realmManager.getSession().users().getConsentByClient(realm, mary.getId(), hardcodedClient.getId());
Assert.assertEquals(maryHardcodedConsent.getGrantedRoles().size(), 0);
Assert.assertEquals(maryHardcodedConsent.getGrantedProtocolMappers().size(), 0);
Assert.assertNotNull("Created Date should be set", maryHardcodedConsent.getCreatedDate());
Assert.assertNotNull("Last Updated Date should be set", maryHardcodedConsent.getLastUpdatedDate());
Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, mary.getId(), barClient.getId()));
Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, john.getId(), hardcodedClient.getId()));
}
@Test
@ -139,14 +168,26 @@ public class UserConsentModelTest extends AbstractModelTest {
List<UserConsentModel> johnConsents = realmManager.getSession().users().getConsents(realm, john.getId());
Assert.assertEquals(2, johnConsents.size());
ClientModel hardcodedClient = session.realms().getClientByClientId("hardcoded-client", realm);
List<UserConsentModel> maryConsents = realmManager.getSession().users().getConsents(realm, mary.getId());
Assert.assertEquals(1, maryConsents.size());
Assert.assertEquals(2, maryConsents.size());
UserConsentModel maryConsent = maryConsents.get(0);
UserConsentModel maryHardcodedConsent = maryConsents.get(1);
if (maryConsents.get(0).getClient().getId().equals(hardcodedClient.getId())) {
maryConsent = maryConsents.get(1);
maryHardcodedConsent = maryConsents.get(0);
}
Assert.assertEquals(maryConsent.getClient().getId(), fooClient.getId());
Assert.assertEquals(maryConsent.getGrantedRoles().size(), 1);
Assert.assertEquals(maryConsent.getGrantedProtocolMappers().size(), 1);
Assert.assertTrue(isRoleGranted(realm, "realm-role", maryConsent));
Assert.assertTrue(isMapperGranted(fooClient, "foo", maryConsent));
Assert.assertEquals(maryHardcodedConsent.getClient().getId(), hardcodedClient.getId());
Assert.assertEquals(maryHardcodedConsent.getGrantedRoles().size(), 0);
Assert.assertEquals(maryHardcodedConsent.getGrantedProtocolMappers().size(), 0);
}
@Test
@ -190,14 +231,19 @@ public class UserConsentModelTest extends AbstractModelTest {
RealmModel realm = realmManager.getRealm("original");
ClientModel fooClient = realm.getClientByClientId("foo-client");
UserModel john = session.users().getUserByUsername("john", realm);
UserModel mary = session.users().getUserByUsername("mary", realm);
realmManager.getSession().users().revokeConsentForClient(realm, john.getId(), fooClient.getId());
ClientModel hardcodedClient = session.realms().getClientByClientId("hardcoded-client", realm);
realmManager.getSession().users().revokeConsentForClient(realm, mary.getId(), hardcodedClient.getId());
commit();
realm = realmManager.getRealm("original");
john = session.users().getUserByUsername("john", realm);
Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, john.getId(), fooClient.getId()));
mary = session.users().getUserByUsername("mary", realm);
Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, mary.getId(), hardcodedClient.getId()));
}
@Test
@ -206,6 +252,8 @@ public class UserConsentModelTest extends AbstractModelTest {
RealmModel realm = realmManager.getRealm("original");
UserModel john = session.users().getUserByUsername("john", realm);
session.users().removeUser(realm, john);
UserModel mary = session.users().getUserByUsername("mary", realm);
session.users().removeUser(realm, mary);
}
@Test
@ -270,6 +318,24 @@ public class UserConsentModelTest extends AbstractModelTest {
Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, john.getId(), barClient.getId()));
}
@Test
public void deleteClientStorageTest() {
RealmModel realm = realmManager.getRealm("original");
realm.removeComponent(clientStorageComponent);
commit();
realm = realmManager.getRealm("original");
ClientModel hardcodedClient = session.realms().getClientByClientId("hardcoded-client", realm);
Assert.assertNull(hardcodedClient);
UserModel mary = session.users().getUserByUsername("mary", realm);
List<UserConsentModel> maryConsents = realmManager.getSession().users().getConsents(realm, mary.getId());
Assert.assertEquals(1, maryConsents.size());
}
private boolean isRoleGranted(RoleContainerModel roleContainer, String roleName, UserConsentModel consentModel) {
RoleModel role = roleContainer.getRole(roleName);
return consentModel.isRoleGranted(role);

View file

@ -20,6 +20,7 @@ package org.keycloak.testsuite.model;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ModelException;
import org.keycloak.models.ProtocolMapperModel;
@ -31,6 +32,8 @@ import org.keycloak.models.UserModel;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.mappers.UserPropertyMapper;
import org.keycloak.storage.UserStorageProviderModel;
import org.keycloak.storage.client.ClientStorageProviderModel;
import org.keycloak.testsuite.federation.HardcodedClientStorageProviderFactory;
import org.keycloak.testsuite.federation.storage.UserMapStorageFactory;
import org.keycloak.testsuite.federation.storage.UserPropertyFileStorageFactory;
@ -41,6 +44,8 @@ import java.util.List;
*/
public class UserConsentWithUserStorageModelTest extends AbstractModelTest {
private ComponentModel clientStorageComponent;
@Before
public void setupEnv() {
RealmModel realm = realmManager.createRealm("original");
@ -97,6 +102,22 @@ public class UserConsentWithUserStorageModelTest extends AbstractModelTest {
maryFooGrant.addGrantedProtocolMapper(fooMapper);
realmManager.getSession().users().addConsent(realm, mary.getId(), maryFooGrant);
ClientStorageProviderModel clientStorage = new ClientStorageProviderModel();
clientStorage.setProviderId(HardcodedClientStorageProviderFactory.PROVIDER_ID);
clientStorage.getConfig().putSingle(HardcodedClientStorageProviderFactory.CLIENT_ID, "hardcoded-client");
clientStorage.getConfig().putSingle(HardcodedClientStorageProviderFactory.REDIRECT_URI, "http://localhost:8081/*");
clientStorage.getConfig().putSingle(HardcodedClientStorageProviderFactory.CONSENT, "true");
clientStorage.setParentId(realm.getId());
clientStorageComponent = realm.addComponentModel(clientStorage);
ClientModel hardcodedClient = session.realms().getClientByClientId("hardcoded-client", realm);
Assert.assertNotNull(hardcodedClient);
UserConsentModel maryHardcodedGrant = new UserConsentModel(hardcodedClient);
realmManager.getSession().users().addConsent(realm, mary.getId(), maryHardcodedGrant);
commit();
}
@ -135,7 +156,15 @@ public class UserConsentWithUserStorageModelTest extends AbstractModelTest {
Assert.assertNotNull("Created Date should be set", maryConsent.getCreatedDate());
Assert.assertNotNull("Last Updated Date should be set", maryConsent.getLastUpdatedDate());
ClientModel hardcodedClient = session.realms().getClientByClientId("hardcoded-client", realm);
UserConsentModel maryHardcodedConsent = realmManager.getSession().users().getConsentByClient(realm, mary.getId(), hardcodedClient.getId());
Assert.assertEquals(maryHardcodedConsent.getGrantedRoles().size(), 0);
Assert.assertEquals(maryHardcodedConsent.getGrantedProtocolMappers().size(), 0);
Assert.assertNotNull("Created Date should be set", maryHardcodedConsent.getCreatedDate());
Assert.assertNotNull("Last Updated Date should be set", maryHardcodedConsent.getLastUpdatedDate());
Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, mary.getId(), barClient.getId()));
Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, john.getId(), hardcodedClient.getId()));
}
@Test
@ -149,14 +178,26 @@ public class UserConsentWithUserStorageModelTest extends AbstractModelTest {
List<UserConsentModel> johnConsents = realmManager.getSession().users().getConsents(realm, john.getId());
Assert.assertEquals(2, johnConsents.size());
ClientModel hardcodedClient = session.realms().getClientByClientId("hardcoded-client", realm);
List<UserConsentModel> maryConsents = realmManager.getSession().users().getConsents(realm, mary.getId());
Assert.assertEquals(1, maryConsents.size());
Assert.assertEquals(2, maryConsents.size());
UserConsentModel maryConsent = maryConsents.get(0);
UserConsentModel maryHardcodedConsent = maryConsents.get(1);
if (maryConsents.get(0).getClient().getId().equals(hardcodedClient.getId())) {
maryConsent = maryConsents.get(1);
maryHardcodedConsent = maryConsents.get(0);
}
Assert.assertEquals(maryConsent.getClient().getId(), fooClient.getId());
Assert.assertEquals(maryConsent.getGrantedRoles().size(), 1);
Assert.assertEquals(maryConsent.getGrantedProtocolMappers().size(), 1);
Assert.assertTrue(isRoleGranted(realm, "realm-role", maryConsent));
Assert.assertTrue(isMapperGranted(fooClient, "foo", maryConsent));
Assert.assertEquals(maryHardcodedConsent.getClient().getId(), hardcodedClient.getId());
Assert.assertEquals(maryHardcodedConsent.getGrantedRoles().size(), 0);
Assert.assertEquals(maryHardcodedConsent.getGrantedProtocolMappers().size(), 0);
}
@Test
@ -200,14 +241,19 @@ public class UserConsentWithUserStorageModelTest extends AbstractModelTest {
RealmModel realm = realmManager.getRealm("original");
ClientModel fooClient = realm.getClientByClientId("foo-client");
UserModel john = session.users().getUserByUsername("john", realm);
UserModel mary = session.users().getUserByUsername("mary", realm);
realmManager.getSession().users().revokeConsentForClient(realm, john.getId(), fooClient.getId());
ClientModel hardcodedClient = session.realms().getClientByClientId("hardcoded-client", realm);
realmManager.getSession().users().revokeConsentForClient(realm, mary.getId(), hardcodedClient.getId());
commit();
realm = realmManager.getRealm("original");
john = session.users().getUserByUsername("john", realm);
Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, john.getId(), fooClient.getId()));
mary = session.users().getUserByUsername("mary", realm);
Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, mary.getId(), hardcodedClient.getId()));
}
@Test
@ -216,6 +262,8 @@ public class UserConsentWithUserStorageModelTest extends AbstractModelTest {
RealmModel realm = realmManager.getRealm("original");
UserModel john = session.users().getUserByUsername("john", realm);
session.users().removeUser(realm, john);
UserModel mary = session.users().getUserByUsername("mary", realm);
session.users().removeUser(realm, mary);
}
@Test
@ -280,6 +328,24 @@ public class UserConsentWithUserStorageModelTest extends AbstractModelTest {
Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, john.getId(), barClient.getId()));
}
@Test
public void deleteClientStorageTest() {
RealmModel realm = realmManager.getRealm("original");
realm.removeComponent(clientStorageComponent);
commit();
realm = realmManager.getRealm("original");
ClientModel hardcodedClient = session.realms().getClientByClientId("hardcoded-client", realm);
Assert.assertNull(hardcodedClient);
UserModel mary = session.users().getUserByUsername("mary", realm);
List<UserConsentModel> maryConsents = realmManager.getSession().users().getConsents(realm, mary.getId());
Assert.assertEquals(1, maryConsents.size());
}
private boolean isRoleGranted(RoleContainerModel roleContainer, String roleName, UserConsentModel consentModel) {
RoleModel role = roleContainer.getRole(roleName);
return consentModel.isRoleGranted(role);