fix
This commit is contained in:
parent
12cb295a35
commit
f67013bcb6
8 changed files with 646 additions and 4 deletions
|
@ -141,6 +141,7 @@ public class JsonWebToken implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasAudience(String audience) {
|
public boolean hasAudience(String audience) {
|
||||||
|
if (this.audience == null) return false;
|
||||||
for (String a : this.audience) {
|
for (String a : this.audience) {
|
||||||
if (a.equals(audience)) {
|
if (a.equals(audience)) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* 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.authorization.admin.permissions;
|
||||||
|
|
||||||
|
import org.keycloak.authorization.AuthorizationProvider;
|
||||||
|
import org.keycloak.authorization.model.Policy;
|
||||||
|
import org.keycloak.authorization.model.Resource;
|
||||||
|
import org.keycloak.authorization.model.ResourceServer;
|
||||||
|
import org.keycloak.authorization.model.Scope;
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.RoleModel;
|
||||||
|
import org.keycloak.representations.idm.authorization.DecisionStrategy;
|
||||||
|
import org.keycloak.representations.idm.authorization.Logic;
|
||||||
|
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
|
||||||
|
import org.keycloak.representations.idm.authorization.ScopePermissionRepresentation;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class Helper {
|
||||||
|
public static Policy addScopePermission(AuthorizationProvider authz, ResourceServer resourceServer, String name, Resource resource, Scope scope, Policy policy) {
|
||||||
|
ScopePermissionRepresentation representation = new ScopePermissionRepresentation();
|
||||||
|
|
||||||
|
representation.setName(name);
|
||||||
|
representation.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
|
||||||
|
representation.setLogic(Logic.POSITIVE);
|
||||||
|
representation.addResource(resource.getName());
|
||||||
|
representation.addScope(scope.getName());
|
||||||
|
representation.addPolicy(policy.getName());
|
||||||
|
|
||||||
|
return authz.getStoreFactory().getPolicyStore().create(representation, resourceServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Policy addEmptyScopePermission(AuthorizationProvider authz, ResourceServer resourceServer, String name, Resource resource, Scope scope) {
|
||||||
|
ScopePermissionRepresentation representation = new ScopePermissionRepresentation();
|
||||||
|
|
||||||
|
representation.setName(name);
|
||||||
|
representation.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
|
||||||
|
representation.setLogic(Logic.POSITIVE);
|
||||||
|
representation.addResource(resource.getName());
|
||||||
|
representation.addScope(scope.getName());
|
||||||
|
|
||||||
|
return authz.getStoreFactory().getPolicyStore().create(representation, resourceServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Policy createRolePolicy(AuthorizationProvider authz, ResourceServer resourceServer, RoleModel role) {
|
||||||
|
String roleName = getRolePolicyName(role);
|
||||||
|
return createRolePolicy(authz, resourceServer, role, roleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Policy createRolePolicy(AuthorizationProvider authz, ResourceServer resourceServer, RoleModel role, String policyName) {
|
||||||
|
PolicyRepresentation representation = new PolicyRepresentation();
|
||||||
|
|
||||||
|
representation.setName(policyName);
|
||||||
|
representation.setType("role");
|
||||||
|
representation.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
|
||||||
|
representation.setLogic(Logic.POSITIVE);
|
||||||
|
String roleValues = "[{\"id\":\"" + role.getId() + "\",\"required\": true}]";
|
||||||
|
Map<String, String> config = new HashMap<>();
|
||||||
|
config.put("roles", roleValues);
|
||||||
|
representation.setConfig(config);
|
||||||
|
|
||||||
|
return authz.getStoreFactory().getPolicyStore().create(representation, resourceServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getRolePolicyName(RoleModel role) {
|
||||||
|
String roleName = "";
|
||||||
|
if (role.getContainer() instanceof ClientModel) {
|
||||||
|
ClientModel client = (ClientModel) role.getContainer();
|
||||||
|
roleName = client.getClientId() + "." + role.getName();
|
||||||
|
} else {
|
||||||
|
roleName = role.getName();
|
||||||
|
}
|
||||||
|
roleName = "role.policy." + roleName;
|
||||||
|
return roleName;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* 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.authorization.admin.permissions;
|
||||||
|
|
||||||
|
import org.keycloak.authorization.AuthorizationProvider;
|
||||||
|
import org.keycloak.authorization.AuthorizationProviderFactory;
|
||||||
|
import org.keycloak.authorization.common.KeycloakIdentity;
|
||||||
|
import org.keycloak.authorization.common.UserModelIdentity;
|
||||||
|
import org.keycloak.authorization.identity.Identity;
|
||||||
|
import org.keycloak.authorization.model.ResourceServer;
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.Constants;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.keycloak.services.managers.RealmManager;
|
||||||
|
import org.keycloak.services.resources.admin.AdminAuth;
|
||||||
|
import org.keycloak.services.resources.admin.RealmAuth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class MgmtPermissions {
|
||||||
|
public static final String MANAGE_SCOPE = "manage";
|
||||||
|
|
||||||
|
protected RealmModel realm;
|
||||||
|
protected KeycloakSession session;
|
||||||
|
protected AuthorizationProvider authz;
|
||||||
|
protected AdminAuth auth;
|
||||||
|
protected Identity identity;
|
||||||
|
|
||||||
|
public MgmtPermissions(KeycloakSession session, RealmModel realm) {
|
||||||
|
this.session = session;
|
||||||
|
this.realm = realm;
|
||||||
|
AuthorizationProviderFactory factory = (AuthorizationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(AuthorizationProvider.class);
|
||||||
|
this.authz = factory.create(session, realm);
|
||||||
|
}
|
||||||
|
public MgmtPermissions(KeycloakSession session, RealmModel realm, AdminAuth auth) {
|
||||||
|
this(session, realm);
|
||||||
|
this.auth = auth;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAdminSameRealm() {
|
||||||
|
return realm.getId().equals(auth.getRealm().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public RealmAuth getRealmAuth() {
|
||||||
|
RealmManager realmManager = new RealmManager(session);
|
||||||
|
if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
|
||||||
|
return new RealmAuth(auth, realm.getMasterAdminClient());
|
||||||
|
} else {
|
||||||
|
return new RealmAuth(auth, realm.getClientByClientId(realmManager.getRealmAdminClientId(auth.getRealm())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Identity identity() {
|
||||||
|
if (identity != null) return identity;
|
||||||
|
if (auth.getClient().getClientId().equals(Constants.REALM_MANAGEMENT_CLIENT_ID)) {
|
||||||
|
this.identity = new UserModelIdentity(realm, auth.getUser());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.identity = new KeycloakIdentity(auth.getToken(), session);
|
||||||
|
}
|
||||||
|
return this.identity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public RoleMgmtPermissions roles() {
|
||||||
|
return new RoleMgmtPermissions(session, realm, authz, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceServer findOrCreateResourceServer(ClientModel client) {
|
||||||
|
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
||||||
|
if (server == null) {
|
||||||
|
server = authz.getStoreFactory().getResourceServerStore().create(client.getId());
|
||||||
|
}
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
* 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.authorization.admin.permissions;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.authorization.AuthorizationProvider;
|
||||||
|
import org.keycloak.authorization.Decision;
|
||||||
|
import org.keycloak.authorization.common.DefaultEvaluationContext;
|
||||||
|
import org.keycloak.authorization.identity.Identity;
|
||||||
|
import org.keycloak.authorization.model.Policy;
|
||||||
|
import org.keycloak.authorization.model.Resource;
|
||||||
|
import org.keycloak.authorization.model.ResourceServer;
|
||||||
|
import org.keycloak.authorization.model.Scope;
|
||||||
|
import org.keycloak.authorization.permission.ResourcePermission;
|
||||||
|
import org.keycloak.authorization.permission.evaluator.PermissionEvaluator;
|
||||||
|
import org.keycloak.authorization.policy.evaluation.DecisionResult;
|
||||||
|
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
|
||||||
|
import org.keycloak.authorization.util.Permissions;
|
||||||
|
import org.keycloak.models.AdminRoles;
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.Constants;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.RoleModel;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class RoleMgmtPermissions {
|
||||||
|
private static final Logger logger = Logger.getLogger(RoleMgmtPermissions.class);
|
||||||
|
public static final String MAP_ROLE_SCOPE = "map-role";
|
||||||
|
protected final KeycloakSession session;
|
||||||
|
protected final RealmModel realm;
|
||||||
|
protected final AuthorizationProvider authz;
|
||||||
|
protected final MgmtPermissions root;
|
||||||
|
|
||||||
|
public RoleMgmtPermissions(KeycloakSession session, RealmModel realm, AuthorizationProvider authz, MgmtPermissions root) {
|
||||||
|
this.session = session;
|
||||||
|
this.realm = realm;
|
||||||
|
this.authz = authz;
|
||||||
|
this.root = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPermissionsEnabled(RoleModel role) {
|
||||||
|
ClientModel client = getRoleClient(role);
|
||||||
|
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
||||||
|
if (server == null) return false;
|
||||||
|
|
||||||
|
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
|
||||||
|
if (resource == null) return false;
|
||||||
|
|
||||||
|
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRoleScopePermissionName(role), server.getId());
|
||||||
|
|
||||||
|
return policy != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPermissionsEnabled(RoleModel role, boolean enable) {
|
||||||
|
if (enable) {
|
||||||
|
ResourceServer server = getResourceServer(role);
|
||||||
|
if (authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId()) != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
createResource(role);
|
||||||
|
} else {
|
||||||
|
ClientModel client = getRoleClient(role);
|
||||||
|
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
||||||
|
if (server == null) return;
|
||||||
|
Resource resource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), server.getId());
|
||||||
|
if (resource != null) authz.getStoreFactory().getResourceStore().delete(resource.getId());
|
||||||
|
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRoleScopePermissionName(role), server.getId());
|
||||||
|
if (policy != null) authz.getStoreFactory().getPolicyStore().delete(policy.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canMapRole(RoleModel role) {
|
||||||
|
if (!root.isAdminSameRealm()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!isPermissionsEnabled(role)) return true; // no authz permissions set up so just allow it.
|
||||||
|
|
||||||
|
ResourceServer resourceServer = getResourceServer(role);
|
||||||
|
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(getMapRoleScopePermissionName(role), resourceServer.getId());
|
||||||
|
if (policy.getAssociatedPolicies().isEmpty()) {
|
||||||
|
return true; // if no policies applied, just ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Identity identity = root.identity();
|
||||||
|
|
||||||
|
EvaluationContext context = new DefaultEvaluationContext(identity, session);
|
||||||
|
DecisionResult decisionCollector = new DecisionResult();
|
||||||
|
Resource roleResource = authz.getStoreFactory().getResourceStore().findByName(getRoleResourceName(role), resourceServer.getId());
|
||||||
|
Scope mapRoleScope = getMapRoleScope(resourceServer);
|
||||||
|
|
||||||
|
List<ResourcePermission> permissions = Permissions.permission(resourceServer, roleResource, mapRoleScope);
|
||||||
|
PermissionEvaluator from = authz.evaluators().from(permissions, context);
|
||||||
|
from.evaluate(decisionCollector);
|
||||||
|
if (!decisionCollector.completed()) {
|
||||||
|
logger.error("Failed to run map role policy check", decisionCollector.getError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return decisionCollector.getResults().get(0).getEffect() == Decision.Effect.PERMIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ClientModel getRoleClient(RoleModel role) {
|
||||||
|
ClientModel client = null;
|
||||||
|
if (role.getContainer() instanceof ClientModel) {
|
||||||
|
client = (ClientModel)role.getContainer();
|
||||||
|
} else {
|
||||||
|
client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||||
|
}
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Policy getManageUsersPolicy(ResourceServer server) {
|
||||||
|
RoleModel role = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID).getRole(AdminRoles.MANAGE_USERS);
|
||||||
|
return getRolePolicy(server, role);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Policy getRolePolicy(ResourceServer server, RoleModel role) {
|
||||||
|
String policyName = Helper.getRolePolicyName(role);
|
||||||
|
Policy policy = authz.getStoreFactory().getPolicyStore().findByName(policyName, server.getId());
|
||||||
|
if (policy != null) return policy;
|
||||||
|
return Helper.createRolePolicy(authz, server, role, policyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Scope getMapRoleScope(ResourceServer server) {
|
||||||
|
Scope scope = authz.getStoreFactory().getScopeStore().findByName(MAP_ROLE_SCOPE, server.getId());
|
||||||
|
if (scope == null) {
|
||||||
|
scope = authz.getStoreFactory().getScopeStore().create(MAP_ROLE_SCOPE, server);
|
||||||
|
}
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Resource createResource(RoleModel role) {
|
||||||
|
ResourceServer server = getResourceServer(role);
|
||||||
|
Resource resource = authz.getStoreFactory().getResourceStore().create(getRoleResourceName(role), server, server.getClientId());
|
||||||
|
resource.setType("Role");
|
||||||
|
Scope mapRoleScope = getMapRoleScope(server);
|
||||||
|
Helper.addEmptyScopePermission(authz, server, getMapRoleScopePermissionName(role), resource, mapRoleScope);
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getMapRoleScopePermissionName(RoleModel role) {
|
||||||
|
return MAP_ROLE_SCOPE + ".permission." + role.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResourceServer getResourceServer(RoleModel role) {
|
||||||
|
ClientModel client = getRoleClient(role);
|
||||||
|
return root.findOrCreateResourceServer(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getRoleResourceName(RoleModel role) {
|
||||||
|
return "role.resource." + role.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,188 @@
|
||||||
|
/*
|
||||||
|
* 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.authorization.admin.permissions;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.authorization.AuthorizationProvider;
|
||||||
|
import org.keycloak.authorization.Decision;
|
||||||
|
import org.keycloak.authorization.common.DefaultEvaluationContext;
|
||||||
|
import org.keycloak.authorization.identity.Identity;
|
||||||
|
import org.keycloak.authorization.model.Policy;
|
||||||
|
import org.keycloak.authorization.model.Resource;
|
||||||
|
import org.keycloak.authorization.model.ResourceServer;
|
||||||
|
import org.keycloak.authorization.model.Scope;
|
||||||
|
import org.keycloak.authorization.permission.ResourcePermission;
|
||||||
|
import org.keycloak.authorization.permission.evaluator.PermissionEvaluator;
|
||||||
|
import org.keycloak.authorization.policy.evaluation.DecisionResult;
|
||||||
|
import org.keycloak.authorization.policy.evaluation.EvaluationContext;
|
||||||
|
import org.keycloak.authorization.util.Permissions;
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.Constants;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.RoleModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.services.managers.RealmManager;
|
||||||
|
import org.keycloak.services.resources.admin.AdminAuth;
|
||||||
|
import org.keycloak.services.resources.admin.RealmAuth;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class UsersPermissions {
|
||||||
|
private static final Logger logger = Logger.getLogger(UsersPermissions.class);
|
||||||
|
protected final KeycloakSession session;
|
||||||
|
protected final RealmModel realm;
|
||||||
|
protected final AuthorizationProvider authz;
|
||||||
|
protected final MgmtPermissions root;
|
||||||
|
|
||||||
|
public UsersPermissions(KeycloakSession session, RealmModel realm, AuthorizationProvider authz, MgmtPermissions root) {
|
||||||
|
this.session = session;
|
||||||
|
this.realm = realm;
|
||||||
|
this.authz = authz;
|
||||||
|
this.root = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize() {
|
||||||
|
ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||||
|
ResourceServer server = root.findOrCreateResourceServer(client);
|
||||||
|
Scope manageScope = authz.getStoreFactory().getScopeStore().findByName(MgmtPermissions.MANAGE_SCOPE, server.getId());
|
||||||
|
if (manageScope == null) {
|
||||||
|
manageScope = authz.getStoreFactory().getScopeStore().create(MgmtPermissions.MANAGE_SCOPE, server);
|
||||||
|
|
||||||
|
}
|
||||||
|
Resource usersResource = authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
|
||||||
|
if (usersResource == null) {
|
||||||
|
usersResource = authz.getStoreFactory().getResourceStore().create("Users", server, server.getClientId());
|
||||||
|
}
|
||||||
|
Policy policy = authz.getStoreFactory().getPolicyStore().findByName("manage.permissions.users", server.getId());
|
||||||
|
if (policy == null) {
|
||||||
|
Set<Scope> scopeset = new HashSet<>();
|
||||||
|
scopeset.add(manageScope);
|
||||||
|
usersResource.updateScopes(scopeset);
|
||||||
|
Policy manageUsersPolicy = root.roles().getManageUsersPolicy(server);
|
||||||
|
Helper.addScopePermission(authz, server, "manage.permission.users", usersResource, manageScope, manageUsersPolicy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPermissionsEnabled() {
|
||||||
|
ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||||
|
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
||||||
|
if (server == null) return false;
|
||||||
|
|
||||||
|
Resource resource = authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
|
||||||
|
if (resource == null) return false;
|
||||||
|
|
||||||
|
Policy policy = authz.getStoreFactory().getPolicyStore().findByName("manage.permissions.users", server.getId());
|
||||||
|
|
||||||
|
return policy != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPermissionsEnabled(RoleModel role, boolean enable) {
|
||||||
|
ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||||
|
if (enable) {
|
||||||
|
initialize();
|
||||||
|
} else {
|
||||||
|
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
||||||
|
if (server == null) return;
|
||||||
|
Resource usersResource = authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
|
||||||
|
if (usersResource == null) {
|
||||||
|
authz.getStoreFactory().getResourceStore().delete(usersResource.getId());
|
||||||
|
}
|
||||||
|
Policy policy = authz.getStoreFactory().getPolicyStore().findByName("manage.permissions.users", server.getId());
|
||||||
|
if (policy == null) {
|
||||||
|
authz.getStoreFactory().getPolicyStore().delete(policy.getId());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Resource getUsersResource(ResourceServer server) {
|
||||||
|
Resource usersResource = authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
|
||||||
|
if (usersResource == null) {
|
||||||
|
usersResource = authz.getStoreFactory().getResourceStore().create("Users", server, server.getClientId());
|
||||||
|
}
|
||||||
|
return usersResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Scope getManageScope(ResourceServer server) {
|
||||||
|
Scope manageScope = authz.getStoreFactory().getScopeStore().findByName(MgmtPermissions.MANAGE_SCOPE, server.getId());
|
||||||
|
if (manageScope == null) {
|
||||||
|
manageScope = authz.getStoreFactory().getScopeStore().create(MgmtPermissions.MANAGE_SCOPE, server);
|
||||||
|
|
||||||
|
}
|
||||||
|
return manageScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResourceServer getRealmManagementResourceServer() {
|
||||||
|
ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||||
|
return root.findOrCreateResourceServer(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canManageDefault() {
|
||||||
|
RealmAuth auth = root.getRealmAuth();
|
||||||
|
auth.init(RealmAuth.Resource.USER);
|
||||||
|
return auth.hasManage();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canManage(UserModel user) {
|
||||||
|
if (!root.isAdminSameRealm()) {
|
||||||
|
return canManageDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||||
|
ResourceServer server = authz.getStoreFactory().getResourceServerStore().findByClient(client.getId());
|
||||||
|
if (server == null) return canManageDefault();
|
||||||
|
|
||||||
|
Resource resource = authz.getStoreFactory().getResourceStore().findByName("Users", server.getId());
|
||||||
|
if (resource == null) return canManageDefault();
|
||||||
|
|
||||||
|
Policy policy = authz.getStoreFactory().getPolicyStore().findByName("manage.permissions.users", server.getId());
|
||||||
|
if (policy == null) {
|
||||||
|
return canManageDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
|
||||||
|
// if no policies attached to permission then just do default behavior
|
||||||
|
if (associatedPolicies == null || associatedPolicies.isEmpty()) {
|
||||||
|
return canManageDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
Identity identity = root.identity();
|
||||||
|
EvaluationContext context = new DefaultEvaluationContext(identity, session);
|
||||||
|
DecisionResult decisionCollector = new DecisionResult();
|
||||||
|
ResourceServer resourceServer = getRealmManagementResourceServer();
|
||||||
|
Resource roleResource = authz.getStoreFactory().getResourceStore().findByName("Users", resourceServer.getId());
|
||||||
|
Scope manageScope = getManageScope(resourceServer);
|
||||||
|
|
||||||
|
List<ResourcePermission> permissions = Permissions.permission(resourceServer, roleResource, manageScope);
|
||||||
|
PermissionEvaluator from = authz.evaluators().from(permissions, context);
|
||||||
|
from.evaluate(decisionCollector);
|
||||||
|
if (!decisionCollector.completed()) {
|
||||||
|
logger.error("Failed to run Users manage check", decisionCollector.getError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return decisionCollector.getResults().get(0).getEffect() == Decision.Effect.PERMIT;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,6 +54,74 @@ public class KeycloakIdentity implements Identity {
|
||||||
this(Tokens.getAccessToken(keycloakSession), keycloakSession);
|
this(Tokens.getAccessToken(keycloakSession), keycloakSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public KeycloakIdentity(KeycloakSession keycloakSession, AccessToken accessToken) {
|
||||||
|
this(accessToken, keycloakSession, keycloakSession.getContext().getRealm());
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeycloakIdentity(AccessToken accessToken, KeycloakSession keycloakSession, RealmModel realm) {
|
||||||
|
if (accessToken == null) {
|
||||||
|
throw new ErrorResponseException("invalid_bearer_token", "Could not obtain bearer access_token from request.", Status.FORBIDDEN);
|
||||||
|
}
|
||||||
|
if (keycloakSession == null) {
|
||||||
|
throw new ErrorResponseException("no_keycloak_session", "No keycloak session", Status.FORBIDDEN);
|
||||||
|
}
|
||||||
|
if (realm == null) {
|
||||||
|
throw new ErrorResponseException("no_keycloak_session", "No realm set", Status.FORBIDDEN);
|
||||||
|
}
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
this.keycloakSession = keycloakSession;
|
||||||
|
this.realm = realm;
|
||||||
|
|
||||||
|
Map<String, Collection<String>> attributes = new HashMap<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
ObjectNode objectNode = JsonSerialization.createObjectNode(this.accessToken);
|
||||||
|
Iterator<String> iterator = objectNode.fieldNames();
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
String fieldName = iterator.next();
|
||||||
|
JsonNode fieldValue = objectNode.get(fieldName);
|
||||||
|
List<String> values = new ArrayList<>();
|
||||||
|
|
||||||
|
if (fieldValue.isArray()) {
|
||||||
|
Iterator<JsonNode> valueIterator = fieldValue.iterator();
|
||||||
|
|
||||||
|
while (valueIterator.hasNext()) {
|
||||||
|
values.add(valueIterator.next().asText());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String value = fieldValue.asText();
|
||||||
|
|
||||||
|
if (StringUtil.isNullOrEmpty(value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
values.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!values.isEmpty()) {
|
||||||
|
attributes.put(fieldName, values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessToken.Access realmAccess = accessToken.getRealmAccess();
|
||||||
|
|
||||||
|
if (realmAccess != null) {
|
||||||
|
attributes.put("kc.realm.roles", realmAccess.getRoles());
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, AccessToken.Access> resourceAccess = accessToken.getResourceAccess();
|
||||||
|
|
||||||
|
if (resourceAccess != null) {
|
||||||
|
resourceAccess.forEach((clientId, access) -> attributes.put("kc.client." + clientId + ".roles", access.getRoles()));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Error while reading attributes from security token.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.attributes = Attributes.from(attributes);
|
||||||
|
}
|
||||||
|
|
||||||
public KeycloakIdentity(AccessToken accessToken, KeycloakSession keycloakSession) {
|
public KeycloakIdentity(AccessToken accessToken, KeycloakSession keycloakSession) {
|
||||||
if (accessToken == null) {
|
if (accessToken == null) {
|
||||||
throw new ErrorResponseException("invalid_bearer_token", "Could not obtain bearer access_token from request.", Status.FORBIDDEN);
|
throw new ErrorResponseException("invalid_bearer_token", "Could not obtain bearer access_token from request.", Status.FORBIDDEN);
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.admin.client.resource.RealmResource;
|
import org.keycloak.admin.client.resource.RealmResource;
|
||||||
import org.keycloak.authorization.AuthorizationProvider;
|
import org.keycloak.authorization.AuthorizationProvider;
|
||||||
|
import org.keycloak.authorization.AuthorizationProviderFactory;
|
||||||
import org.keycloak.authorization.Decision;
|
import org.keycloak.authorization.Decision;
|
||||||
import org.keycloak.authorization.common.DefaultEvaluationContext;
|
import org.keycloak.authorization.common.DefaultEvaluationContext;
|
||||||
import org.keycloak.authorization.common.UserModelIdentity;
|
import org.keycloak.authorization.common.UserModelIdentity;
|
||||||
|
@ -79,9 +80,10 @@ public class FineGrainAdminLocalTest extends AbstractKeycloakTest {
|
||||||
public static void setupDefaults(KeycloakSession session) {
|
public static void setupDefaults(KeycloakSession session) {
|
||||||
RealmModel realm = session.realms().getRealmByName(TEST);
|
RealmModel realm = session.realms().getRealmByName(TEST);
|
||||||
|
|
||||||
ClientModel client = realm.getClientByClientId("realm-management");
|
ClientModel client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
|
||||||
|
|
||||||
AuthorizationProvider authz = session.getProvider(AuthorizationProvider.class);
|
AuthorizationProviderFactory factory = (AuthorizationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(AuthorizationProvider.class);
|
||||||
|
AuthorizationProvider authz = factory.create(session, realm);
|
||||||
ResourceServer resourceServer = authz.getStoreFactory().getResourceServerStore().create(client.getId());
|
ResourceServer resourceServer = authz.getStoreFactory().getResourceServerStore().create(client.getId());
|
||||||
Scope mapRoleScope = authz.getStoreFactory().getScopeStore().create("map-role", resourceServer);
|
Scope mapRoleScope = authz.getStoreFactory().getScopeStore().create("map-role", resourceServer);
|
||||||
Scope manageScope = authz.getStoreFactory().getScopeStore().create("manage", resourceServer);
|
Scope manageScope = authz.getStoreFactory().getScopeStore().create("manage", resourceServer);
|
||||||
|
@ -103,6 +105,7 @@ public class FineGrainAdminLocalTest extends AbstractKeycloakTest {
|
||||||
|
|
||||||
String name = "map.role.permission." + client.getClientId() + "." + role.getName();
|
String name = "map.role.permission." + client.getClientId() + "." + role.getName();
|
||||||
Policy permission = addScopePermission(authz, resourceServer, name, resource, mapRoleScope, policy);
|
Policy permission = addScopePermission(authz, resourceServer, name, resource, mapRoleScope, policy);
|
||||||
|
addEmptyScopePermission(authz, resourceServer, "empty. " + name, resource, mapRoleScope);
|
||||||
|
|
||||||
}
|
}
|
||||||
Resource usersResource = authz.getStoreFactory().getResourceStore().create("Users", resourceServer, resourceServer.getClientId());
|
Resource usersResource = authz.getStoreFactory().getResourceStore().create("Users", resourceServer, resourceServer.getClientId());
|
||||||
|
@ -125,6 +128,18 @@ public class FineGrainAdminLocalTest extends AbstractKeycloakTest {
|
||||||
return authz.getStoreFactory().getPolicyStore().create(representation, resourceServer);
|
return authz.getStoreFactory().getPolicyStore().create(representation, resourceServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Policy addEmptyScopePermission(AuthorizationProvider authz, ResourceServer resourceServer, String name, Resource resource, Scope scope) {
|
||||||
|
ScopePermissionRepresentation representation = new ScopePermissionRepresentation();
|
||||||
|
|
||||||
|
representation.setName(name);
|
||||||
|
representation.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
|
||||||
|
representation.setLogic(Logic.POSITIVE);
|
||||||
|
representation.addResource(resource.getName());
|
||||||
|
representation.addScope(scope.getName());
|
||||||
|
|
||||||
|
return authz.getStoreFactory().getPolicyStore().create(representation, resourceServer);
|
||||||
|
}
|
||||||
|
|
||||||
private static Resource createRoleResource(AuthorizationProvider authz, ResourceServer resourceServer, RoleModel role) {
|
private static Resource createRoleResource(AuthorizationProvider authz, ResourceServer resourceServer, RoleModel role) {
|
||||||
String roleName = getRoleResourceName(role);
|
String roleName = getRoleResourceName(role);
|
||||||
Resource resource = authz.getStoreFactory().getResourceStore().create(roleName, resourceServer, resourceServer.getClientId());
|
Resource resource = authz.getStoreFactory().getResourceStore().create(roleName, resourceServer, resourceServer.getClientId());
|
||||||
|
@ -179,7 +194,7 @@ public class FineGrainAdminLocalTest extends AbstractKeycloakTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@Test
|
@Test
|
||||||
public void testUI() throws Exception {
|
public void testUI() throws Exception {
|
||||||
testingClient.server().run(FineGrainAdminLocalTest::setupDefaults);
|
testingClient.server().run(FineGrainAdminLocalTest::setupDefaults);
|
||||||
testingClient.server().run(FineGrainAdminLocalTest::setupUsers);
|
testingClient.server().run(FineGrainAdminLocalTest::setupUsers);
|
||||||
|
|
|
@ -20,6 +20,7 @@ import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.admin.client.resource.RealmResource;
|
import org.keycloak.admin.client.resource.RealmResource;
|
||||||
import org.keycloak.authorization.AuthorizationProvider;
|
import org.keycloak.authorization.AuthorizationProvider;
|
||||||
|
import org.keycloak.authorization.AuthorizationProviderFactory;
|
||||||
import org.keycloak.authorization.model.Policy;
|
import org.keycloak.authorization.model.Policy;
|
||||||
import org.keycloak.authorization.model.Resource;
|
import org.keycloak.authorization.model.Resource;
|
||||||
import org.keycloak.authorization.model.ResourceServer;
|
import org.keycloak.authorization.model.ResourceServer;
|
||||||
|
@ -66,7 +67,8 @@ public class PolicyEvaluationCompositeRoleTest extends AbstractKeycloakTest {
|
||||||
RoleModel role1 = client.addRole("client-role1");
|
RoleModel role1 = client.addRole("client-role1");
|
||||||
|
|
||||||
|
|
||||||
AuthorizationProvider authz = session.getProvider(AuthorizationProvider.class);
|
AuthorizationProviderFactory factory = (AuthorizationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(AuthorizationProvider.class);
|
||||||
|
AuthorizationProvider authz = factory.create(session, realm);
|
||||||
ResourceServer resourceServer = authz.getStoreFactory().getResourceServerStore().create(client.getId());
|
ResourceServer resourceServer = authz.getStoreFactory().getResourceServerStore().create(client.getId());
|
||||||
Policy policy = createRolePolicy(authz, resourceServer, role1);
|
Policy policy = createRolePolicy(authz, resourceServer, role1);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue