[KEYCLOAK-7885] Add user policy support to the policy API
This commit is contained in:
parent
1912a8acf4
commit
0b95cdacb8
3 changed files with 152 additions and 24 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue