Details
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 c2a9507..e4cd7f5 100755
--- a/model/api/src/main/java/org/keycloak/models/RoleModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RoleModel.java
@@ -30,4 +30,5 @@ 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 6f46042..29dfdbd 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
@@ -261,4 +261,11 @@ public class ApplicationAdapter implements ApplicationModel {
public void addScope(RoleModel role) {
realm.addScopeMapping(getApplicationUser(), role);
}
+
+ public boolean equals(Object o) {
+ if (o == null) return false;
+ 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/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
index a627a84..82a95b5 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
@@ -897,28 +897,13 @@ public class RealmAdapter implements RealmModel {
return new RoleAdapter(this, em, entity);
}
- protected boolean searchCompositeFor(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;
- }
- return false;
- }
-
@Override
public boolean hasRole(UserModel user, RoleModel role) {
Set<RoleModel> roles = getRoleMappings(user);
if (roles.contains(role)) return true;
- Set<RoleModel> visited = new HashSet<RoleModel>();
for (RoleModel mapping : roles) {
- if (!mapping.isComposite()) continue;
- if (searchCompositeFor(role, mapping, visited)) return true;
-
+ if (mapping.hasRole(role)) return true;
}
return false;
}
@@ -1104,4 +1089,12 @@ public class RealmAdapter implements RealmModel {
realm.setPasswordPolicy(policy.toString());
em.flush();
}
+
+ public boolean equals(Object o) {
+ if (o == null) return false;
+ if (!(o instanceof RealmAdapter)) return false;
+ RealmAdapter r = (RealmAdapter)o;
+ return r.getId().equals(getId());
+ }
+
}
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 87c09d0..529fc7d 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,6 +3,7 @@ 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;
@@ -97,6 +98,27 @@ public class RoleAdapter implements RoleModel {
return set;
}
+ public static boolean searchCompositeFor(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;
+ }
+ 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);
+ }
+
@Override
public RoleContainerModel getContainer() {
if (role instanceof ApplicationRoleEntity) {
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 6531942..8cdb690 100755
--- a/services/src/main/java/org/keycloak/services/managers/TokenManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
@@ -16,6 +16,7 @@ import javax.ws.rs.core.MultivaluedMap;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -69,31 +70,34 @@ public class TokenManager {
List<RoleModel> realmRolesRequested = code.getRealmRolesRequested();
MultivaluedMap<String, RoleModel> resourceRolesRequested = code.getResourceRolesRequested();
- Set<RoleModel> realmScopeMappings = realm.getRealmScopeMappings(client);
- for (RoleModel desiredRole : realmScopeMappings) {
- if (!realm.hasRole(user, desiredRole)) continue;
- if (desiresScope(scopeMap, "realm", desiredRole.getName())) {
- realmRolesRequested.add(desiredRole);
- }
- }
- for (ApplicationModel application : realm.getApplications()) {
- if (!desiresScopeGroup(scopeMap, application.getName())) continue;
- Set<RoleModel> desiredRoles = application.getApplicationScopeMappings(client);
- if (desiredRoles.isEmpty()) {
- if (application.getApplicationUser().getLoginName().equals(client.getLoginName())) {
- Set<RoleModel> appRoleMappings = application.getApplicationRoleMappings(user);
- for (RoleModel desiredAppRole : appRoleMappings) {
- if (desiresScope(scopeMap, application.getName(), desiredAppRole.getName())) {
- resourceRolesRequested.add(application.getName(), desiredAppRole);
- }
+ Set<RoleModel> roleMappings = realm.getRoleMappings(user);
+ Set<RoleModel> scopeMappings = realm.getScopeMappings(client);
+ Set<RoleModel> requestedRoles = new HashSet<RoleModel>();
+
+ for (RoleModel role : roleMappings) {
+ 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);
}
}
- } else {
- for (RoleModel desiredAppRole : desiredRoles) {
- if (realm.hasRole(user, desiredAppRole) && desiresScope(scopeMap, application.getName(), desiredAppRole.getName())) {
- resourceRolesRequested.add(application.getName(), desiredAppRole);
- }
+ }
+ }
+
+ for (RoleModel role : requestedRoles) {
+ if (role.getContainer() instanceof RealmModel && desiresScope(scopeMap, "realm", role.getName())) {
+ realmRolesRequested.add(role);
+ } else if (role.getContainer() instanceof ApplicationModel) {
+ ApplicationModel app = (ApplicationModel)role.getContainer();
+ if (desiresScope(scopeMap, app.getName(), role.getName())) {
+ resourceRolesRequested.add(app.getName(), role);
}
}
}
@@ -166,7 +170,6 @@ public class TokenManager {
SkeletonKeyToken token = initToken(realm, client, user);
if (accessCodeEntry.getRealmRolesRequested().size() > 0) {
- SkeletonKeyToken.Access access = new SkeletonKeyToken.Access();
for (RoleModel role : accessCodeEntry.getRealmRolesRequested()) {
addComposites(token, role);
}
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 ddde357..d21d85f 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
@@ -58,6 +58,8 @@ public class CompositeRoleTest {
manager.generateRealmKeys(realm);
realmPublicKey = realm.getPublicKey();
realm.setTokenLifespan(10000);
+ realm.setAccessCodeLifespanUserAction(1000);
+ realm.setAccessCodeLifespan(1000);
realm.setSslNotRequired(true);
realm.setEnabled(true);
realm.addRequiredResourceCredential(UserCredentialModel.PASSWORD);
@@ -75,6 +77,11 @@ public class CompositeRoleTest {
realm.updateCredential(realmComposite1User, UserCredentialModel.password("password"));
realm.grantRole(realmComposite1User, realmComposite1);
+ final UserModel realmRole1User = realm.addUser("REALM_ROLE_1_USER");
+ realmRole1User.setEnabled(true);
+ realm.updateCredential(realmRole1User, UserCredentialModel.password("password"));
+ realm.grantRole(realmRole1User, realmRole1);
+
final ApplicationModel realmComposite1Application = new ApplicationManager(manager).createApplication(realm, "REALM_COMPOSITE_1_APPLICATION");
realmComposite1Application.setEnabled(true);
realmComposite1Application.addScope(realmComposite1);
@@ -109,7 +116,7 @@ public class CompositeRoleTest {
protected LoginPage loginPage;
@Test
- public void testRealmOnlyCompositeWithUserCompositeAppComposite() throws Exception {
+ public void testRealmOnlyWithUserCompositeAppComposite() throws Exception {
oauth.realm("Test");
oauth.realmPublicKey(realmPublicKey);
oauth.clientId("REALM_COMPOSITE_1_APPLICATION");
@@ -132,7 +139,7 @@ public class CompositeRoleTest {
}
@Test
- public void testRealmOnlyCompositeWithUserCompositeAppRole() throws Exception {
+ public void testRealmOnlyWithUserCompositeAppRole() throws Exception {
oauth.realm("Test");
oauth.realmPublicKey(realmPublicKey);
oauth.clientId("REALM_ROLE_1_APPLICATION");
@@ -153,5 +160,29 @@ public class CompositeRoleTest {
Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1"));
}
+ @Test
+ public void testRealmOnlyWithUserRoleAppComposite() throws Exception {
+ oauth.realm("Test");
+ oauth.realmPublicKey(realmPublicKey);
+ oauth.clientId("REALM_COMPOSITE_1_APPLICATION");
+ oauth.doLogin("REALM_ROLE_1_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_ROLE_1_USER", token.getSubject());
+
+ Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
+ Assert.assertTrue(token.getRealmAccess().isUserInRole("REALM_ROLE_1"));
+ }
+
+
+
}