[KEYCLOAK-7885] Add user policy support to the policy API

This commit is contained in:
Stefan Guilhen 2018-08-13 00:23:44 -03:00 committed by Pedro Igor
parent 1912a8acf4
commit 0b95cdacb8
3 changed files with 152 additions and 24 deletions

View file

@ -45,6 +45,7 @@ import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation.RoleDefinition;
import org.keycloak.representations.idm.authorization.UmaPermissionRepresentation;
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
@ -106,6 +107,14 @@ public class UMAPolicyProviderFactory implements PolicyProviderFactory<UmaPermis
}
}
Set<String> users = representation.getUsers();
if (users != null) {
for (String user : users) {
createUserPolicy(policy, policyStore, user, representation.getOwner());
}
}
String condition = representation.getCondition();
if (condition != null) {
@ -184,6 +193,24 @@ public class UMAPolicyProviderFactory implements PolicyProviderFactory<UmaPermis
} else {
RepresentationToModel.toModel(rep, authorization, associatedPolicy);
}
} else if ("user".equals(associatedRep.getType())) {
UserPolicyRepresentation rep = UserPolicyRepresentation.class.cast(associatedRep);
rep.setUsers(new HashSet<>());
Set<String> updatedUsers = representation.getUsers();
if (updatedUsers != null) {
for (String user : updatedUsers) {
rep.addUser(user);
}
}
if (rep.getUsers().isEmpty()) {
policyStore.delete(associatedPolicy.getId());
} else {
RepresentationToModel.toModel(rep, authorization, associatedPolicy);
}
}
}
@ -241,6 +268,24 @@ public class UMAPolicyProviderFactory implements PolicyProviderFactory<UmaPermis
}
}
Set<String> updatedUsers = representation.getUsers();
if (updatedUsers != null) {
boolean createPolicy = true;
for (Policy associatedPolicy : associatedPolicies) {
if ("user".equals(associatedPolicy.getType())) {
createPolicy = false;
}
}
if (createPolicy) {
for (String user : updatedUsers) {
createUserPolicy(policy, policyStore, user, policy.getOwner());
}
}
}
String condition = representation.getCondition();
if (condition != null) {
@ -300,6 +345,12 @@ public class UMAPolicyProviderFactory implements PolicyProviderFactory<UmaPermis
for (String client : rep.getClients()) {
representation.addClient(realm.getClientById(client).getClientId());
}
} else if ("user".equals(associatedPolicy.getType())) {
UserPolicyRepresentation rep = UserPolicyRepresentation.class.cast(associatedRep);
for (String user : rep.getUsers()) {
representation.addUser(authorization.getKeycloakSession().users().getUserById(user, realm).getUsername());
}
}
}
@ -391,4 +442,17 @@ public class UMAPolicyProviderFactory implements PolicyProviderFactory<UmaPermis
policy.addAssociatedPolicy(associatedPolicy);
}
private void createUserPolicy(Policy policy, PolicyStore policyStore, String user, String owner) {
UserPolicyRepresentation rep = new UserPolicyRepresentation();
rep.setName(KeycloakModelUtils.generateId());
rep.addUser(user);
Policy associatedPolicy = policyStore.create(rep, policy.getResourceServer());
associatedPolicy.setOwner(owner);
policy.addAssociatedPolicy(associatedPolicy);
}
}

View file

