composite roles 2

This commit is contained in:
Bill Burke 2014-01-29 23:28:08 -05:00
parent bb5991239b
commit 6a5994c3e2
6 changed files with 98 additions and 41 deletions

View file

@ -30,4 +30,5 @@ public interface RoleModel {
RoleContainerModel getContainer();
boolean hasRole(RoleModel role);
}

View file

@ -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());
}
}

View file

@ -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());
}
}

View file

@ -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) {

View file

@ -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);
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);
}
}
}
}
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);
}
}
}
} 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);
}

View file

@ -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"));
}
}