keycloak-aplcache

composite tests

1/30/2014 11:31:44 PM

Details

diff --git a/model/api/src/main/java/org/keycloak/models/RoleContainerModel.java b/model/api/src/main/java/org/keycloak/models/RoleContainerModel.java
index a34d4c8..bd8bfab 100755
--- a/model/api/src/main/java/org/keycloak/models/RoleContainerModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RoleContainerModel.java
@@ -1,6 +1,7 @@
 package org.keycloak.models;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -13,7 +14,7 @@ public interface RoleContainerModel {
 
     boolean removeRoleById(String id);
 
-    List<RoleModel> getRoles();
+    Set<RoleModel> getRoles();
 
     RoleModel getRoleById(String id);
 }
diff --git a/model/api/src/main/java/org/keycloak/models/RoleModel.java b/model/api/src/main/java/org/keycloak/models/RoleModel.java
index e4cd7f5..1cacaff 100755
--- a/model/api/src/main/java/org/keycloak/models/RoleModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RoleModel.java
@@ -29,6 +29,6 @@ public interface RoleModel {
 
     RoleContainerModel getContainer();
 
-
     boolean hasRole(RoleModel role);
+
 }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java
index 29dfdbd..8f650c6 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java
@@ -143,8 +143,8 @@ public class ApplicationAdapter implements ApplicationModel {
     }
 
     @Override
