/*
* Copyright 2015 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @author tags. All rights reserved.
*
* 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.partialimport;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.core.Response;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.representations.idm.PartialImportRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.services.ErrorResponse;
/**
*
* @author Stan Silvert ssilvert@redhat.com (C) 2015 Red Hat Inc.
*/
public class ClientRolesPartialImport implements PartialImport {
public Map<String, List<RoleRepresentation>> getRepList(PartialImportRepresentation partialImportRep) {
if (partialImportRep.getRoles() == null) return null;
return partialImportRep.getRoles().getClient();
}
public String getName(RoleRepresentation roleRep) {
if (roleRep.getName() == null)
throw new IllegalStateException("Client role to import does not have a name");
return roleRep.getName();
}
public String getCombinedName(String clientId, RoleRepresentation roleRep) {
return clientId + "-->" + getName(roleRep);
}
public boolean exists(RealmModel realm, KeycloakSession session, String clientId, RoleRepresentation roleRep) {
System.out.println("**** exists *****");
System.out.println("clientId =" + clientId);
ClientModel client = realm.getClientByClientId(clientId);
if (client == null) return false;
System.out.println("client=" + client);
for (RoleModel role : client.getRoles()) {
if (getName(roleRep).equals(role.getName())) return true;
}
return false;
}
public String existsMessage(String clientId, RoleRepresentation roleRep) {
return "Client role '" + getName(roleRep) + "' for client '" + clientId + "' already exists.";
}
public ResourceType getResourceType() {
return ResourceType.CLIENT_ROLE;
}
public void overwrite(RealmModel realm, KeycloakSession session, String clientId, RoleRepresentation roleRep) {
ClientModel client = realm.getClientByClientId(clientId);
checkForComposite(roleRep);
RoleModel role = client.getRole(getName(roleRep));
checkForOverwriteComposite(role);
RealmRolesPartialImport.RoleHelper helper = new RealmRolesPartialImport.RoleHelper(realm);
helper.updateRole(roleRep, role);
}
private void checkForComposite(RoleRepresentation roleRep) {
if (roleRep.isComposite()) {
throw new IllegalArgumentException("Composite role '" + getName(roleRep) + "' can not be partially imported");
}
}
private void checkForOverwriteComposite(RoleModel role) {
if (role.isComposite()) {
throw new IllegalArgumentException("Composite role '" + role.getName() + "' can not be overwritten.");
}
}
public void create(RealmModel realm, KeycloakSession session, String clientId, RoleRepresentation roleRep) {
ClientModel client = realm.getClientByClientId(clientId);
if (client == null) {
throw new IllegalStateException("Client '" + clientId + "' does not exist for client role " + getName(roleRep));
}
checkForComposite(roleRep);
client.addRole(getName(roleRep));
overwrite(realm, session, clientId, roleRep);
}
protected void prepare(PartialImportRepresentation partialImportRep,
RealmModel realm,
KeycloakSession session,
Map<String, Set<RoleRepresentation>> resourcesToOverwrite,
Map<String, Set<RoleRepresentation>> resourcesToSkip) throws ErrorResponseException {
Map<String, List<RoleRepresentation>> repList = getRepList(partialImportRep);
for (String clientId : repList.keySet()) {
resourcesToOverwrite.put(clientId, new HashSet<RoleRepresentation>());
resourcesToSkip.put(clientId, new HashSet<RoleRepresentation>());
for (RoleRepresentation roleRep : repList.get(clientId)) {
if (exists(realm, session, clientId, roleRep)) {
switch (partialImportRep.getPolicy()) {
case SKIP:
resourcesToSkip.get(clientId).add(roleRep);
break;
case OVERWRITE:
resourcesToOverwrite.get(clientId).add(roleRep);
break;
default:
throw exists(existsMessage(clientId, roleRep));
}
}
}
}
}
protected ErrorResponseException exists(String message) {
Response error = ErrorResponse.exists(message);
return new ErrorResponseException(error);
}
protected PartialImportResult overwritten(String clientId, String modelId, RoleRepresentation roleRep) {
return PartialImportResult.overwritten(getResourceType(), getCombinedName(clientId, roleRep), modelId, roleRep);
}
protected PartialImportResult skipped(String clientId, String modelId, RoleRepresentation roleRep) {
return PartialImportResult.skipped(getResourceType(), getCombinedName(clientId, roleRep), modelId, roleRep);
}
protected PartialImportResult added(String clientId, String modelId, RoleRepresentation roleRep) {
return PartialImportResult.added(getResourceType(), getCombinedName(clientId, roleRep), modelId, roleRep);
}
@Override
public PartialImportResults doImport(PartialImportRepresentation partialImportRep, RealmModel realm, KeycloakSession session) throws ErrorResponseException {
PartialImportResults results = new PartialImportResults();
Map<String, List<RoleRepresentation>> repList = getRepList(partialImportRep);
if ((repList == null) || repList.isEmpty()) return results;
final Map<String, Set<RoleRepresentation>> toOverwrite = new HashMap<>();
final Map<String, Set<RoleRepresentation>> toSkip = new HashMap<>();
prepare(partialImportRep, realm, session, toOverwrite, toSkip);
for (String clientId : toOverwrite.keySet()) {
for (RoleRepresentation roleRep : toOverwrite.get(clientId)) {
System.out.println("overwriting " + getResourceType() + " " + getCombinedName(clientId, roleRep));
try {
overwrite(realm, session, clientId, roleRep);
} catch (Exception e) {
throw new ErrorResponseException(ErrorResponse.error(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR));
}
String modelId = getModelId(realm, clientId);
results.addResult(overwritten(clientId, modelId, roleRep));
}
}
for (String clientId : toSkip.keySet()) {
for (RoleRepresentation roleRep : toSkip.get(clientId)) {
System.out.println("skipping " + getResourceType() + " " + getCombinedName(clientId, roleRep));
String modelId = getModelId(realm, clientId);
results.addResult(skipped(clientId, modelId, roleRep));
}
}
for (String clientId : repList.keySet()) {
for (RoleRepresentation roleRep : repList.get(clientId)) {
if (toOverwrite.get(clientId).contains(roleRep)) continue;
if (toSkip.get(clientId).contains(roleRep)) continue;
try {
System.out.println("adding " + getResourceType() + " " + getCombinedName(clientId, roleRep));
create(realm, session, clientId, roleRep);
String modelId = getModelId(realm, clientId);
results.addResult(added(clientId, modelId, roleRep));
} catch (Exception e) {
//e.printStackTrace();
throw new ErrorResponseException(ErrorResponse.error(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR));
}
}
}
return results;
}
private String getModelId(RealmModel realm, String clientId) {
return realm.getClientByClientId(clientId).getId();
}
}