keycloak-uncached

KEYCLOAK-4256

1/18/2017 9:28:08 PM

Details

diff --git a/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserConsentEntity.java b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserConsentEntity.java
index 8066310..225e80b 100755
--- a/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserConsentEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserConsentEntity.java
@@ -65,6 +65,14 @@ public class FederatedUserConsentEntity {
     @Column(name="CLIENT_ID")
     protected String clientId;
 
+    @Column(name = "CREATED_DATE")
+    private Long createdDate;
+
+    @Column(name = "LAST_UPDATED_DATE")
+    private Long lastUpdatedDate;
+
+
+
     @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "userConsent")
     Collection<FederatedUserConsentRoleEntity> grantedRoles = new ArrayList<FederatedUserConsentRoleEntity>();
 
@@ -127,6 +135,22 @@ public class FederatedUserConsentEntity {
         this.grantedProtocolMappers = grantedProtocolMappers;
     }
 
+    public Long getCreatedDate() {
+        return createdDate;
+    }
+
+    public void setCreatedDate(Long createdDate) {
+        this.createdDate = createdDate;
+    }
+
+    public Long getLastUpdatedDate() {
+        return lastUpdatedDate;
+    }
+
+    public void setLastUpdatedDate(Long lastUpdatedDate) {
+        this.lastUpdatedDate = lastUpdatedDate;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
diff --git a/model/jpa/src/main/java/org/keycloak/storage/jpa/JpaUserFederatedStorageProvider.java b/model/jpa/src/main/java/org/keycloak/storage/jpa/JpaUserFederatedStorageProvider.java
index 1222872..cded4e9 100644
--- a/model/jpa/src/main/java/org/keycloak/storage/jpa/JpaUserFederatedStorageProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/storage/jpa/JpaUserFederatedStorageProvider.java
@@ -17,6 +17,7 @@
 package org.keycloak.storage.jpa;
 
 import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.common.util.Time;
 import org.keycloak.component.ComponentModel;
 import org.keycloak.credential.CredentialModel;
 import org.keycloak.credential.UserCredentialStore;
@@ -259,6 +260,9 @@ public class JpaUserFederatedStorageProvider implements
         consentEntity.setClientId(clientId);
         consentEntity.setRealmId(realm.getId());
         consentEntity.setStorageProviderId(new StorageId(userId).getProviderId());
+        long currentTime = Time.currentTimeMillis();
+        consentEntity.setCreatedDate(currentTime);
+        consentEntity.setLastUpdatedDate(currentTime);
         em.persist(consentEntity);
         em.flush();
 
@@ -335,6 +339,8 @@ public class JpaUserFederatedStorageProvider implements
             throw new ModelException("Client with id " + entity.getClientId() + " is not available");
         }
         UserConsentModel model = new UserConsentModel(client);
+        model.setCreatedDate(entity.getCreatedDate());
+        model.setLastUpdatedDate(entity.getLastUpdatedDate());
 
         Collection<FederatedUserConsentRoleEntity> grantedRoleEntities = entity.getGrantedRoles();
         if (grantedRoleEntities != null) {
@@ -404,6 +410,8 @@ public class JpaUserFederatedStorageProvider implements
             em.remove(toRemove);
         }
 
+        consentEntity.setLastUpdatedDate(Time.currentTimeMillis());
+
         em.flush();
     }
 
diff --git a/model/jpa/src/main/resources/META-INF/jpa-changelog-2.5.1.xml b/model/jpa/src/main/resources/META-INF/jpa-changelog-2.5.1.xml
new file mode 100755
index 0000000..3184134
--- /dev/null
+++ b/model/jpa/src/main/resources/META-INF/jpa-changelog-2.5.1.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+  ~ Copyright 2016 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.
+  -->
+
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
+
+     <changeSet author="bburke@redhat.com" id="2.5.1">
+         <addColumn tableName="FED_USER_CONSENT">
+             <column name="CREATED_DATE" type="BIGINT"/>
+             <column name="LAST_UPDATED_DATE" type="BIGINT"/>
+         </addColumn>
+
+     </changeSet>
+
+</databaseChangeLog>
\ No newline at end of file
diff --git a/model/jpa/src/main/resources/META-INF/jpa-changelog-master.xml b/model/jpa/src/main/resources/META-INF/jpa-changelog-master.xml
index 4b7f713..0a26548 100755
--- a/model/jpa/src/main/resources/META-INF/jpa-changelog-master.xml
+++ b/model/jpa/src/main/resources/META-INF/jpa-changelog-master.xml
@@ -45,4 +45,5 @@
     <include file="META-INF/jpa-changelog-2.3.0.xml"/>
     <include file="META-INF/jpa-changelog-2.4.0.xml"/>
     <include file="META-INF/jpa-changelog-2.5.0.xml"/>