-    public List<RoleModel> getRoles() {
-        ArrayList<RoleModel> list = new ArrayList<RoleModel>();
+    public Set<RoleModel> getRoles() {
+        Set<RoleModel> list = new HashSet<RoleModel>();
         Collection<ApplicationRoleEntity> roles = application.getRoles();
         if (roles == null) return list;
         for (RoleEntity entity : roles) {
@@ -264,6 +264,7 @@ public class ApplicationAdapter implements ApplicationModel {
 
     public boolean equals(Object o) {
         if (o == null) return false;
+        if (o == this) return true;
         if (!(o instanceof ApplicationAdapter)) return false;
         ApplicationAdapter app = (ApplicationAdapter)o;
         return app.getId().equals(getId());
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java
index f65a59f..6d14601 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java
@@ -8,6 +8,7 @@ import javax.persistence.Id;
 import javax.persistence.Inheritance;
 import javax.persistence.InheritanceType;
 import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
 import javax.persistence.OneToMany;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -17,16 +18,17 @@ import java.util.Collection;
  * @version $Revision: 1 $
  */
 @Entity
+@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
 public abstract class RoleEntity {
     @Id
-    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @GeneratedValue(strategy = GenerationType.AUTO)
     private String id;
 
     private String name;
     private String description;
     private boolean composite;
-    @OneToMany(fetch = FetchType.LAZY, cascade = {}, orphanRemoval = false)
-    @JoinTable(name = "COMPOSITE_ROLE")
+    @ManyToMany(fetch = FetchType.LAZY, cascade = {})
+    //@JoinTable(name = "COMPOSITE_ROLE")
     private Collection<RoleEntity> compositeRoles = new ArrayList<RoleEntity>();
 
 
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
index 82a95b5..b14fa97 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
@@ -880,8 +880,8 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
-    public List<RoleModel> getRoles() {
-        ArrayList<RoleModel> list = new ArrayList<RoleModel>();
+    public Set<RoleModel> getRoles() {
+        Set<RoleModel> list = new HashSet<RoleModel>();
         Collection<RealmRoleEntity> roles = realm.getRoles();
         if (roles == null) return list;
         for (RoleEntity entity : roles) {
@@ -1000,7 +1000,6 @@ public class RealmAdapter implements RealmModel {
         entity.setUser(((UserAdapter) agent).getUser());
         entity.setRole(((RoleAdapter)role).getRole());
         em.persist(entity);
-        em.flush();
     }
 
     @Override
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java
index 529fc7d..69aa3ae 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java
@@ -3,7 +3,6 @@ package org.keycloak.models.jpa;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleContainerModel;
 import org.keycloak.models.RoleModel;
-import org.keycloak.models.UserModel;
 import org.keycloak.models.jpa.entities.ApplicationRoleEntity;
 import org.keycloak.models.jpa.entities.RealmRoleEntity;
 import org.keycloak.models.jpa.entities.RoleEntity;
@@ -23,6 +22,7 @@ public class RoleAdapter implements RoleModel {
     protected RealmModel realm;
 
     public RoleAdapter(RealmModel realm, EntityManager em, RoleEntity role) {
+        this.em = em;
         this.realm = realm;
         this.role = role;
     }
@@ -77,6 +77,7 @@ public class RoleAdapter implements RoleModel {
             if (composite.equals(entity)) return;
         }
         getRole().getCompositeRoles().add(entity);
+        em.flush();
     }
 
     @Override
@@ -98,25 +99,27 @@ public class RoleAdapter implements RoleModel {
         return set;
     }
 
-    public static boolean searchCompositeFor(RoleModel role, RoleModel composite, Set<RoleModel> visited) {
+    public static boolean searchFor(RoleModel role, RoleModel composite, Set<RoleModel> visited) {
         if (visited.contains(composite)) return false;
         visited.add(composite);
         Set<RoleModel> composites = composite.getComposites();
         if (composites.contains(role)) return true;
         for (RoleModel contained : composites) {
             if (!contained.isComposite()) continue;
-            if (searchCompositeFor(role, contained, visited)) return true;
+            if (searchFor(role, contained, visited)) return true;
         }
         return false;
     }
 
+
+
     @Override
     public boolean hasRole(RoleModel role) {
         if (this.equals(role)) return true;
         if (!isComposite()) return false;
 
         Set<RoleModel> visited = new HashSet<RoleModel>();
-        return searchCompositeFor(role, this, visited);
+        return searchFor(role, this, visited);
     }
 
     @Override
diff --git a/services/src/main/java/org/keycloak/services/managers/TokenManager.java b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
index 8cdb690..e447ab1 100755
--- a/services/src/main/java/org/keycloak/services/managers/TokenManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
@@ -62,6 +62,21 @@ public class TokenManager {
         return scope == null || scope.isEmpty();
     }
 
+    public static void addScopes(RoleModel role, RoleModel scope, Set<RoleModel> visited, Set<RoleModel> requested) {
+        if (visited.contains(scope)) return;
+        visited.add(scope);
+        if (role.hasRole(scope)) {
+            requested.add(scope);
+            return;
+        }
+        if (!scope.isComposite()) return;
+
+        for (RoleModel contained : scope.getComposites()) {
+            addScopes(role, contained, visited, requested);
+        }
+    }
+
+
 
     public AccessCodeEntry createAccessCode(String scopeParam, String state, String redirect, RealmModel realm, UserModel client, UserModel user) {
         AccessCodeEntry code = new AccessCodeEntry();
@@ -73,21 +88,17 @@ public class TokenManager {
 
         Set<RoleModel> roleMappings = realm.getRoleMappings(user);
         Set<RoleModel> scopeMappings = realm.getScopeMappings(client);
+        ApplicationModel clientApp = realm.getApplicationByName(client.getLoginName());
+        Set<RoleModel> clientAppRoles = clientApp == null ? null : clientApp.getRoles();
+        if (clientAppRoles != null) scopeMappings.addAll(clientAppRoles);
+
         Set<RoleModel> requestedRoles = new HashSet<RoleModel>();
 
         for (RoleModel role : roleMappings) {
+            if (clientApp != null && role.getContainer().equals(clientApp)) requestedRoles.add(role);
             for (RoleModel desiredRole : scopeMappings) {
-                if (desiredRole.equals(role)) {
-                    requestedRoles.add(role);
-                } else if (desiredRole.hasRole(role)) {
-                    requestedRoles.add(role);
-                } else if (role.hasRole(desiredRole)) {
-                    requestedRoles.add(desiredRole);
-                } else if (role.getContainer() instanceof ApplicationModel) {
-                    if (((ApplicationModel)role.getContainer()).getApplicationUser().getLoginName().equals(client.getLoginName())) {
-                        requestedRoles.add(role);
-                    }
-                }
+                Set<RoleModel> visited = new HashSet<RoleModel>();
+                addScopes(role, desiredRole, visited, requestedRoles);
             }
         }
 
@@ -98,6 +109,36 @@ public class TokenManager {
                 ApplicationModel app = (ApplicationModel)role.getContainer();
                 if (desiresScope(scopeMap, app.getName(), role.getName())) {
                     resourceRolesRequested.add(app.getName(), role);
+
+                }
+            }
+        }
+
+
+
+
+        Set<RoleModel> realmRoleMappings = realm.getRealmRoleMappings(user);
+
+        for (RoleModel role : realmRoleMappings) {
+            if (!desiresScope(scopeMap, "realm", role.getName())) continue;
+            for (RoleModel desiredRole : scopeMappings) {
+                if (desiredRole.hasRole(role)) {
+                    realmRolesRequested.add(role);
+                } else if (role.hasRole(desiredRole)) {
+                    realmRolesRequested.add(desiredRole);
+                }
+            }
+        }
+
+        for (ApplicationModel application : realm.getApplications()) {
+            if (!desiresScopeGroup(scopeMap, application.getName())) continue;
+            Set<RoleModel> appRoleMappings = application.getApplicationRoleMappings(user);
+            for (RoleModel role : appRoleMappings) {
+                if (!desiresScope(scopeMap, application.getName(), role.getName())) continue;
+                for (RoleModel desiredRole : scopeMappings) {
+                    if (!application.getApplicationUser().getLoginName().equals(client.getLoginName())
+                          && !desiredRole.hasRole(role)) continue;
+                    resourceRolesRequested.add(application.getName(), role);
                 }
             }
         }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
index 3d43178..1971b31 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
@@ -34,7 +34,7 @@ public class RoleContainerResource {
     @NoCache
     @Produces("application/json")
     public List<RoleRepresentation> getRoles() {
-        List<RoleModel> roleModels = roleContainer.getRoles();
+        Set<RoleModel> roleModels = roleContainer.getRoles();
         List<RoleRepresentation> roles = new ArrayList<RoleRepresentation>();
         for (RoleModel roleModel : roleModels) {
             if (!roleModel.getName().startsWith(Constants.INTERNAL_ROLE)) {
diff --git a/services/src/test/java/org/keycloak/test/AdapterTest.java b/services/src/test/java/org/keycloak/test/AdapterTest.java
index 3c49cd4..9f49a98 100755
--- a/services/src/test/java/org/keycloak/test/AdapterTest.java
+++ b/services/src/test/java/org/keycloak/test/AdapterTest.java
@@ -448,7 +448,7 @@ public class AdapterTest extends AbstractKeycloakTest {
         test1CreateRealm();
         realmModel.addRole("admin");
         realmModel.addRole("user");
-        List<RoleModel> roles = realmModel.getRoles();
+        Set<RoleModel> roles = realmModel.getRoles();
         Assert.assertEquals(5, roles.size());
         UserModel user = realmModel.addUser("bburke");
         RoleModel role = realmModel.getRole("user");
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java
index d21d85f..3cc1e40 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java
@@ -97,6 +97,46 @@ public class CompositeRoleTest {
             realm.updateCredential(realmRole1Application.getApplicationUser(), UserCredentialModel.password("password"));
 
 
+            final ApplicationModel appRoleApplication = new ApplicationManager(manager).createApplication(realm, "APP_ROLE_APPLICATION");
+            appRoleApplication.setEnabled(true);
+            appRoleApplication.setBaseUrl("http://localhost:8081/app");
+            appRoleApplication.setManagementUrl("http://localhost:8081/app/logout");
+            realm.updateCredential(appRoleApplication.getApplicationUser(), UserCredentialModel.password("password"));
+            final RoleModel appRole1 = appRoleApplication.addRole("APP_ROLE_1");
+            final RoleModel appRole2 = appRoleApplication.addRole("APP_ROLE_2");
+
+            final RoleModel realmAppCompositeRole = realm.addRole("REALM_APP_COMPOSITE_ROLE");
+            realmAppCompositeRole.setComposite(true);
+            realmAppCompositeRole.addCompositeRole(appRole1);
+
+            final UserModel realmAppCompositeUser = realm.addUser("REALM_APP_COMPOSITE_USER");
+            realmAppCompositeUser.setEnabled(true);
+            realm.updateCredential(realmAppCompositeUser, UserCredentialModel.password("password"));
+            realm.grantRole(realmAppCompositeUser, realmAppCompositeRole);
+
+            final UserModel realmAppRoleUser = realm.addUser("REALM_APP_ROLE_USER");
+            realmAppRoleUser.setEnabled(true);
+            realm.updateCredential(realmAppRoleUser, UserCredentialModel.password("password"));
+            realm.grantRole(realmAppRoleUser, appRole2);
+
+            final ApplicationModel appCompositeApplication = new ApplicationManager(manager).createApplication(realm, "APP_COMPOSITE_APPLICATION");
+            appCompositeApplication.setEnabled(true);
+            appCompositeApplication.setBaseUrl("http://localhost:8081/app");
+            appCompositeApplication.setManagementUrl("http://localhost:8081/app/logout");
+            realm.updateCredential(appCompositeApplication.getApplicationUser(), UserCredentialModel.password("password"));
+            final RoleModel appCompositeRole = appCompositeApplication.addRole("APP_COMPOSITE_ROLE");
+            appCompositeRole.setComposite(true);
+            appCompositeApplication.addScope(appRole2);
+            appCompositeRole.addCompositeRole(realmRole1);
+            appCompositeRole.addCompositeRole(realmRole2);
+            appCompositeRole.addCompositeRole(realmRole3);
+            appCompositeRole.addCompositeRole(appRole1);
+
+            final UserModel appCompositeUser = realm.addUser("APP_COMPOSITE_USER");
+            appCompositeUser.setEnabled(true);
+            realm.updateCredential(appCompositeUser, UserCredentialModel.password("password"));
+            realm.grantRole(appCompositeUser, realmAppCompositeRole);
+            realm.grantRole(appCompositeUser, realmComposite1);
 
             deployServlet("app", "/app", ApplicationServlet.class);
 
@@ -116,6 +156,55 @@ public class CompositeRoleTest {
     protected LoginPage loginPage;
 
     @Test
+    public void testAppCompositeUser() throws Exception {
+        oauth.realm("Test");
+        oauth.realmPublicKey(realmPublicKey);
+        oauth.clientId("APP_COMPOSITE_APPLICATION");
+        oauth.doLogin("APP_COMPOSITE_USER", "password");
+
+        String code = oauth.getCurrentQuery().get("code");
+        AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
+
+        Assert.assertEquals(200, response.getStatusCode());
+
+        Assert.assertEquals("bearer", response.getTokenType());
+
+        SkeletonKeyToken token = oauth.verifyToken(response.getAccessToken());
+
+        Assert.assertEquals("APP_COMPOSITE_USER", token.getSubject());
+
+        Assert.assertEquals(1, token.getResourceAccess("APP_ROLE_APPLICATION").getRoles().size());
+        Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
+        Assert.assertTrue(token.getResourceAccess("APP_ROLE_APPLICATION").isUserInRole("APP_ROLE_1"));
+        Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1"));
+    }
+
+
+    @Test
+    public void testRealmAppCompositeUser() throws Exception {
+        oauth.realm("Test");
+        oauth.realmPublicKey(realmPublicKey);
+        oauth.clientId("APP_ROLE_APPLICATION");
+        oauth.doLogin("REALM_APP_COMPOSITE_USER", "password");
+
+        String code = oauth.getCurrentQuery().get("code");
+        AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
+
+        Assert.assertEquals(200, response.getStatusCode());
+
+        Assert.assertEquals("bearer", response.getTokenType());
+
+        SkeletonKeyToken token = oauth.verifyToken(response.getAccessToken());
+
+        Assert.assertEquals("REALM_APP_COMPOSITE_USER", token.getSubject());
+
+        Assert.assertEquals(1, token.getResourceAccess("APP_ROLE_APPLICATION").getRoles().size());
+        Assert.assertTrue(token.getResourceAccess("APP_ROLE_APPLICATION").isUserInRole("APP_ROLE_1"));
+    }
+
+
+
+    @Test
     public void testRealmOnlyWithUserCompositeAppComposite() throws Exception {
         oauth.realm("Test");
         oauth.realmPublicKey(realmPublicKey);