Skip to content

Commit

Permalink
[KEYCLOAK-4755] - Client UI Tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pedroigor committed Apr 26, 2017
1 parent 2913ee8 commit fbcfcfa
Show file tree
Hide file tree
Showing 27 changed files with 962 additions and 155 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;
Expand All @@ -9,24 +9,29 @@
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();

for (String client : representation.getClients()) {
ClientModel clientModel = realm.getClientById(client);


if (clients.length > 0) { if (context.getAttributes().containsValue("kc.client.id", clientModel.getClientId())) {
for (String client : clients) { evaluation.grant();
ClientModel clientModel = realm.getClientById(client); return;
if (context.getAttributes().containsValue("kc.client.id", clientModel.getClientId())) {
evaluation.grant();
return;
}
} }
} }
} }
Expand Down
Expand Up @@ -2,27 +2,33 @@


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;
import org.keycloak.authorization.store.StoreFactory; 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() {
Expand All @@ -40,8 +46,29 @@ public PolicyProvider create(AuthorizationProvider authorization) {
} }


@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
Expand Down Expand Up @@ -101,7 +128,41 @@ public String getId() {
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) {
Expand Down
Expand Up @@ -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;
Expand All @@ -29,43 +29,43 @@
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();
Identity identity = evaluation.getContext().getIdentity();


if (roleIds.length > 0) { for (RolePolicyRepresentation.RoleDefinition roleDefinition : roleIds) {
Identity identity = evaluation.getContext().getIdentity(); RoleModel role = realm.getRoleById(roleDefinition.getId());


for (Map<String, Object> current : roleIds) { if (role != null) {
RoleModel role = realm.getRoleById((String) current.get("id")); boolean hasRole = hasRole(identity, role, realm);


if (role != null) { if (!hasRole && roleDefinition.isRequired()) {
boolean hasRole = hasRole(identity, role, realm); evaluation.deny();

return;
if (!hasRole && Boolean.valueOf(isRequired(current))) { } else if (hasRole) {
evaluation.deny(); evaluation.grant();
return;
} else if (hasRole) {
evaluation.grant();
}
} }
} }
} }
} }


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();
if (role.isClientRole()) { if (role.isClientRole()) {
Expand Down
Expand Up @@ -23,7 +23,6 @@
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;
Expand Down Expand Up @@ -53,7 +52,7 @@
*/ */
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() {
Expand All @@ -70,20 +69,15 @@ public PolicyProvider create(AuthorizationProvider authorization) {
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);
} }
Expand Down Expand Up @@ -119,65 +113,63 @@ private void updateRoles(Policy policy, RolePolicyRepresentation representation,
} }


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

if (roles != null) {
for (RolePolicyRepresentation.RoleDefinition definition : roles) {
String roleName = definition.getId();
String clientId = null;
int clientIdSeparator = roleName.indexOf("/");

if (clientIdSeparator != -1) {
clientId = roleName.substring(0, clientIdSeparator);
roleName = roleName.substring(clientIdSeparator + 1);
}

RoleModel role;


if (clientId == null) { if (roles != null) {
role = realm.getRole(roleName); for (RolePolicyRepresentation.RoleDefinition definition : roles) {

String roleName = definition.getId();
if (role == null) { String clientId = null;
role = realm.getRoleById(roleName); int clientIdSeparator = roleName.indexOf("/");
}
} else { if (clientIdSeparator != -1) {
ClientModel client = realm.getClientByClientId(clientId); clientId = roleName.substring(0, clientIdSeparator);
roleName = roleName.substring(clientIdSeparator + 1);
}


if (client == null) { RoleModel role;
throw new RuntimeException("Client with id [" + clientId + "] not found.");
}


role = client.getRole(roleName); if (clientId == null) {
} role = realm.getRole(roleName);


// fallback to find any client role with the given name
if (role == null) { if (role == null) {
String finalRoleName = roleName; role = realm.getRoleById(roleName);
role = realm.getClients().stream().map(clientModel -> clientModel.getRole(finalRoleName)).filter(roleModel -> roleModel != null)
.findFirst().orElse(null);
} }
} else {
ClientModel client = realm.getClientByClientId(clientId);


if (role == null) { if (client == null) {
throw new RuntimeException("Error while importing configuration. Role [" + roleName + "] could not be found."); throw new RuntimeException("Client with id [" + clientId + "] not found.");
} }


definition.setId(role.getId()); role = client.getRole(roleName);
}


updatedRoles.add(definition); // fallback to find any client role with the given name
if (role == null) {
String finalRoleName = roleName;
role = realm.getClients().stream().map(clientModel -> clientModel.getRole(finalRoleName)).filter(roleModel -> roleModel != null)
.findFirst().orElse(null);
} }
try {
} catch (Exception e) { if (role == null) {
throw new RuntimeException("Error while updating policy [" + policy.getName() + "].", e); throw new RuntimeException("Error while updating policy [" + policy.getName() + "]. Role [" + roleName + "] could not be found.");
} }

definition.setId(role.getId());

updatedRoles.add(definition);
} }
}


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


Expand Down Expand Up @@ -253,7 +245,7 @@ public String getId() {
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) {
Expand Down

0 comments on commit fbcfcfa

Please sign in to comment.