/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual 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.util;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.ErrorCode;
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.store.PolicyStore;
import org.keycloak.authorization.store.ResourceStore;
import org.keycloak.authorization.store.StoreFactory;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.services.ErrorResponseException;
import org.keycloak.util.JsonSerialization;
import javax.ws.rs.core.Response.Status;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Some utility methods to transform models to representations and vice-versa.
*
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
*/
public final class Models {
public static ScopeRepresentation toRepresentation(Scope model, AuthorizationProvider authorizationProvider) {
ScopeRepresentation scope = new ScopeRepresentation();
scope.setId(model.getId());
scope.setName(model.getName());
scope.setIconUri(model.getIconUri());
StoreFactory storeFactory = authorizationProvider.getStoreFactory();
scope.setResources(new ArrayList<>());
storeFactory.getResourceStore().findByScope(model.getId()).forEach(resource -> scope.getResources().add(toRepresentation(resource, resource.getResourceServer(), authorizationProvider)));
PolicyStore policyStore = storeFactory.getPolicyStore();
scope.setPolicies(new ArrayList<>());
policyStore.findByScopeIds(Arrays.asList(model.getId()), model.getResourceServer().getId()).forEach(policyModel -> {
PolicyRepresentation policy = new PolicyRepresentation();
policy.setId(policyModel.getId());
policy.setName(policyModel.getName());
policy.setType(policyModel.getType());
if (!scope.getPolicies().contains(policy)) {
scope.getPolicies().add(policy);
}
});
return scope;
}
public static Scope toModel(ScopeRepresentation scope, ResourceServer resourceServer, AuthorizationProvider authorization) {
StoreFactory storeFactory = authorization.getStoreFactory();
Scope model = storeFactory.getScopeStore().findByName(scope.getName(), resourceServer.getId());
if (model == null) {
model = storeFactory.getScopeStore().create(scope.getName(), resourceServer);
model.setIconUri(scope.getIconUri());
}
return model;
}
public static ResourceServerRepresentation toRepresentation(ResourceServer model, RealmModel realm) {
ResourceServerRepresentation server = new ResourceServerRepresentation();
server.setId(model.getId());
server.setClientId(model.getClientId());
ClientModel clientById = realm.getClientById(model.getClientId());
server.setName(clientById.getClientId());
server.setAllowRemoteResourceManagement(model.isAllowRemoteResourceManagement());
server.setPolicyEnforcementMode(model.getPolicyEnforcementMode());
return server;
}
public static ResourceServer toModel(ResourceServerRepresentation server, AuthorizationProvider authorization) {
RealmModel realm = authorization.getKeycloakSession().getContext().getRealm();
ClientModel client = realm.getClientById(server.getClientId());
if (client == null) {
throw new ErrorResponseException(ErrorCode.INVALID_CLIENT_ID, "Client with id [" + server.getClientId() + "] not found in realm [" + realm.getName() + "].", Status.BAD_REQUEST);
}
if (!client.isServiceAccountsEnabled()) {
throw new ErrorResponseException(ErrorCode.INVALID_CLIENT_ID, "Client with id [" + server.getClientId() + "] must have a service account.", Status.BAD_REQUEST);
}
ResourceServer existingResourceServer = authorization.getStoreFactory().getResourceServerStore().findByClient(client.getId());
if (existingResourceServer != null) {
throw new ErrorResponseException(ErrorCode.INVALID_CLIENT_ID, "Resource server already exists with client id [" + server.getClientId() + "].", Status.BAD_REQUEST);
}
if (server.getName() == null) {
server.setName(client.getName());
}
ResourceServer model = authorization.getStoreFactory().getResourceServerStore().create(client.getId());
model.setAllowRemoteResourceManagement(server.isAllowRemoteResourceManagement());
model.setPolicyEnforcementMode(server.getPolicyEnforcementMode());
return model;
}
public static PolicyRepresentation toRepresentation(Policy model, AuthorizationProvider authorization) {
PolicyRepresentation representation = new PolicyRepresentation();
representation.setId(model.getId());
representation.setName(model.getName());
representation.setDescription(model.getDescription());
representation.setType(model.getType());
representation.setDecisionStrategy(model.getDecisionStrategy());
representation.setLogic(model.getLogic());
representation.setConfig(new HashMap<>(model.getConfig()));
List<Policy> policies = authorization.getStoreFactory().getPolicyStore().findDependentPolicies(model.getId());
representation.setDependentPolicies(policies.stream().map(policy -> {
PolicyRepresentation representation1 = new PolicyRepresentation();
representation1.setId(policy.getId());
representation1.setName(policy.getName());
return representation1;
}).collect(Collectors.toList()));
List<PolicyRepresentation> associatedPolicies = new ArrayList<>();
List<String> obj = model.getAssociatedPolicies().stream().map(policy -> {
PolicyRepresentation representation1 = new PolicyRepresentation();
representation1.setId(policy.getId());
representation1.setName(policy.getName());
representation1.setType(policy.getType());
associatedPolicies.add(representation1);
return policy.getId();
}).collect(Collectors.toList());
representation.setAssociatedPolicies(associatedPolicies);
try {
representation.getConfig().put("applyPolicies", JsonSerialization.writeValueAsString(obj));
} catch (IOException e) {
e.printStackTrace();
}
return representation;
}
public static Policy toModel(PolicyRepresentation policy, ResourceServer resourceServer, AuthorizationProvider authorizationManager) {
Policy model = authorizationManager.getStoreFactory().getPolicyStore().create(policy.getName(), policy.getType(), resourceServer);
model.setDescription(policy.getDescription());
model.setDecisionStrategy(policy.getDecisionStrategy());
model.setLogic(policy.getLogic());
model.setConfig(policy.getConfig());
return model;
}
public static ResourceRepresentation toRepresentation(Resource model, ResourceServer resourceServer, AuthorizationProvider authorization) {
ResourceRepresentation resource = new ResourceRepresentation();
resource.setId(model.getId());
resource.setType(model.getType());
resource.setName(model.getName());
resource.setUri(model.getUri());
resource.setIconUri(model.getIconUri());
ResourceOwnerRepresentation owner = new ResourceOwnerRepresentation();
owner.setId(model.getOwner());
KeycloakSession keycloakSession = authorization.getKeycloakSession();
RealmModel realm = keycloakSession.getContext().getRealm();
if (owner.getId().equals(resourceServer.getClientId())) {
ClientModel clientModel = realm.getClientById(resourceServer.getClientId());
owner.setName(clientModel.getClientId());
} else {
UserModel userModel = keycloakSession.users().getUserById(owner.getId(), realm);
if (userModel == null) {
throw new ErrorResponseException("invalid_owner", "Could not find the user [" + owner.getId() + "] who owns the Resource [" + resource.getId() + "].", Status.BAD_REQUEST);
}
owner.setName(userModel.getUsername());
}
resource.setOwner(owner);
resource.setScopes(model.getScopes().stream().map(model1 -> {
ScopeRepresentation scope = new ScopeRepresentation();
scope.setId(model1.getId());
scope.setName(model1.getName());
String iconUri = model1.getIconUri();
if (iconUri != null) {
scope.setIconUri(iconUri);
}
return scope;
}).collect(Collectors.toSet()));
resource.setPolicies(new ArrayList<>());
Set<Policy> policies = new HashSet<>();
PolicyStore policyStore = authorization.getStoreFactory().getPolicyStore();
policies.addAll(policyStore.findByResource(resource.getId()));
policies.addAll(policyStore.findByResourceType(resource.getType(), resourceServer.getId()));
policies.addAll(policyStore.findByScopeIds(resource.getScopes().stream().map(scope -> scope.getId()).collect(Collectors.toList()), resourceServer.getId()));
for (Policy policyModel : policies) {
PolicyRepresentation policy = new PolicyRepresentation();
policy.setId(policyModel.getId());
policy.setName(policyModel.getName());
policy.setType(policyModel.getType());
if (!resource.getPolicies().contains(policy)) {
resource.getPolicies().add(policy);
}
}
return resource;
}
public static Resource toModel(ResourceRepresentation resource, ResourceServer resourceServer, AuthorizationProvider authorization) {
ResourceOwnerRepresentation owner = resource.getOwner();
if (owner == null) {
owner = new ResourceOwnerRepresentation();
owner.setId(resourceServer.getClientId());
}
if (owner.getId() == null) {
throw new ErrorResponseException("invalid_owner", "No owner specified for resource [" + resource.getName() + "].", Status.BAD_REQUEST);
}
ResourceStore resourceStore = authorization.getStoreFactory().getResourceStore();
Resource model = resourceStore.create(resource.getName(), resourceServer, owner.getId());
model.setType(resource.getType());
model.setUri(resource.getUri());
model.setIconUri(resource.getIconUri());
Set<ScopeRepresentation> scopes = resource.getScopes();
if (scopes != null) {
model.updateScopes(scopes.stream().map((Function<ScopeRepresentation, Scope>) scope -> toModel(scope, resourceServer, authorization)).collect(Collectors.toSet()));
}
return model;
}
}