@ -26,11 +26,10 @@ import java.util.Set;
*/
public class UmaPermissionRepresentation extends AbstractPolicyRepresentation {
private String id;
private String description;
private Set<String> roles;
private Set<String> groups;
private Set<String> clients;
private Set<String> users;
private String condition;
@Override
@ -38,22 +37,6 @@ public class UmaPermissionRepresentation extends AbstractPolicyRepresentation {
return "uma";
}
public void setId(String id){
this.id = id;
}
public String getId(){
return id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public void setRoles(Set<String> roles) {
this.roles = roles;
}
@ -124,6 +107,27 @@ public class UmaPermissionRepresentation extends AbstractPolicyRepresentation {
return clients;
}
public void setUsers(Set<String> users) {
this.users = users;
}
public void addUser(String... user) {
if (this.users == null) {
this.users = new HashSet<>();
}
this.users.addAll(Arrays.asList(user));
}
public void removeUser(String user) {
if (this.users != null) {
this.users.remove(user);
}
}
public Set<String> getUsers() {
return this.users;
}
public void setCondition(String condition) {
this.condition = condition;
}

View file

@ -111,6 +111,7 @@ public class UserManagedPermissionServiceTest extends AbstractResourceServerTest
newPermission.addGroup("/group_a", "/group_a/group_b", "/group_c");
newPermission.addClient("client-a", "resource-server-test");
newPermission.setCondition("$evaluation.grant()");
newPermission.addUser("kolo");
ProtectionResource protection = getAuthzClient().protection("marta", "password");
@ -118,11 +119,17 @@ public class UserManagedPermissionServiceTest extends AbstractResourceServerTest
assertEquals(newPermission.getName(), permission.getName());
assertEquals(newPermission.getDescription(), permission.getDescription());
assertNotNull(permission.getScopes());
assertTrue(permission.getScopes().containsAll(newPermission.getScopes()));
assertNotNull(permission.getRoles());
assertTrue(permission.getRoles().containsAll(newPermission.getRoles()));
assertNotNull(permission.getGroups());
assertTrue(permission.getGroups().containsAll(newPermission.getGroups()));
assertNotNull(permission.getClients());
assertTrue(permission.getClients().containsAll(newPermission.getClients()));
assertEquals(newPermission.getCondition(), permission.getCondition());
assertNotNull(permission.getUsers());
assertTrue(permission.getUsers().containsAll(newPermission.getUsers()));
}
@Test
@ -233,6 +240,38 @@ public class UserManagedPermissionServiceTest extends AbstractResourceServerTest
assertEquals(permission.getCondition(), updated.getCondition());
permission.addUser("alice");
protection.policy(resource.getId()).update(permission);
assertEquals(5, getAssociatedPolicies(permission).size());
updated = protection.policy(resource.getId()).findById(permission.getId());
assertEquals(1, updated.getUsers().size());
assertEquals(permission.getUsers(), updated.getUsers());
permission.addUser("kolo");
protection.policy(resource.getId()).update(permission);
assertEquals(5, getAssociatedPolicies(permission).size());
updated = protection.policy(resource.getId()).findById(permission.getId());
assertEquals(2, updated.getUsers().size());
assertEquals(permission.getUsers(), updated.getUsers());
permission.removeUser("alice");
protection.policy(resource.getId()).update(permission);
assertEquals(5, getAssociatedPolicies(permission).size());
updated = protection.policy(resource.getId()).findById(permission.getId());
assertEquals(1, updated.getUsers().size());
assertEquals(permission.getUsers(), updated.getUsers());
permission.setUsers(null);
protection.policy(resource.getId()).update(permission);
assertEquals(4, getAssociatedPolicies(permission).size());
updated = protection.policy(resource.getId()).findById(permission.getId());
assertEquals(permission.getUsers(), updated.getUsers());
permission.setCondition(null);
protection.policy(resource.getId()).update(permission);
@ -308,14 +347,14 @@ public class UserManagedPermissionServiceTest extends AbstractResourceServerTest
protection.policy(resource.getId()).update(permission);
try {
authzResponse = authorization.authorize(request);
authorization.authorize(request);
fail("User should not have permission");
} catch (Exception e) {
assertTrue(AuthorizationDeniedException.class.isInstance(e));
}
try {
authzResponse = getAuthzClient().authorization("alice", "password").authorize(request);
getAuthzClient().authorization("alice", "password").authorize(request);
fail("User should not have permission");
} catch (Exception e) {
assertTrue(AuthorizationDeniedException.class.isInstance(e));
@ -332,7 +371,7 @@ public class UserManagedPermissionServiceTest extends AbstractResourceServerTest
protection.policy(resource.getId()).delete(permission.getId());
try {
authzResponse = authorization.authorize(request);
authorization.authorize(request);
fail("User should not have permission");
} catch (Exception e) {
assertTrue(AuthorizationDeniedException.class.isInstance(e));
@ -344,6 +383,27 @@ public class UserManagedPermissionServiceTest extends AbstractResourceServerTest
} catch (Exception e) {
assertEquals(404, HttpResponseException.class.cast(e.getCause()).getStatusCode());
}
// create a user based permission, where only selected users are allowed access to the resource.
permission = new UmaPermissionRepresentation();
permission.setName("Custom User-Managed Permission");
permission.setDescription("Specific users are allowed access to the resource");
permission.addScope("Scope A");
permission.addUser("alice");
protection.policy(resource.getId()).create(permission);
// alice should be able to access the resource with the updated permission.
authzResponse = getAuthzClient().authorization("alice", "password").authorize(request);
assertNotNull(authzResponse);
// kolo shouldn't be able to access the resource with the updated permission.
try {
authorization.authorize(request);
fail("User should not have permission to access the protected resource");
} catch(Exception e) {
assertTrue(AuthorizationDeniedException.class.isInstance(e));
}
}
@Test
@ -395,13 +455,13 @@ public class UserManagedPermissionServiceTest extends AbstractResourceServerTest
permission = protection.policy(resource.getId()).create(permission);
authzResponse = getAuthzClient().authorization("kolo", "password").authorize(request);
getAuthzClient().authorization("kolo", "password").authorize(request);
ticket.setGranted(false);
getAuthzClient().protection().permission().update(ticket);
authzResponse = getAuthzClient().authorization("kolo", "password").authorize(request);
getAuthzClient().authorization("kolo", "password").authorize(request);
permission = getAuthzClient().protection("marta", "password").policy(resource.getId()).findById(permission.getId());
@ -495,7 +555,7 @@ public class UserManagedPermissionServiceTest extends AbstractResourceServerTest
getAuthzClient().protection("alice", "password").policy(resource.getId()).create(new UmaPermissionRepresentation());
fail("Error expected");
} catch (Exception e) {
assertTrue(HttpResponseException.class.cast(e.getCause()).toString().contains("Only resource onwer can access policies for resource"));
assertTrue(HttpResponseException.class.cast(e.getCause()).toString().contains("Only resource owner can access policies for resource"));
}
}