+    <include file="META-INF/jpa-changelog-2.5.1.xml"/>
 </databaseChangeLog>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserConsentWithUserStorageModelTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserConsentWithUserStorageModelTest.java
new file mode 100644
index 0000000..6fd18bf
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserConsentWithUserStorageModelTest.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2016 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.testsuite.model;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ModelException;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleModel;
+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.UserStorageProviderModel;
+import org.keycloak.testsuite.federation.storage.UserMapStorageFactory;
+import org.keycloak.testsuite.federation.storage.UserPropertyFileStorageFactory;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class UserConsentWithUserStorageModelTest extends AbstractModelTest {
+
+    @Before
+    public void setupEnv() {
+        RealmModel realm = realmManager.createRealm("original");
+
+        UserStorageProviderModel model = new UserStorageProviderModel();
+        model.setName("memory");
+        model.setPriority(0);
+        model.setProviderId(UserMapStorageFactory.PROVIDER_ID);
+        model.setParentId(realm.getId());
+        realm.addComponentModel(model);
+
+        ClientModel fooClient = realm.addClient("foo-client");
+        ClientModel barClient = realm.addClient("bar-client");
+
+        RoleModel realmRole = realm.addRole("realm-role");
+        RoleModel barClientRole = barClient.addRole("bar-client-role");
+
+        ProtocolMapperModel fooMapper = new ProtocolMapperModel();
+        fooMapper.setName("foo");
+        fooMapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
+        fooMapper.setProtocolMapper(UserPropertyMapper.PROVIDER_ID);
+        fooMapper = fooClient.addProtocolMapper(fooMapper);
+
+        ProtocolMapperModel barMapper = new ProtocolMapperModel();
+        barMapper.setName("bar");
+        barMapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
+        barMapper.setProtocolMapper(UserPropertyMapper.PROVIDER_ID);
+        barMapper = barClient.addProtocolMapper(barMapper);
+
+        UserModel john = session.users().addUser(realm, "john");
+        UserModel mary = session.users().addUser(realm, "mary");
+
+        UserConsentModel johnFooGrant = new UserConsentModel(fooClient);
+        johnFooGrant.addGrantedRole(realmRole);
+        johnFooGrant.addGrantedRole(barClientRole);
+        johnFooGrant.addGrantedProtocolMapper(fooMapper);
+        realmManager.getSession().users().addConsent(realm, john.getId(), johnFooGrant);
+
+        UserConsentModel johnBarGrant = new UserConsentModel(barClient);
+        johnBarGrant.addGrantedProtocolMapper(barMapper);
+        johnBarGrant.addGrantedRole(realmRole);
+
+        // Update should fail as grant doesn't yet exists
+        try {
+            realmManager.getSession().users().updateConsent(realm, john.getId(), johnBarGrant);
+            Assert.fail("Not expected to end here");
+        } catch (ModelException expected) {
+        }
+
+        realmManager.getSession().users().addConsent(realm, john.getId(), johnBarGrant);
+
+        UserConsentModel maryFooGrant = new UserConsentModel(fooClient);
+        maryFooGrant.addGrantedRole(realmRole);
+        maryFooGrant.addGrantedProtocolMapper(fooMapper);
+        realmManager.getSession().users().addConsent(realm, mary.getId(), maryFooGrant);
+
+        commit();
+    }
+
+    @Test
+    public void basicConsentTest() {
+        RealmModel realm = realmManager.getRealm("original");
+        ClientModel fooClient = realm.getClientByClientId("foo-client");
+        ClientModel barClient = realm.getClientByClientId("bar-client");
+
+        UserModel john = session.users().getUserByUsername("john", realm);
+        UserModel mary = session.users().getUserByUsername("mary", realm);
+
+        UserConsentModel johnFooConsent = realmManager.getSession().users().getConsentByClient(realm, john.getId(), fooClient.getId());
+        Assert.assertEquals(johnFooConsent.getGrantedRoles().size(), 2);
+        Assert.assertEquals(johnFooConsent.getGrantedProtocolMappers().size(), 1);
+        Assert.assertTrue(isRoleGranted(realm, "realm-role", johnFooConsent));
+        Assert.assertTrue(isRoleGranted(barClient, "bar-client-role", johnFooConsent));
+        Assert.assertTrue(isMapperGranted(fooClient, "foo", johnFooConsent));
+        Assert.assertNotNull("Created Date should be set", johnFooConsent.getCreatedDate());
+        Assert.assertNotNull("Last Updated Date should be set", johnFooConsent.getLastUpdatedDate());
+
+        UserConsentModel johnBarConsent = realmManager.getSession().users().getConsentByClient(realm, john.getId(), barClient.getId());
+        Assert.assertEquals(johnBarConsent.getGrantedRoles().size(), 1);
+        Assert.assertEquals(johnBarConsent.getGrantedProtocolMappers().size(), 1);
+        Assert.assertTrue(isRoleGranted(realm, "realm-role", johnBarConsent));
+        Assert.assertTrue(isMapperGranted(barClient, "bar", johnBarConsent));
+        Assert.assertNotNull("Created Date should be set", johnBarConsent.getCreatedDate());
+        Assert.assertNotNull("Last Updated Date should be set", johnBarConsent.getLastUpdatedDate());
+
+        UserConsentModel maryConsent = realmManager.getSession().users().getConsentByClient(realm, mary.getId(), fooClient.getId());
+        Assert.assertEquals(maryConsent.getGrantedRoles().size(), 1);
+        Assert.assertEquals(maryConsent.getGrantedProtocolMappers().size(), 1);
+        Assert.assertTrue(isRoleGranted(realm, "realm-role", maryConsent));
+        Assert.assertFalse(isRoleGranted(barClient, "bar-client-role", maryConsent));
+        Assert.assertTrue(isMapperGranted(fooClient, "foo", maryConsent));
+        Assert.assertNotNull("Created Date should be set", maryConsent.getCreatedDate());
+        Assert.assertNotNull("Last Updated Date should be set", maryConsent.getLastUpdatedDate());
+
+        Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, mary.getId(), barClient.getId()));
+    }
+
+    @Test
+    public void getAllConsentTest() {
+        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);
+
+        List<UserConsentModel> johnConsents = realmManager.getSession().users().getConsents(realm, john.getId());
+        Assert.assertEquals(2, johnConsents.size());
+
+        List<UserConsentModel> maryConsents = realmManager.getSession().users().getConsents(realm, mary.getId());
+        Assert.assertEquals(1, maryConsents.size());
+        UserConsentModel maryConsent = 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));
+    }
+
+    @Test
+    public void updateWithRoleRemovalTest() {
+        RealmModel realm = realmManager.getRealm("original");
+        ClientModel fooClient = realm.getClientByClientId("foo-client");
+        UserModel john = session.users().getUserByUsername("john", realm);
+
+        UserConsentModel johnConsent = realmManager.getSession().users().getConsentByClient(realm, john.getId(), fooClient.getId());
+
+        // Remove foo protocol mapper from johnConsent
+        ProtocolMapperModel protMapperModel = fooClient.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, "foo");
+        johnConsent.getGrantedProtocolMappers().remove(protMapperModel);
+
+        // Remove realm-role and add new-realm-role to johnConsent
+        RoleModel realmRole = realm.getRole("realm-role");
+        johnConsent.getGrantedRoles().remove(realmRole);
+
+        RoleModel newRealmRole = realm.addRole("new-realm-role");
+        johnConsent.addGrantedRole(newRealmRole);
+
+        realmManager.getSession().users().updateConsent(realm, john.getId(), johnConsent);
+
+        commit();
+
+        realm = realmManager.getRealm("original");
+        fooClient = realm.getClientByClientId("foo-client");
+        john = session.users().getUserByUsername("john", realm);
+        johnConsent = realmManager.getSession().users().getConsentByClient(realm, john.getId(), fooClient.getId());
+
+        Assert.assertEquals(johnConsent.getGrantedRoles().size(), 2);
+        Assert.assertEquals(johnConsent.getGrantedProtocolMappers().size(), 0);
+        Assert.assertFalse(isRoleGranted(realm, "realm-role", johnConsent));
+        Assert.assertTrue(isRoleGranted(realm, "new-realm-role", johnConsent));
+        Assert.assertFalse(isMapperGranted(fooClient, "foo", johnConsent));
+        Assert.assertTrue("Created date should be less than last updated date", johnConsent.getCreatedDate() < johnConsent.getLastUpdatedDate());
+    }
+
+    @Test
+    public void revokeTest() {
+        RealmModel realm = realmManager.getRealm("original");
+        ClientModel fooClient = realm.getClientByClientId("foo-client");
+        UserModel john = session.users().getUserByUsername("john", realm);
+
+        realmManager.getSession().users().revokeConsentForClient(realm, john.getId(), fooClient.getId());
+
+        commit();
+
+        realm = realmManager.getRealm("original");
+        john = session.users().getUserByUsername("john", realm);
+        Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, john.getId(), fooClient.getId()));
+    }
+
+    @Test
+    public void deleteUserTest() {
+        // Validate user deleted without any referential constraint errors
+        RealmModel realm = realmManager.getRealm("original");
+        UserModel john = session.users().getUserByUsername("john", realm);
+        session.users().removeUser(realm, john);
+    }
+
+    @Test
+    public void deleteProtocolMapperTest() {
+        RealmModel realm = realmManager.getRealm("original");
+        ClientModel fooClient = realm.getClientByClientId("foo-client");
+        ProtocolMapperModel fooMapper = fooClient.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, "foo");
+        fooClient.removeProtocolMapper(fooMapper);
+
+        commit();
+
+        realm = realmManager.getRealm("original");
+        fooClient = realm.getClientByClientId("foo-client");
+        UserModel john = session.users().getUserByUsername("john", realm);
+        UserConsentModel johnConsent = realmManager.getSession().users().getConsentByClient(realm, john.getId(), fooClient.getId());
+
+        Assert.assertEquals(johnConsent.getGrantedRoles().size(), 2);
+        Assert.assertEquals(johnConsent.getGrantedProtocolMappers().size(), 0);
+        Assert.assertFalse(johnConsent.isProtocolMapperGranted(fooMapper));
+    }
+
+    @Test
+    public void deleteRoleTest() {
+        RealmModel realm = realmManager.getRealm("original");
+        RoleModel realmRole = realm.getRole("realm-role");
+        realm.removeRole(realmRole);
+
+        commit();
+
+        realm = realmManager.getRealm("original");
+        ClientModel fooClient = realm.getClientByClientId("foo-client");
+        ClientModel barClient = realm.getClientByClientId("bar-client");
+        UserModel john = session.users().getUserByUsername("john", realm);
+        UserConsentModel johnConsent = realmManager.getSession().users().getConsentByClient(realm, john.getId(), fooClient.getId());
+
+        Assert.assertEquals(johnConsent.getGrantedRoles().size(), 1);
+        Assert.assertEquals(johnConsent.getGrantedProtocolMappers().size(), 1);
+        Assert.assertFalse(johnConsent.isRoleGranted(realmRole));
+        Assert.assertTrue(isRoleGranted(barClient, "bar-client-role", johnConsent));
+    }
+
+    @Test
+    public void deleteClientTest() {
+        RealmModel realm = realmManager.getRealm("original");
+        ClientModel barClient = realm.getClientByClientId("bar-client");
+        realm.removeClient(barClient.getId());
+
+        commit();
+
+        realm = realmManager.getRealm("original");
+        ClientModel fooClient = realm.getClientByClientId("foo-client");
+        Assert.assertNull(realm.getClientByClientId("bar-client"));
+
+        UserModel john = session.users().getUserByUsername("john", realm);
+
+        UserConsentModel johnFooConsent = realmManager.getSession().users().getConsentByClient(realm, john.getId(), fooClient.getId());
+        Assert.assertEquals(johnFooConsent.getGrantedRoles().size(), 1);
+        Assert.assertEquals(johnFooConsent.getGrantedProtocolMappers().size(), 1);
+        Assert.assertTrue(isRoleGranted(realm, "realm-role", johnFooConsent));
+        Assert.assertTrue(isMapperGranted(fooClient, "foo", johnFooConsent));
+
+        Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, john.getId(), barClient.getId()));
+    }
+
+    private boolean isRoleGranted(RoleContainerModel roleContainer, String roleName, UserConsentModel consentModel) {
+        RoleModel role = roleContainer.getRole(roleName);
+        return consentModel.isRoleGranted(role);
+    }
+
+    private boolean isMapperGranted(ClientModel client, String protocolMapperName, UserConsentModel consentModel) {
+        ProtocolMapperModel protocolMapper = client.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, protocolMapperName);
+        return consentModel.isProtocolMapperGranted(protocolMapper);
+    }
+}