[KEYCLOAK-4755] - Client UI Tests
This commit is contained in:
parent
2913ee8e23
commit
fbcfcfa088
27 changed files with 965 additions and 158 deletions
|
@ -1,6 +1,6 @@
|
||||||
package org.keycloak.authorization.policy.provider.client;
|
package org.keycloak.authorization.policy.provider.client;
|
||||||
|
|
||||||
import static org.keycloak.authorization.policy.provider.client.ClientPolicyProviderFactory.getClients;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.keycloak.authorization.AuthorizationProvider;
|
import org.keycloak.authorization.AuthorizationProvider;
|
||||||
import org.keycloak.authorization.model.Policy;
|
import org.keycloak.authorization.model.Policy;
|
||||||
|
@ -9,27 +9,32 @@ import org.keycloak.authorization.policy.evaluation.EvaluationContext;
|
||||||
import org.keycloak.authorization.policy.provider.PolicyProvider;
|
import org.keycloak.authorization.policy.provider.PolicyProvider;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.representations.idm.authorization.ClientPolicyRepresentation;
|
||||||
|
|
||||||
public class ClientPolicyProvider implements PolicyProvider {
|
public class ClientPolicyProvider implements PolicyProvider {
|
||||||
|
|
||||||
|
private final Function<Policy, ClientPolicyRepresentation> representationFunction;
|
||||||
|
|
||||||
|
public ClientPolicyProvider(Function<Policy, ClientPolicyRepresentation> representationFunction) {
|
||||||
|
this.representationFunction = representationFunction;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void evaluate(Evaluation evaluation) {
|
public void evaluate(Evaluation evaluation) {
|
||||||
Policy policy = evaluation.getPolicy();
|
ClientPolicyRepresentation representation = representationFunction.apply(evaluation.getPolicy());
|
||||||
EvaluationContext context = evaluation.getContext();
|
|
||||||
String[] clients = getClients(policy);
|
|
||||||
AuthorizationProvider authorizationProvider = evaluation.getAuthorizationProvider();
|
AuthorizationProvider authorizationProvider = evaluation.getAuthorizationProvider();
|
||||||
RealmModel realm = authorizationProvider.getKeycloakSession().getContext().getRealm();
|
RealmModel realm = authorizationProvider.getKeycloakSession().getContext().getRealm();
|
||||||
|
EvaluationContext context = evaluation.getContext();
|
||||||
|
|
||||||
if (clients.length > 0) {
|
for (String client : representation.getClients()) {
|
||||||
for (String client : clients) {
|
|
||||||
ClientModel clientModel = realm.getClientById(client);
|
ClientModel clientModel = realm.getClientById(client);
|
||||||
|
|
||||||
if (context.getAttributes().containsValue("kc.client.id", clientModel.getClientId())) {
|
if (context.getAttributes().containsValue("kc.client.id", clientModel.getClientId())) {
|
||||||
evaluation.grant();
|
evaluation.grant();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
|
|
|
@ -2,14 +2,17 @@ package org.keycloak.authorization.policy.provider.client;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.authorization.AuthorizationProvider;
|
import org.keycloak.authorization.AuthorizationProvider;
|
||||||
import org.keycloak.authorization.model.Policy;
|
import org.keycloak.authorization.model.Policy;
|
||||||
import org.keycloak.authorization.model.ResourceServer;
|
import org.keycloak.authorization.model.ResourceServer;
|
||||||
import org.keycloak.authorization.policy.provider.PolicyProvider;
|
import org.keycloak.authorization.policy.provider.PolicyProvider;
|
||||||
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
|
|
||||||
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
|
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
|
||||||
import org.keycloak.authorization.store.PolicyStore;
|
import org.keycloak.authorization.store.PolicyStore;
|
||||||
import org.keycloak.authorization.store.ResourceServerStore;
|
import org.keycloak.authorization.store.ResourceServerStore;
|
||||||
|
@ -17,12 +20,15 @@ import org.keycloak.authorization.store.StoreFactory;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RealmModel.ClientRemovedEvent;
|
import org.keycloak.models.RealmModel.ClientRemovedEvent;
|
||||||
|
import org.keycloak.representations.idm.authorization.ClientPolicyRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
public class ClientPolicyProviderFactory implements PolicyProviderFactory {
|
public class ClientPolicyProviderFactory implements PolicyProviderFactory<ClientPolicyRepresentation> {
|
||||||
|
|
||||||
private ClientPolicyProvider provider = new ClientPolicyProvider();
|
private ClientPolicyProvider provider = new ClientPolicyProvider(policy -> toRepresentation(policy, new ClientPolicyRepresentation()));
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -40,8 +46,29 @@ public class ClientPolicyProviderFactory implements PolicyProviderFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer, AuthorizationProvider authorization) {
|
public ClientPolicyRepresentation toRepresentation(Policy policy, ClientPolicyRepresentation representation) {
|
||||||
return null;
|
representation.setClients(new HashSet<>(Arrays.asList(getClients(policy))));
|
||||||
|
return representation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<ClientPolicyRepresentation> getRepresentationType() {
|
||||||
|
return ClientPolicyRepresentation.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Policy policy, ClientPolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||||
|
updateClients(policy, representation.getClients(), authorization);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpdate(Policy policy, ClientPolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||||
|
updateClients(policy, representation.getClients(), authorization);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onImport(Policy policy, PolicyRepresentation representation, AuthorizationProvider authorization) {
|
||||||
|
updateClients(policy, new HashSet<>(Arrays.asList(getClients(policy))), authorization);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -101,7 +128,41 @@ public class ClientPolicyProviderFactory implements PolicyProviderFactory {
|
||||||
return "client";
|
return "client";
|
||||||
}
|
}
|
||||||
|
|
||||||
static String[] getClients(Policy policy) {
|
private void updateClients(Policy policy, Set<String> clients, AuthorizationProvider authorization) {
|
||||||
|
RealmModel realm = authorization.getKeycloakSession().getContext().getRealm();
|
||||||
|
|
||||||
|
if (clients == null || clients.isEmpty()) {
|
||||||
|
throw new RuntimeException("No client provided.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> updatedClients = new HashSet<>();
|
||||||
|
|
||||||
|
for (String id : clients) {
|
||||||
|
ClientModel client = realm.getClientByClientId(id);
|
||||||
|
|
||||||
|
if (client == null) {
|
||||||
|
client = realm.getClientById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client == null) {
|
||||||
|
throw new RuntimeException("Error while updating policy [" + policy.getName() + "]. Client [" + id + "] could not be found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedClients.add(client.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Map<String, String> config = policy.getConfig();
|
||||||
|
|
||||||
|
config.put("clients", JsonSerialization.writeValueAsString(updatedClients));
|
||||||
|
|
||||||
|
policy.setConfig(config);
|
||||||
|
} catch (IOException cause) {
|
||||||
|
throw new RuntimeException("Failed to serialize clients", cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] getClients(Policy policy) {
|
||||||
String clients = policy.getConfig().get("clients");
|
String clients = policy.getConfig().get("clients");
|
||||||
|
|
||||||
if (clients != null) {
|
if (clients != null) {
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.authorization.policy.provider.role;
|
package org.keycloak.authorization.policy.provider.role;
|
||||||
|
|
||||||
import static org.keycloak.authorization.policy.provider.role.RolePolicyProviderFactory.getRoles;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.keycloak.authorization.AuthorizationProvider;
|
import org.keycloak.authorization.AuthorizationProvider;
|
||||||
import org.keycloak.authorization.identity.Identity;
|
import org.keycloak.authorization.identity.Identity;
|
||||||
|
@ -29,29 +29,34 @@ import org.keycloak.authorization.policy.provider.PolicyProvider;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
|
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
*/
|
*/
|
||||||
public class RolePolicyProvider implements PolicyProvider {
|
public class RolePolicyProvider implements PolicyProvider {
|
||||||
|
|
||||||
|
private final Function<Policy, RolePolicyRepresentation> representationFunction;
|
||||||
|
|
||||||
|
public RolePolicyProvider(Function<Policy, RolePolicyRepresentation> representationFunction) {
|
||||||
|
this.representationFunction = representationFunction;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void evaluate(Evaluation evaluation) {
|
public void evaluate(Evaluation evaluation) {
|
||||||
Policy policy = evaluation.getPolicy();
|
Policy policy = evaluation.getPolicy();
|
||||||
Map<String, Object>[] roleIds = getRoles(policy);
|
Set<RolePolicyRepresentation.RoleDefinition> roleIds = representationFunction.apply(policy).getRoles();
|
||||||
AuthorizationProvider authorizationProvider = evaluation.getAuthorizationProvider();
|
AuthorizationProvider authorizationProvider = evaluation.getAuthorizationProvider();
|
||||||
RealmModel realm = authorizationProvider.getKeycloakSession().getContext().getRealm();
|
RealmModel realm = authorizationProvider.getKeycloakSession().getContext().getRealm();
|
||||||
|
|
||||||
if (roleIds.length > 0) {
|
|
||||||
Identity identity = evaluation.getContext().getIdentity();
|
Identity identity = evaluation.getContext().getIdentity();
|
||||||
|
|
||||||
for (Map<String, Object> current : roleIds) {
|
for (RolePolicyRepresentation.RoleDefinition roleDefinition : roleIds) {
|
||||||
RoleModel role = realm.getRoleById((String) current.get("id"));
|
RoleModel role = realm.getRoleById(roleDefinition.getId());
|
||||||
|
|
||||||
if (role != null) {
|
if (role != null) {
|
||||||
boolean hasRole = hasRole(identity, role, realm);
|
boolean hasRole = hasRole(identity, role, realm);
|
||||||
|
|
||||||
if (!hasRole && Boolean.valueOf(isRequired(current))) {
|
if (!hasRole && roleDefinition.isRequired()) {
|
||||||
evaluation.deny();
|
evaluation.deny();
|
||||||
return;
|
return;
|
||||||
} else if (hasRole) {
|
} else if (hasRole) {
|
||||||
|
@ -60,11 +65,6 @@ public class RolePolicyProvider implements PolicyProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isRequired(Map<String, Object> current) {
|
|
||||||
return (boolean) current.getOrDefault("required", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasRole(Identity identity, RoleModel role, RealmModel realm) {
|
private boolean hasRole(Identity identity, RoleModel role, RealmModel realm) {
|
||||||
String roleName = role.getName();
|
String roleName = role.getName();
|
||||||
|
|
|
@ -23,7 +23,6 @@ import org.keycloak.authorization.AuthorizationProvider;
|
||||||
import org.keycloak.authorization.model.Policy;
|
import org.keycloak.authorization.model.Policy;
|
||||||
import org.keycloak.authorization.model.ResourceServer;
|
import org.keycloak.authorization.model.ResourceServer;
|
||||||
import org.keycloak.authorization.policy.provider.PolicyProvider;
|
import org.keycloak.authorization.policy.provider.PolicyProvider;
|
||||||
import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
|
|
||||||
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
|
import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
|
||||||
import org.keycloak.authorization.store.PolicyStore;
|
import org.keycloak.authorization.store.PolicyStore;
|
||||||
import org.keycloak.authorization.store.ResourceServerStore;
|
import org.keycloak.authorization.store.ResourceServerStore;
|
||||||
|
@ -53,7 +52,7 @@ import java.util.Set;
|
||||||
*/
|
*/
|
||||||
public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePolicyRepresentation> {
|
public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePolicyRepresentation> {
|
||||||
|
|
||||||
private RolePolicyProvider provider = new RolePolicyProvider();
|
private RolePolicyProvider provider = new RolePolicyProvider(policy -> toRepresentation(policy, new RolePolicyRepresentation()));
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -70,20 +69,15 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePoli
|
||||||
return provider;
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer, AuthorizationProvider authorization) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PolicyProvider create(KeycloakSession session) {
|
public PolicyProvider create(KeycloakSession session) {
|
||||||
return new RolePolicyProvider();
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RolePolicyRepresentation toRepresentation(Policy policy, RolePolicyRepresentation representation) {
|
public RolePolicyRepresentation toRepresentation(Policy policy, RolePolicyRepresentation representation) {
|
||||||
try {
|
try {
|
||||||
representation.setRoles(JsonSerialization.readValue(policy.getConfig().get("roles"), Set.class));
|
representation.setRoles(new HashSet<>(Arrays.asList(JsonSerialization.readValue(policy.getConfig().get("roles"), RolePolicyRepresentation.RoleDefinition[].class))));
|
||||||
} catch (IOException cause) {
|
} catch (IOException cause) {
|
||||||
throw new RuntimeException("Failed to deserialize roles", cause);
|
throw new RuntimeException("Failed to deserialize roles", cause);
|
||||||
}
|
}
|
||||||
|
@ -119,7 +113,6 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePoli
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateRoles(Policy policy, AuthorizationProvider authorization, Set<RolePolicyRepresentation.RoleDefinition> roles) {
|
private void updateRoles(Policy policy, AuthorizationProvider authorization, Set<RolePolicyRepresentation.RoleDefinition> roles) {
|
||||||
try {
|
|
||||||
RealmModel realm = authorization.getRealm();
|
RealmModel realm = authorization.getRealm();
|
||||||
Set<RolePolicyRepresentation.RoleDefinition> updatedRoles = new HashSet<>();
|
Set<RolePolicyRepresentation.RoleDefinition> updatedRoles = new HashSet<>();
|
||||||
|
|
||||||
|
@ -160,24 +153,23 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePoli
|
||||||
}
|
}
|
||||||
|
|
||||||
if (role == null) {
|
if (role == null) {
|
||||||
throw new RuntimeException("Error while importing configuration. Role [" + roleName + "] could not be found.");
|
throw new RuntimeException("Error while updating policy [" + policy.getName() + "]. Role [" + roleName + "] could not be found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
definition.setId(role.getId());
|
definition.setId(role.getId());
|
||||||
|
|
||||||
updatedRoles.add(definition);
|
updatedRoles.add(definition);
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("Error while updating policy [" + policy.getName() + "].", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
Map<String, String> config = policy.getConfig();
|
Map<String, String> config = policy.getConfig();
|
||||||
|
|
||||||
config.put("roles", JsonSerialization.writeValueAsString(updatedRoles));
|
config.put("roles", JsonSerialization.writeValueAsString(updatedRoles));
|
||||||
|
|
||||||
policy.setConfig(config);
|
policy.setConfig(config);
|
||||||
} catch (IOException cause) {
|
} catch (IOException cause) {
|
||||||
throw new RuntimeException("Failed to deserialize roles", cause);
|
throw new RuntimeException("Failed to serialize roles", cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +245,7 @@ public class RolePolicyProviderFactory implements PolicyProviderFactory<RolePoli
|
||||||
return "role";
|
return "role";
|
||||||
}
|
}
|
||||||
|
|
||||||
static Map<String, Object>[] getRoles(Policy policy) {
|
private Map<String, Object>[] getRoles(Policy policy) {
|
||||||
String roles = policy.getConfig().get("roles");
|
String roles = policy.getConfig().get("roles");
|
||||||
|
|
||||||
if (roles != null) {
|
if (roles != null) {
|
||||||
|
|
|
@ -17,33 +17,37 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.authorization.policy.provider.user;
|
package org.keycloak.authorization.policy.provider.user;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.keycloak.authorization.model.Policy;
|
import org.keycloak.authorization.model.Policy;
|
||||||
import org.keycloak.authorization.policy.evaluation.Evaluation;
|
import org.keycloak.authorization.policy.evaluation.Evaluation;
|
||||||
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
|
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
|
||||||
import org.keycloak.authorization.policy.provider.PolicyProvider;
|
import org.keycloak.authorization.policy.provider.PolicyProvider;
|
||||||
|
import org.keycloak.representations.idm.authorization.UserPolicyRepresentation;
|
||||||
import static org.keycloak.authorization.policy.provider.user.UserPolicyProviderFactory.getUsers;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
*/
|
*/
|
||||||
public class UserPolicyProvider implements PolicyProvider {
|
public class UserPolicyProvider implements PolicyProvider {
|
||||||
|
|
||||||
|
private final Function<Policy, UserPolicyRepresentation> representationFunction;
|
||||||
|
|
||||||
|
public UserPolicyProvider(Function<Policy, UserPolicyRepresentation> representationFunction) {
|
||||||
|
this.representationFunction = representationFunction;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void evaluate(Evaluation evaluation) {
|
public void evaluate(Evaluation evaluation) {
|
||||||
Policy policy = evaluation.getPolicy();
|
|
||||||
EvaluationContext context = evaluation.getContext();
|
EvaluationContext context = evaluation.getContext();
|
||||||
String[] userIds = getUsers(policy);
|
UserPolicyRepresentation representation = representationFunction.apply(evaluation.getPolicy());
|
||||||
|
|
||||||
if (userIds.length > 0) {
|
for (String userId : representation.getUsers()) {
|
||||||
for (String userId : userIds) {
|
|
||||||
if (context.getIdentity().getId().equals(userId)) {
|
if (context.getIdentity().getId().equals(userId)) {
|
||||||
evaluation.grant();
|
evaluation.grant();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.authorization.AuthorizationProvider;
|
import org.keycloak.authorization.AuthorizationProvider;
|
||||||
|
@ -49,7 +50,7 @@ import org.keycloak.util.JsonSerialization;
|
||||||
*/
|
*/
|
||||||
public class UserPolicyProviderFactory implements PolicyProviderFactory<UserPolicyRepresentation> {
|
public class UserPolicyProviderFactory implements PolicyProviderFactory<UserPolicyRepresentation> {
|
||||||
|
|
||||||
private UserPolicyProvider provider = new UserPolicyProvider();
|
private UserPolicyProvider provider = new UserPolicyProvider((Function<Policy, UserPolicyRepresentation>) policy -> toRepresentation(policy, new UserPolicyRepresentation()));
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -110,14 +111,12 @@ public class UserPolicyProviderFactory implements PolicyProviderFactory<UserPoli
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateUsers(Policy policy, AuthorizationProvider authorization, Set<String> users) {
|
private void updateUsers(Policy policy, AuthorizationProvider authorization, Set<String> users) {
|
||||||
try {
|
|
||||||
KeycloakSession session = authorization.getKeycloakSession();
|
KeycloakSession session = authorization.getKeycloakSession();
|
||||||
RealmModel realm = authorization.getRealm();
|
RealmModel realm = authorization.getRealm();
|
||||||
UserProvider userProvider = session.users();
|
UserProvider userProvider = session.users();
|
||||||
Set<String> updatedUsers = new HashSet<>();
|
Set<String> updatedUsers = new HashSet<>();
|
||||||
|
|
||||||
if (users != null) {
|
if (users != null) {
|
||||||
try {
|
|
||||||
for (String userId : users) {
|
for (String userId : users) {
|
||||||
UserModel user = null;
|
UserModel user = null;
|
||||||
|
|
||||||
|
@ -131,21 +130,21 @@ public class UserPolicyProviderFactory implements PolicyProviderFactory<UserPoli
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
throw new RuntimeException("Error while importing configuration. User [" + userId + "] could not be found.");
|
throw new RuntimeException("Error while updating policy [" + policy.getName() + "]. User [" + userId + "] could not be found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
updatedUsers.add(user.getId());
|
updatedUsers.add(user.getId());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("Error while updating policy [" + policy.getName() + "].", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
Map<String, String> config = policy.getConfig();
|
Map<String, String> config = policy.getConfig();
|
||||||
|
|
||||||
config.put("users", JsonSerialization.writeValueAsString(updatedUsers));
|
config.put("users", JsonSerialization.writeValueAsString(updatedUsers));
|
||||||
|
|
||||||
policy.setConfig(config);
|
policy.setConfig(config);
|
||||||
} catch (IOException cause) {
|
} catch (IOException cause) {
|
||||||
throw new RuntimeException("Failed to deserialize roles", cause);
|
throw new RuntimeException("Failed to serialize users", cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.representations.idm.authorization;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
public class ClientPolicyRepresentation extends AbstractPolicyRepresentation {
|
||||||
|
|
||||||
|
private Set<String> clients;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return "client";
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getClients() {
|
||||||
|
return clients;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClients(Set<String> clients) {
|
||||||
|
this.clients = clients;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addClient(String... id) {
|
||||||
|
if (this.clients == null) {
|
||||||
|
this.clients = new HashSet<>();
|
||||||
|
}
|
||||||
|
this.clients.addAll(Arrays.asList(id));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.admin.client.resource;
|
||||||
|
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||||
|
import org.keycloak.representations.idm.authorization.ClientPolicyRepresentation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
public interface ClientPoliciesResource {
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
Response create(ClientPolicyRepresentation representation);
|
||||||
|
|
||||||
|
@Path("{id}")
|
||||||
|
ClientPolicyResource findById(@PathParam("id") String id);
|
||||||
|
|
||||||
|
@Path("/search")
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@NoCache
|
||||||
|
ClientPolicyRepresentation findByName(@QueryParam("name") String name);
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.admin.client.resource;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.DELETE;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.PUT;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||||
|
import org.keycloak.representations.idm.authorization.ClientPolicyRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
public interface ClientPolicyResource {
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@NoCache
|
||||||
|
ClientPolicyRepresentation toRepresentation();
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
void update(ClientPolicyRepresentation representation);
|
||||||
|
|
||||||
|
@DELETE
|
||||||
|
void remove();
|
||||||
|
|
||||||
|
@Path("/associatedPolicies")
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@NoCache
|
||||||
|
List<PolicyRepresentation> associatedPolicies();
|
||||||
|
|
||||||
|
@Path("/dependentPolicies")
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@NoCache
|
||||||
|
List<PolicyRepresentation> dependentPolicies();
|
||||||
|
|
||||||
|
@Path("/resources")
|
||||||
|
@GET
|
||||||
|
@Produces("application/json")
|
||||||
|
@NoCache
|
||||||
|
List<ResourceRepresentation> resources();
|
||||||
|
|
||||||
|
}
|
|
@ -70,10 +70,10 @@ public interface PoliciesResource {
|
||||||
PolicyEvaluationResponse evaluate(PolicyEvaluationRequest evaluationRequest);
|
PolicyEvaluationResponse evaluate(PolicyEvaluationRequest evaluationRequest);
|
||||||
|
|
||||||
@Path("role")
|
@Path("role")
|
||||||
RolePoliciesResource roles();
|
RolePoliciesResource role();
|
||||||
|
|
||||||
@Path("user")
|
@Path("user")
|
||||||
UserPoliciesResource users();
|
UserPoliciesResource user();
|
||||||
|
|
||||||
@Path("js")
|
@Path("js")
|
||||||
JSPoliciesResource js();
|
JSPoliciesResource js();
|
||||||
|
@ -86,4 +86,7 @@ public interface PoliciesResource {
|
||||||
|
|
||||||
@Path("rules")
|
@Path("rules")
|
||||||
RulePoliciesResource rule();
|
RulePoliciesResource rule();
|
||||||
|
|
||||||
|
@Path("client")
|
||||||
|
ClientPoliciesResource client();
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,7 @@ public abstract class AbstractServletAuthzAdapterTest extends AbstractExampleAda
|
||||||
return getClientResource(RESOURCE_SERVER_ID).authorization();
|
return getClientResource(RESOURCE_SERVER_ID).authorization();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClientResource getClientResource(String clientId) {
|
protected ClientResource getClientResource(String clientId) {
|
||||||
ClientsResource clients = this.realmsResouce().realm(REALM_NAME).clients();
|
ClientsResource clients = this.realmsResouce().realm(REALM_NAME).clients();
|
||||||
ClientRepresentation resourceServer = clients.findByClientId(clientId).get(0);
|
ClientRepresentation resourceServer = clients.findByClientId(clientId).get(0);
|
||||||
return clients.get(resourceServer.getId());
|
return clients.get(resourceServer.getId());
|
||||||
|
@ -199,7 +199,7 @@ public abstract class AbstractServletAuthzAdapterTest extends AbstractExampleAda
|
||||||
|
|
||||||
assertFalse(policy.getUsers().isEmpty());
|
assertFalse(policy.getUsers().isEmpty());
|
||||||
|
|
||||||
getAuthorizationResource().policies().users().create(policy);
|
getAuthorizationResource().policies().user().create(policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected interface ExceptionRunnable {
|
protected interface ExceptionRunnable {
|
||||||
|
|
|
@ -26,15 +26,19 @@ import java.util.List;
|
||||||
import org.jboss.arquillian.container.test.api.Deployment;
|
import org.jboss.arquillian.container.test.api.Deployment;
|
||||||
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.admin.client.resource.ClientsResource;
|
import org.keycloak.admin.client.resource.ClientPoliciesResource;
|
||||||
import org.keycloak.admin.client.resource.RealmResource;
|
import org.keycloak.admin.client.resource.RealmResource;
|
||||||
import org.keycloak.admin.client.resource.ResourcesResource;
|
import org.keycloak.admin.client.resource.ResourcesResource;
|
||||||
|
import org.keycloak.admin.client.resource.RolePoliciesResource;
|
||||||
|
import org.keycloak.admin.client.resource.RoleScopeResource;
|
||||||
|
import org.keycloak.admin.client.resource.RolesResource;
|
||||||
import org.keycloak.admin.client.resource.UserResource;
|
import org.keycloak.admin.client.resource.UserResource;
|
||||||
import org.keycloak.admin.client.resource.UsersResource;
|
import org.keycloak.admin.client.resource.UsersResource;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
|
||||||
import org.keycloak.representations.idm.RoleRepresentation;
|
import org.keycloak.representations.idm.RoleRepresentation;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.ClientPolicyRepresentation;
|
||||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
|
||||||
import org.keycloak.testsuite.util.WaitUtils;
|
import org.keycloak.testsuite.util.WaitUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -205,4 +209,99 @@ public abstract class AbstractServletAuthzFunctionalAdapterTest extends Abstract
|
||||||
assertTrue(hasText("This is public resource that should be accessible without login."));
|
assertTrue(hasText("This is public resource that should be accessible without login."));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRequiredRole() throws Exception {
|
||||||
|
performTests(() -> {
|
||||||
|
login("jdoe", "jdoe");
|
||||||
|
navigateToUserPremiumPage();
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
RolesResource rolesResource = getClientResource(RESOURCE_SERVER_ID).roles();
|
||||||
|
|
||||||
|
rolesResource.create(new RoleRepresentation("required-role", "", false));
|
||||||
|
|
||||||
|
RolePolicyRepresentation policy = new RolePolicyRepresentation();
|
||||||
|
|
||||||
|
policy.setName("Required Role Policy");
|
||||||
|
policy.addRole("user_premium", false);
|
||||||
|
policy.addRole("required-role", false);
|
||||||
|
|
||||||
|
RolePoliciesResource rolePolicy = getAuthorizationResource().policies().role();
|
||||||
|
|
||||||
|
rolePolicy.create(policy);
|
||||||
|
policy = rolePolicy.findByName(policy.getName());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Premium Resource Permission", policy.getName());
|
||||||
|
|
||||||
|
login("jdoe", "jdoe");
|
||||||
|
navigateToUserPremiumPage();
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
policy.getRoles().clear();
|
||||||
|
policy.addRole("user_premium", false);
|
||||||
|
policy.addRole("required-role", true);
|
||||||
|
|
||||||
|
rolePolicy.findById(policy.getId()).update(policy);
|
||||||
|
|
||||||
|
login("jdoe", "jdoe");
|
||||||
|
navigateToUserPremiumPage();
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
|
||||||
|
UsersResource users = realmsResouce().realm(REALM_NAME).users();
|
||||||
|
UserRepresentation user = users.search("jdoe").get(0);
|
||||||
|
|
||||||
|
RoleScopeResource roleScopeResource = users.get(user.getId()).roles().clientLevel(getClientResource(RESOURCE_SERVER_ID).toRepresentation().getId());
|
||||||
|
RoleRepresentation requiredRole = rolesResource.get("required-role").toRepresentation();
|
||||||
|
roleScopeResource.add(Arrays.asList(requiredRole));
|
||||||
|
|
||||||
|
login("jdoe", "jdoe");
|
||||||
|
navigateToUserPremiumPage();
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
policy.getRoles().clear();
|
||||||
|
policy.addRole("user_premium", false);
|
||||||
|
policy.addRole("required-role", false);
|
||||||
|
|
||||||
|
rolePolicy.findById(policy.getId()).update(policy);
|
||||||
|
|
||||||
|
login("jdoe", "jdoe");
|
||||||
|
navigateToUserPremiumPage();
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
roleScopeResource.remove(Arrays.asList(requiredRole));
|
||||||
|
|
||||||
|
login("jdoe", "jdoe");
|
||||||
|
navigateToUserPremiumPage();
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnlySpecificClient() throws Exception {
|
||||||
|
performTests(() -> {
|
||||||
|
login("jdoe", "jdoe");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
|
||||||
|
ClientPolicyRepresentation policy = new ClientPolicyRepresentation();
|
||||||
|
|
||||||
|
policy.setName("Only Client Policy");
|
||||||
|
policy.addClient("admin-cli");
|
||||||
|
|
||||||
|
ClientPoliciesResource policyResource = getAuthorizationResource().policies().client();
|
||||||
|
policyResource.create(policy);
|
||||||
|
policy = policyResource.findByName(policy.getName());
|
||||||
|
|
||||||
|
updatePermissionPolicies("Protected Resource Permission", policy.getName());
|
||||||
|
|
||||||
|
login("jdoe", "jdoe");
|
||||||
|
assertTrue(wasDenied());
|
||||||
|
|
||||||
|
policy.addClient("servlet-authz-app");
|
||||||
|
policyResource.findById(policy.getId()).update(policy);
|
||||||
|
|
||||||
|
login("jdoe", "jdoe");
|
||||||
|
assertFalse(wasDenied());
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,7 +147,7 @@ public abstract class AbstractPolicyManagementTest extends AbstractKeycloakTest
|
||||||
representation.setName(name);
|
representation.setName(name);
|
||||||
representation.addUser(userId);
|
representation.addUser(userId);
|
||||||
|
|
||||||
client.authorization().policies().users().create(representation);
|
client.authorization().policies().user().create(representation);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ClientResource getClient() {
|
protected ClientResource getClient() {
|
||||||
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.testsuite.admin.client.authorization;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.ws.rs.NotFoundException;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.admin.client.resource.AuthorizationResource;
|
||||||
|
import org.keycloak.admin.client.resource.ClientPoliciesResource;
|
||||||
|
import org.keycloak.admin.client.resource.ClientPolicyResource;
|
||||||
|
import org.keycloak.admin.client.resource.PolicyResource;
|
||||||
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.ClientPolicyRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.DecisionStrategy;
|
||||||
|
import org.keycloak.representations.idm.authorization.Logic;
|
||||||
|
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||||
|
import org.keycloak.testsuite.util.ClientBuilder;
|
||||||
|
import org.keycloak.testsuite.util.RealmBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
public class ClientPolicyManagementTest extends AbstractPolicyManagementTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RealmBuilder createTestRealm() {
|
||||||
|
return super.createTestRealm()
|
||||||
|
.client(ClientBuilder.create().clientId("Client A"))
|
||||||
|
.client(ClientBuilder.create().clientId("Client B"))
|
||||||
|
.client(ClientBuilder.create().clientId("Client C"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreate() {
|
||||||
|
AuthorizationResource authorization = getClient().authorization();
|
||||||
|
ClientPolicyRepresentation representation = new ClientPolicyRepresentation();
|
||||||
|
|
||||||
|
representation.setName("Realm Client Policy");
|
||||||
|
representation.setDescription("description");
|
||||||
|
representation.setDecisionStrategy(DecisionStrategy.CONSENSUS);
|
||||||
|
representation.setLogic(Logic.NEGATIVE);
|
||||||
|
representation.addClient("Client A");
|
||||||
|
representation.addClient("Client B");
|
||||||
|
|
||||||
|
assertCreated(authorization, representation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdate() {
|
||||||
|
AuthorizationResource authorization = getClient().authorization();
|
||||||
|
ClientPolicyRepresentation representation = new ClientPolicyRepresentation();
|
||||||
|
|
||||||
|
representation.setName("Update Test Client Policy");
|
||||||
|
representation.setDescription("description");
|
||||||
|
representation.setDecisionStrategy(DecisionStrategy.CONSENSUS);
|
||||||
|
representation.setLogic(Logic.NEGATIVE);
|
||||||
|
representation.addClient("Client A");
|
||||||
|
representation.addClient("Client B");
|
||||||
|
representation.addClient("Client C");
|
||||||
|
|
||||||
|
assertCreated(authorization, representation);
|
||||||
|
|
||||||
|
representation.setName("changed");
|
||||||
|
representation.setDescription("changed");
|
||||||
|
representation.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
|
||||||
|
representation.setLogic(Logic.POSITIVE);
|
||||||
|
representation.setClients(representation.getClients().stream().filter(userName -> !userName.equals("Client A")).collect(Collectors.toSet()));
|
||||||
|
|
||||||
|
ClientPoliciesResource policies = authorization.policies().client();
|
||||||
|
ClientPolicyResource permission = policies.findById(representation.getId());
|
||||||
|
|
||||||
|
permission.update(representation);
|
||||||
|
assertRepresentation(representation, permission);
|
||||||
|
|
||||||
|
representation.setClients(representation.getClients().stream().filter(userName -> !userName.equals("Client C")).collect(Collectors.toSet()));
|
||||||
|
|
||||||
|
permission.update(representation);
|
||||||
|
assertRepresentation(representation, permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDelete() {
|
||||||
|
AuthorizationResource authorization = getClient().authorization();
|
||||||
|
ClientPolicyRepresentation representation = new ClientPolicyRepresentation();
|
||||||
|
|
||||||
|
representation.setName("Test Delete Permission");
|
||||||
|
representation.addClient("Client A");
|
||||||
|
|
||||||
|
ClientPoliciesResource policies = authorization.policies().client();
|
||||||
|
Response response = policies.create(representation);
|
||||||
|
ClientPolicyRepresentation created = response.readEntity(ClientPolicyRepresentation.class);
|
||||||
|
|
||||||
|
policies.findById(created.getId()).remove();
|
||||||
|
|
||||||
|
ClientPolicyResource removed = policies.findById(created.getId());
|
||||||
|
|
||||||
|
try {
|
||||||
|
removed.toRepresentation();
|
||||||
|
fail("Permission not removed");
|
||||||
|
} catch (NotFoundException ignore) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGenericConfig() {
|
||||||
|
AuthorizationResource authorization = getClient().authorization();
|
||||||
|
ClientPolicyRepresentation representation = new ClientPolicyRepresentation();
|
||||||
|
|
||||||
|
representation.setName("Test Generic Config Permission");
|
||||||
|
representation.addClient("Client A");
|
||||||
|
|
||||||
|
ClientPoliciesResource policies = authorization.policies().client();
|
||||||
|
Response response = policies.create(representation);
|
||||||
|
ClientPolicyRepresentation created = response.readEntity(ClientPolicyRepresentation.class);
|
||||||
|
|
||||||
|
PolicyResource policy = authorization.policies().policy(created.getId());
|
||||||
|
PolicyRepresentation genericConfig = policy.toRepresentation();
|
||||||
|
|
||||||
|
assertNotNull(genericConfig.getConfig());
|
||||||
|
assertNotNull(genericConfig.getConfig().get("clients"));
|
||||||
|
|
||||||
|
ClientRepresentation user = getRealm().clients().findByClientId("Client A").get(0);
|
||||||
|
|
||||||
|
assertTrue(genericConfig.getConfig().get("clients").contains(user.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertCreated(AuthorizationResource authorization, ClientPolicyRepresentation representation) {
|
||||||
|
ClientPoliciesResource permissions = authorization.policies().client();
|
||||||
|
Response response = permissions.create(representation);
|
||||||
|
ClientPolicyRepresentation created = response.readEntity(ClientPolicyRepresentation.class);
|
||||||
|
ClientPolicyResource permission = permissions.findById(created.getId());
|
||||||
|
assertRepresentation(representation, permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertRepresentation(ClientPolicyRepresentation representation, ClientPolicyResource permission) {
|
||||||
|
ClientPolicyRepresentation actual = permission.toRepresentation();
|
||||||
|
assertRepresentation(representation, actual, () -> permission.resources(), () -> Collections.emptyList(), () -> permission.associatedPolicies());
|
||||||
|
assertEquals(representation.getClients().size(), actual.getClients().size());
|
||||||
|
assertEquals(0, actual.getClients().stream().filter(clientId -> !representation.getClients().stream()
|
||||||
|
.filter(userName -> getClientName(clientId).equalsIgnoreCase(userName))
|
||||||
|
.findFirst().isPresent())
|
||||||
|
.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getClientName(String id) {
|
||||||
|
return getRealm().clients().get(id).toRepresentation().getClientId();
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ import org.keycloak.admin.client.resource.ClientResource;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.representations.idm.RoleRepresentation;
|
import org.keycloak.representations.idm.RoleRepresentation;
|
||||||
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
|
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
|
||||||
|
import org.keycloak.testsuite.util.UserBuilder;
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,6 +44,8 @@ public class ImportAuthorizationSettingsTest extends AbstractAuthorizationTest {
|
||||||
RoleRepresentation role = new RoleRepresentation();
|
RoleRepresentation role = new RoleRepresentation();
|
||||||
role.setName("admin");
|
role.setName("admin");
|
||||||
clientResource.roles().create(role);
|
clientResource.roles().create(role);
|
||||||
|
|
||||||
|
testRealmResource().users().create(UserBuilder.create().username("alice").build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
@ -72,6 +75,6 @@ public class ImportAuthorizationSettingsTest extends AbstractAuthorizationTest {
|
||||||
|
|
||||||
authorizationResource.importSettings(toImport);
|
authorizationResource.importSettings(toImport);
|
||||||
|
|
||||||
assertEquals(13, authorizationResource.policies().policies().size());
|
assertEquals(15, authorizationResource.policies().policies().size());
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -119,7 +119,7 @@ public class RolePolicyManagementTest extends AbstractPolicyManagementTest {
|
||||||
representation.setLogic(Logic.POSITIVE);
|
representation.setLogic(Logic.POSITIVE);
|
||||||
representation.setRoles(representation.getRoles().stream().filter(roleDefinition -> !roleDefinition.getId().equals("Resource A")).collect(Collectors.toSet()));
|
representation.setRoles(representation.getRoles().stream().filter(roleDefinition -> !roleDefinition.getId().equals("Resource A")).collect(Collectors.toSet()));
|
||||||
|
|
||||||
RolePoliciesResource policies = authorization.policies().roles();
|
RolePoliciesResource policies = authorization.policies().role();
|
||||||
RolePolicyResource permission = policies.findById(representation.getId());
|
RolePolicyResource permission = policies.findById(representation.getId());
|
||||||
|
|
||||||
permission.update(representation);
|
permission.update(representation);
|
||||||
|
@ -146,7 +146,7 @@ public class RolePolicyManagementTest extends AbstractPolicyManagementTest {
|
||||||
representation.setName("Test Delete Permission");
|
representation.setName("Test Delete Permission");
|
||||||
representation.addRole("Role A", false);
|
representation.addRole("Role A", false);
|
||||||
|
|
||||||
RolePoliciesResource policies = authorization.policies().roles();
|
RolePoliciesResource policies = authorization.policies().role();
|
||||||
Response response = policies.create(representation);
|
Response response = policies.create(representation);
|
||||||
RolePolicyRepresentation created = response.readEntity(RolePolicyRepresentation.class);
|
RolePolicyRepresentation created = response.readEntity(RolePolicyRepresentation.class);
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ public class RolePolicyManagementTest extends AbstractPolicyManagementTest {
|
||||||
representation.setName("Test Generic Config Permission");
|
representation.setName("Test Generic Config Permission");
|
||||||
representation.addRole("Role A", false);
|
representation.addRole("Role A", false);
|
||||||
|
|
||||||
RolePoliciesResource policies = authorization.policies().roles();
|
RolePoliciesResource policies = authorization.policies().role();
|
||||||
Response response = policies.create(representation);
|
Response response = policies.create(representation);
|
||||||
RolePolicyRepresentation created = response.readEntity(RolePolicyRepresentation.class);
|
RolePolicyRepresentation created = response.readEntity(RolePolicyRepresentation.class);
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ public class RolePolicyManagementTest extends AbstractPolicyManagementTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertCreated(AuthorizationResource authorization, RolePolicyRepresentation representation) {
|
private void assertCreated(AuthorizationResource authorization, RolePolicyRepresentation representation) {
|
||||||
RolePoliciesResource permissions = authorization.policies().roles();
|
RolePoliciesResource permissions = authorization.policies().role();
|
||||||
Response response = permissions.create(representation);
|
Response response = permissions.create(representation);
|
||||||
RolePolicyRepresentation created = response.readEntity(RolePolicyRepresentation.class);
|
RolePolicyRepresentation created = response.readEntity(RolePolicyRepresentation.class);
|
||||||
RolePolicyResource permission = permissions.findById(created.getId());
|
RolePolicyResource permission = permissions.findById(created.getId());
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class UserPolicyManagementTest extends AbstractPolicyManagementTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateUserPolicy() {
|
public void testCreate() {
|
||||||
AuthorizationResource authorization = getClient().authorization();
|
AuthorizationResource authorization = getClient().authorization();
|
||||||
UserPolicyRepresentation representation = new UserPolicyRepresentation();
|
UserPolicyRepresentation representation = new UserPolicyRepresentation();
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ public class UserPolicyManagementTest extends AbstractPolicyManagementTest {
|
||||||
representation.setLogic(Logic.POSITIVE);
|
representation.setLogic(Logic.POSITIVE);
|
||||||
representation.setUsers(representation.getUsers().stream().filter(userName -> !userName.equals("User A")).collect(Collectors.toSet()));
|
representation.setUsers(representation.getUsers().stream().filter(userName -> !userName.equals("User A")).collect(Collectors.toSet()));
|
||||||
|
|
||||||
UserPoliciesResource policies = authorization.policies().users();
|
UserPoliciesResource policies = authorization.policies().user();
|
||||||
UserPolicyResource permission = policies.findById(representation.getId());
|
UserPolicyResource permission = policies.findById(representation.getId());
|
||||||
|
|
||||||
permission.update(representation);
|
permission.update(representation);
|
||||||
|
@ -109,7 +109,7 @@ public class UserPolicyManagementTest extends AbstractPolicyManagementTest {
|
||||||
representation.setName("Test Delete Permission");
|
representation.setName("Test Delete Permission");
|
||||||
representation.addUser("User A");
|
representation.addUser("User A");
|
||||||
|
|
||||||
UserPoliciesResource policies = authorization.policies().users();
|
UserPoliciesResource policies = authorization.policies().user();
|
||||||
Response response = policies.create(representation);
|
Response response = policies.create(representation);
|
||||||
UserPolicyRepresentation created = response.readEntity(UserPolicyRepresentation.class);
|
UserPolicyRepresentation created = response.readEntity(UserPolicyRepresentation.class);
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ public class UserPolicyManagementTest extends AbstractPolicyManagementTest {
|
||||||
representation.setName("Test Generic Config Permission");
|
representation.setName("Test Generic Config Permission");
|
||||||
representation.addUser("User A");
|
representation.addUser("User A");
|
||||||
|
|
||||||
UserPoliciesResource policies = authorization.policies().users();
|
UserPoliciesResource policies = authorization.policies().user();
|
||||||
Response response = policies.create(representation);
|
Response response = policies.create(representation);
|
||||||
UserPolicyRepresentation created = response.readEntity(UserPolicyRepresentation.class);
|
UserPolicyRepresentation created = response.readEntity(UserPolicyRepresentation.class);
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ public class UserPolicyManagementTest extends AbstractPolicyManagementTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertCreated(AuthorizationResource authorization, UserPolicyRepresentation representation) {
|
private void assertCreated(AuthorizationResource authorization, UserPolicyRepresentation representation) {
|
||||||
UserPoliciesResource permissions = authorization.policies().users();
|
UserPoliciesResource permissions = authorization.policies().user();
|
||||||
Response response = permissions.create(representation);
|
Response response = permissions.create(representation);
|
||||||
UserPolicyRepresentation created = response.readEntity(UserPolicyRepresentation.class);
|
UserPolicyRepresentation created = response.readEntity(UserPolicyRepresentation.class);
|
||||||
UserPolicyResource permission = permissions.findById(created.getId());
|
UserPolicyResource permission = permissions.findById(created.getId());
|
||||||
|
|
|
@ -161,6 +161,20 @@
|
||||||
"config": {
|
"config": {
|
||||||
"code": "var context = $evaluation.getContext();\nvar identity = context.getIdentity();\nvar attributes = identity.getAttributes();\nvar email = attributes.getValue('email').asString(0);\n\nif (identity.hasRole('admin') || email.endsWith('@keycloak.org')) {\n $evaluation.grant();\n}"
|
"code": "var context = $evaluation.getContext();\nvar identity = context.getIdentity();\nvar attributes = identity.getAttributes();\nvar email = attributes.getValue('email').asString(0);\n\nif (identity.hasRole('admin') || email.endsWith('@keycloak.org')) {\n $evaluation.grant();\n}"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Test Client Policy",
|
||||||
|
"type": "client",
|
||||||
|
"config": {
|
||||||
|
"clients": "[\"admin-cli\"]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Test User Policy",
|
||||||
|
"type": "user",
|
||||||
|
"config": {
|
||||||
|
"users": "[\"alice\"]"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.testsuite.console.page.clients.authorization.policy;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
|
import org.keycloak.representations.idm.authorization.ClientPolicyRepresentation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
public class ClientPolicy implements PolicyTypeUI {
|
||||||
|
|
||||||
|
@Page
|
||||||
|
private ClientPolicyForm form;
|
||||||
|
|
||||||
|
public ClientPolicyForm form() {
|
||||||
|
return form;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientPolicyRepresentation toRepresentation() {
|
||||||
|
return form.toRepresentation();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(ClientPolicyRepresentation expected) {
|
||||||
|
form().populate(expected);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.testsuite.console.page.clients.authorization.policy;
|
||||||
|
|
||||||
|
import static org.openqa.selenium.By.tagName;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.keycloak.representations.idm.authorization.ClientPolicyRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.Logic;
|
||||||
|
import org.keycloak.testsuite.console.page.fragment.MultipleStringSelect2;
|
||||||
|
import org.keycloak.testsuite.page.Form;
|
||||||
|
import org.openqa.selenium.By;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
import org.openqa.selenium.support.ui.Select;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
public class ClientPolicyForm extends Form {
|
||||||
|
|
||||||
|
@FindBy(id = "name")
|
||||||
|
private WebElement name;
|
||||||
|
|
||||||
|
@FindBy(id = "description")
|
||||||
|
private WebElement description;
|
||||||
|
|
||||||
|
@FindBy(id = "logic")
|
||||||
|
private Select logic;
|
||||||
|
|
||||||
|
@FindBy(xpath = "//i[contains(@class,'pficon-delete')]")
|
||||||
|
private WebElement deleteButton;
|
||||||
|
|
||||||
|
@FindBy(id = "s2id_clients")
|
||||||
|
private ClientSelect clientsInput;
|
||||||
|
|
||||||
|
@FindBy(xpath = ACTIVE_DIV_XPATH + "/button[text()='Delete']")
|
||||||
|
private WebElement confirmDelete;
|
||||||
|
|
||||||
|
public void populate(ClientPolicyRepresentation expected) {
|
||||||
|
setInputValue(name, expected.getName());
|
||||||
|
setInputValue(description, expected.getDescription());
|
||||||
|
logic.selectByValue(expected.getLogic().name());
|
||||||
|
|
||||||
|
clientsInput.update(expected.getClients());
|
||||||
|
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
deleteButton.click();
|
||||||
|
confirmDelete.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientPolicyRepresentation toRepresentation() {
|
||||||
|
ClientPolicyRepresentation representation = new ClientPolicyRepresentation();
|
||||||
|
|
||||||
|
representation.setName(getInputValue(name));
|
||||||
|
representation.setDescription(getInputValue(description));
|
||||||
|
representation.setLogic(Logic.valueOf(logic.getFirstSelectedOption().getText().toUpperCase()));
|
||||||
|
representation.setClients(clientsInput.getSelected());
|
||||||
|
|
||||||
|
return representation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ClientSelect extends MultipleStringSelect2 {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<WebElement> getSelectedElements() {
|
||||||
|
return getRoot().findElements(By.xpath("(//table[@id='selected-clients'])/tbody/tr")).stream()
|
||||||
|
.filter(webElement -> webElement.findElements(tagName("td")).size() > 1)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BiFunction<WebElement, String, Boolean> deselect() {
|
||||||
|
return (webElement, name) -> {
|
||||||
|
List<WebElement> tds = webElement.findElements(tagName("td"));
|
||||||
|
|
||||||
|
if (!tds.get(0).getText().isEmpty()) {
|
||||||
|
if (tds.get(0).getText().equals(name)) {
|
||||||
|
tds.get(1).findElement(By.tagName("button")).click();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Function<WebElement, String> representation() {
|
||||||
|
return webElement -> webElement.findElements(tagName("td")).get(0).getText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ import static org.openqa.selenium.By.tagName;
|
||||||
import org.jboss.arquillian.graphene.page.Page;
|
import org.jboss.arquillian.graphene.page.Page;
|
||||||
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
import org.keycloak.representations.idm.authorization.AbstractPolicyRepresentation;
|
||||||
import org.keycloak.representations.idm.authorization.AggregatePolicyRepresentation;
|
import org.keycloak.representations.idm.authorization.AggregatePolicyRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.ClientPolicyRepresentation;
|
||||||
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
|
import org.keycloak.representations.idm.authorization.JSPolicyRepresentation;
|
||||||
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||||
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
|
import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
|
||||||
|
@ -62,6 +63,9 @@ public class Policies extends Form {
|
||||||
@Page
|
@Page
|
||||||
private RulePolicy rulePolicy;
|
private RulePolicy rulePolicy;
|
||||||
|
|
||||||
|
@Page
|
||||||
|
private ClientPolicy clientPolicy;
|
||||||
|
|
||||||
public PoliciesTable policies() {
|
public PoliciesTable policies() {
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
@ -95,6 +99,10 @@ public class Policies extends Form {
|
||||||
rulePolicy.form().populate((RulePolicyRepresentation) expected);
|
rulePolicy.form().populate((RulePolicyRepresentation) expected);
|
||||||
rulePolicy.form().save();
|
rulePolicy.form().save();
|
||||||
return (P) rulePolicy;
|
return (P) rulePolicy;
|
||||||
|
} else if ("client".equals(type)) {
|
||||||
|
clientPolicy.form().populate((ClientPolicyRepresentation) expected);
|
||||||
|
clientPolicy.form().save();
|
||||||
|
return (P) clientPolicy;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -120,6 +128,8 @@ public class Policies extends Form {
|
||||||
timePolicy.form().populate((TimePolicyRepresentation) representation);
|
timePolicy.form().populate((TimePolicyRepresentation) representation);
|
||||||
} else if ("rules".equals(type)) {
|
} else if ("rules".equals(type)) {
|
||||||
rulePolicy.form().populate((RulePolicyRepresentation) representation);
|
rulePolicy.form().populate((RulePolicyRepresentation) representation);
|
||||||
|
} else if ("client".equals(type)) {
|
||||||
|
clientPolicy.form().populate((ClientPolicyRepresentation) representation);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -146,6 +156,8 @@ public class Policies extends Form {
|
||||||
return (P) timePolicy;
|
return (P) timePolicy;
|
||||||
} else if ("rules".equals(type)) {
|
} else if ("rules".equals(type)) {
|
||||||
return (P) rulePolicy;
|
return (P) rulePolicy;
|
||||||
|
} else if ("client".equals(type)) {
|
||||||
|
return (P) clientPolicy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,6 +185,8 @@ public class Policies extends Form {
|
||||||
timePolicy.form().delete();
|
timePolicy.form().delete();
|
||||||
} else if ("rules".equals(type)) {
|
} else if ("rules".equals(type)) {
|
||||||
rulePolicy.form().delete();
|
rulePolicy.form().delete();
|
||||||
|
} else if ("client".equals(type)) {
|
||||||
|
clientPolicy.form().delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -55,7 +55,7 @@ public class AggregatePolicyManagementTest extends AbstractAuthorizationSettings
|
||||||
|
|
||||||
AuthorizationResource authorization = testRealmResource().clients().get(newClient.getId()).authorization();
|
AuthorizationResource authorization = testRealmResource().clients().get(newClient.getId()).authorization();
|
||||||
PoliciesResource policies = authorization.policies();
|
PoliciesResource policies = authorization.policies();
|
||||||
RolePoliciesResource roles = policies.roles();
|
RolePoliciesResource roles = policies.role();
|
||||||
|
|
||||||
roles.create(policyA);
|
roles.create(policyA);
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ public class AggregatePolicyManagementTest extends AbstractAuthorizationSettings
|
||||||
policyC.setName("Policy C");
|
policyC.setName("Policy C");
|
||||||
policyC.addUser("test");
|
policyC.addUser("test");
|
||||||
|
|
||||||
policies.users().create(policyC);
|
policies.user().create(policyC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.keycloak.testsuite.console.authorization;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.admin.client.resource.ClientsResource;
|
||||||
|
import org.keycloak.representations.idm.authorization.ClientPolicyRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.Logic;
|
||||||
|
import org.keycloak.testsuite.console.page.clients.authorization.policy.ClientPolicy;
|
||||||
|
import org.keycloak.testsuite.util.ClientBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
public class ClientPolicyManagementTest extends AbstractAuthorizationSettingsTest {
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void configureTest() {
|
||||||
|
super.configureTest();
|
||||||
|
ClientsResource clients = testRealmResource().clients();
|
||||||
|
clients.create(ClientBuilder.create().clientId("client a").build());
|
||||||
|
clients.create(ClientBuilder.create().clientId("client b").build());
|
||||||
|
clients.create(ClientBuilder.create().clientId("client c").build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdate() throws InterruptedException {
|
||||||
|
authorizationPage.navigateTo();
|
||||||
|
ClientPolicyRepresentation expected = new ClientPolicyRepresentation();
|
||||||
|
|
||||||
|
expected.setName("Test Client Policy");
|
||||||
|
expected.setDescription("description");
|
||||||
|
expected.addClient("client a");
|
||||||
|
expected.addClient("client b");
|
||||||
|
expected.addClient("client c");
|
||||||
|
|
||||||
|
expected = createPolicy(expected);
|
||||||
|
|
||||||
|
String previousName = expected.getName();
|
||||||
|
|
||||||
|
expected.setName("Changed Test Client Policy");
|
||||||
|
expected.setDescription("Changed description");
|
||||||
|
expected.setLogic(Logic.NEGATIVE);
|
||||||
|
|
||||||
|
expected.setClients(expected.getClients().stream().filter(client -> !client.equals("client b")).collect(Collectors.toSet()));
|
||||||
|
|
||||||
|
authorizationPage.navigateTo();
|
||||||
|
authorizationPage.authorizationTabs().policies().update(previousName, expected);
|
||||||
|
assertAlertSuccess();
|
||||||
|
|
||||||
|
authorizationPage.navigateTo();
|
||||||
|
ClientPolicy actual = authorizationPage.authorizationTabs().policies().name(expected.getName());
|
||||||
|
|
||||||
|
assertPolicy(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeletePolicy() throws InterruptedException {
|
||||||
|
authorizationPage.navigateTo();
|
||||||
|
ClientPolicyRepresentation expected = new ClientPolicyRepresentation();
|
||||||
|
|
||||||
|
expected.setName("Test Client Policy");
|
||||||
|
expected.setDescription("description");
|
||||||
|
expected.addClient("client c");
|
||||||
|
|
||||||
|
expected = createPolicy(expected);
|
||||||
|
authorizationPage.navigateTo();
|
||||||
|
authorizationPage.authorizationTabs().policies().delete(expected.getName());
|
||||||
|
assertAlertSuccess();
|
||||||
|
authorizationPage.navigateTo();
|
||||||
|
assertNull(authorizationPage.authorizationTabs().policies().policies().findByName(expected.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClientPolicyRepresentation createPolicy(ClientPolicyRepresentation expected) {
|
||||||
|
ClientPolicy policy = authorizationPage.authorizationTabs().policies().create(expected);
|
||||||
|
assertAlertSuccess();
|
||||||
|
return assertPolicy(expected, policy);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClientPolicyRepresentation assertPolicy(ClientPolicyRepresentation expected, ClientPolicy policy) {
|
||||||
|
ClientPolicyRepresentation actual = policy.toRepresentation();
|
||||||
|
|
||||||
|
assertEquals(expected.getName(), actual.getName());
|
||||||
|
assertEquals(expected.getDescription(), actual.getDescription());
|
||||||
|
assertEquals(expected.getLogic(), actual.getLogic());
|
||||||
|
|
||||||
|
assertNotNull(actual.getClients());
|
||||||
|
assertEquals(expected.getClients().size(), actual.getClients().size());
|
||||||
|
assertEquals(0, actual.getClients().stream().filter(actualClient -> !expected.getClients().stream()
|
||||||
|
.filter(expectedClient -> actualClient.equals(expectedClient))
|
||||||
|
.findFirst().isPresent())
|
||||||
|
.count());
|
||||||
|
return actual;
|
||||||
|
}
|
||||||
|
}
|
|
@ -56,7 +56,7 @@ public class ResourcePermissionManagementTest extends AbstractAuthorizationSetti
|
||||||
|
|
||||||
AuthorizationResource authorization = testRealmResource().clients().get(newClient.getId()).authorization();
|
AuthorizationResource authorization = testRealmResource().clients().get(newClient.getId()).authorization();
|
||||||
PoliciesResource policies = authorization.policies();
|
PoliciesResource policies = authorization.policies();
|
||||||
RolePoliciesResource roles = policies.roles();
|
RolePoliciesResource roles = policies.role();
|
||||||
|
|
||||||
roles.create(policyA);
|
roles.create(policyA);
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ public class ResourcePermissionManagementTest extends AbstractAuthorizationSetti
|
||||||
policyC.setName("Policy C");
|
policyC.setName("Policy C");
|
||||||
policyC.addUser("test");
|
policyC.addUser("test");
|
||||||
|
|
||||||
policies.users().create(policyC);
|
policies.user().create(policyC);
|
||||||
|
|
||||||
ResourcesResource resources = authorization.resources();
|
ResourcesResource resources = authorization.resources();
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ public class ScopePermissionManagementTest extends AbstractAuthorizationSettings
|
||||||
|
|
||||||
AuthorizationResource authorization = testRealmResource().clients().get(newClient.getId()).authorization();
|
AuthorizationResource authorization = testRealmResource().clients().get(newClient.getId()).authorization();
|
||||||
PoliciesResource policies = authorization.policies();
|
PoliciesResource policies = authorization.policies();
|
||||||
RolePoliciesResource roles = policies.roles();
|
RolePoliciesResource roles = policies.role();
|
||||||
|
|
||||||
roles.create(policyA);
|
roles.create(policyA);
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ public class ScopePermissionManagementTest extends AbstractAuthorizationSettings
|
||||||
policyC.setName("Policy C");
|
policyC.setName("Policy C");
|
||||||
policyC.addUser("test");
|
policyC.addUser("test");
|
||||||
|
|
||||||
policies.users().create(policyC);
|
policies.user().create(policyC);
|
||||||
|
|
||||||
authorization.scopes().create(new ScopeRepresentation("Scope A"));
|
authorization.scopes().create(new ScopeRepresentation("Scope A"));
|
||||||
authorization.scopes().create(new ScopeRepresentation("Scope B"));
|
authorization.scopes().create(new ScopeRepresentation("Scope B"));
|
||||||
|
|
|
@ -1434,8 +1434,8 @@ module.controller('ResourceServerPolicyClientDetailCtrl', function($scope, $rout
|
||||||
onInitUpdate : function(policy) {
|
onInitUpdate : function(policy) {
|
||||||
var selectedClients = [];
|
var selectedClients = [];
|
||||||
|
|
||||||
if (policy.config.clients) {
|
if (policy.clients) {
|
||||||
var clients = eval(policy.config.clients);
|
var clients = policy.clients;
|
||||||
|
|
||||||
for (var i = 0; i < clients.length; i++) {
|
for (var i = 0; i < clients.length; i++) {
|
||||||
Client.get({realm: $route.current.params.realm, client: clients[i]}, function(data) {
|
Client.get({realm: $route.current.params.realm, client: clients[i]}, function(data) {
|
||||||
|
@ -1461,7 +1461,8 @@ module.controller('ResourceServerPolicyClientDetailCtrl', function($scope, $rout
|
||||||
clients.push($scope.selectedClients[i].id);
|
clients.push($scope.selectedClients[i].id);
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.policy.config.clients = JSON.stringify(clients);
|
$scope.policy.clients = clients;
|
||||||
|
delete $scope.policy.config;
|
||||||
},
|
},
|
||||||
|
|
||||||
onInitCreate : function() {
|
onInitCreate : function() {
|
||||||
|
@ -1481,7 +1482,8 @@ module.controller('ResourceServerPolicyClientDetailCtrl', function($scope, $rout
|
||||||
clients.push($scope.selectedClients[i].id);
|
clients.push($scope.selectedClients[i].id);
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.policy.config.clients = JSON.stringify(clients);
|
$scope.policy.clients = clients;
|
||||||
|
delete $scope.policy.config;
|
||||||
}
|
}
|
||||||
}, realm, client, $scope);
|
}, realm, client, $scope);
|
||||||
});
|
});
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
<div class="form-group clearfix" style="margin-top: -15px;">
|
<div class="form-group clearfix" style="margin-top: -15px;">
|
||||||
<label class="col-md-2 control-label"></label>
|
<label class="col-md-2 control-label"></label>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
<table class="table table-striped table-bordered">
|
<table class="table table-striped table-bordered" id="selected-clients">
|
||||||
<thead>
|
<thead>
|
||||||
<tr data-ng-hide="!selectedClients.length">
|
<tr data-ng-hide="!selectedClients.length">
|
||||||
<th>{{:: 'clientId' | translate}}</th>
|
<th>{{:: 'clientId' | translate}}</th>
|
||||||
|
@ -64,10 +64,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group clearfix">
|
<div class="form-group clearfix">
|
||||||
<label class="col-md-2 control-label" for="policy.logic">{{:: 'authz-policy-logic' | translate}}</label>
|
<label class="col-md-2 control-label" for="logic">{{:: 'authz-policy-logic' | translate}}</label>
|
||||||
|
|
||||||
<div class="col-sm-1">
|
<div class="col-sm-1">
|
||||||
<select class="form-control" id="policy.logic"
|
<select class="form-control" id="logic"
|
||||||
data-ng-model="policy.logic">
|
data-ng-model="policy.logic">
|
||||||
<option value="POSITIVE">{{:: 'authz-policy-logic-positive' | translate}}</option>
|
<option value="POSITIVE">{{:: 'authz-policy-logic-positive' | translate}}</option>
|
||||||
<option value="NEGATIVE">{{:: 'authz-policy-logic-negative' | translate}}</option>
|
<option value="NEGATIVE">{{:: 'authz-policy-logic-negative' | translate}}</option>
|
||||||
|
|
Loading…
Reference in a new issue