/*
* 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.ArrayList;
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 javax.ws.rs.core.UriInfo;
import org.keycloak.events.admin.OperationType;
import org.keycloak.models.ClientModel;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.PartialImportRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.ErrorResponse;
import org.keycloak.services.resources.admin.AdminEventBuilder;
import org.keycloak.services.resources.admin.ClientResource;
import org.keycloak.services.resources.admin.IdentityProviderResource;
import org.keycloak.services.resources.admin.UsersResource;
/**
*
* @author Stan Silvert ssilvert@redhat.com (C) 2015 Red Hat Inc.
*/
public class PartialImportManager {
private List<PartialImport> partialImports = new ArrayList<>();
private final PartialImportRepresentation rep;
private final KeycloakSession session;
private final RealmModel realm;
private final AdminEventBuilder adminEvent;
public PartialImportManager(PartialImportRepresentation rep, KeycloakSession session,
RealmModel realm, AdminEventBuilder adminEvent) {
this.rep = rep;
this.session = session;
this.realm = realm;
this.adminEvent = adminEvent;
// Do not change the order of these!!!
partialImports.add(new ClientsPartialImport());
partialImports.add(new RolesPartialImport());
partialImports.add(new UsersPartialImport());
partialImports.add(new IdentityProvidersPartialImport());
}
public Response saveResources() {
PartialImportResults results = new PartialImportResults();
for (PartialImport partialImport : partialImports) {
try {
partialImport.prepare(rep, realm, session);
} catch (ErrorResponseException error) {
if (session.getTransaction().isActive()) session.getTransaction().setRollbackOnly();
return error.getResponse();
}
}
for (PartialImport partialImport : partialImports) {
try {
results.addAllResults(partialImport.doImport(rep, realm, session));
} catch (ErrorResponseException error) {
if (session.getTransaction().isActive()) session.getTransaction().setRollbackOnly();
return error.getResponse();
}
}
for (PartialImportResult result : results.getResults()) {
switch (result.getAction()) {
case ADDED : addedEvent(result); break;
case OVERWRITTEN: overwrittenEvent(result); break;
}
}
if (session.getTransaction().isActive()) {
session.getTransaction().commit();
}
return Response.ok(results).build();
}
private void addedEvent(PartialImportResult result) {
adminEvent.operation(OperationType.CREATE)
.resourcePath(result.getResourceType().getPath(), result.getId())
.representation(result.getRepresentation())
.success();
};
private void overwrittenEvent(PartialImportResult result) {
adminEvent.operation(OperationType.UPDATE)
.resourcePath(result.getResourceType().getPath(), result.getId())
.representation(result.getRepresentation())
.success();
}
/* Response response = prepareForExistingResources();
if (response != null) return response;
response = saveUsers();
if (response != null) {
session.getTransaction().rollback();
return response;
}
response = saveClients();
if (response != null) {
session.getTransaction().rollback();
return response;
}
response = saveIdps();
if (response != null) {
session.getTransaction().rollback();
return response;
}
if (session.getTransaction().isActive()) {
session.getTransaction().commit();
}
return Response.ok(resultsMap()).build();*/
//}
/*
private Map resultsMap() {
Map<String, Integer> results = new HashMap<>();
results.put("added", added);
results.put("skipped", skipped);
results.put("overwritten", overwritten);
return results;
}
// returns an error response or null
private Response prepareForExistingResources() {
if (rep.hasUsers()) {
Response response = prepareUsers();
if (response != null) return response;
}
if (rep.hasClients()) {
Response response = prepareClients();
if (response != null) return response;
}
if (rep.hasIdps()) {
Response response = prepareIdps();
if (response != null) return response;
}
return null;
}
// returns an error response or null
private Response prepareClients() {
Set<ClientRepresentation> toSkip = new HashSet<>();
for (ClientRepresentation client : rep.getClients()) {
if (clientExists(client)) {
switch (rep.getPolicy()) {
case SKIP: toSkip.addResult(client); break;
case OVERWRITE: clientsToOverwrite.addResult(client); break;
default: return ErrorResponse.exists("Client id '" + client.getClientId() + "' already exists");
}
}
}
for (ClientRepresentation client : toSkip) {
rep.getClients().remove(client);
skipped(client);
}
return null;
}
private boolean clientExists(ClientRepresentation rep) {
return realm.getClientByClientId(rep.getClientId()) != null;
}
// returns an error response or null
private Response saveClients() {
if (!rep.hasClients()) return null;
for (ClientRepresentation client : clientsToOverwrite) {
ClientModel clientModel = realm.getClientByClientId(client.getClientId());
ClientResource.updateClientFromRep(client, clientModel, session);
adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(client).success();
overwritten(client);
}
for (ClientRepresentation client : rep.getClients()) {
if (clientsToOverwrite.contains(client)) continue;
try {
RepresentationToModel.createClient(session, realm, client, true);
added(client);
} catch (Exception e) {
if (session.getTransaction().isActive()) session.getTransaction().setRollbackOnly();
return ErrorResponse.error(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR);
}
}
return null;
}
// returns an error response or null
private Response prepareIdps() {
Set<IdentityProviderRepresentation> toSkip = new HashSet<>();
for (IdentityProviderRepresentation idp : rep.getIdentityProviders()) {
if (idpExists(idp)) {
switch (rep.getPolicy()) {
case SKIP: toSkip.addResult(idp); break;
case OVERWRITE: idpsToOverwrite.addResult(idp); break;
default: return ErrorResponse.exists("Identity Provider '" + idp.getAlias() + "' already exists");
}
}
}
for (IdentityProviderRepresentation idp : toSkip) {
rep.getIdentityProviders().remove(idp);
skipped(idp);
}
return null;
}
private boolean idpExists(IdentityProviderRepresentation rep) {
return realm.getIdentityProviderByAlias(rep.getAlias()) != null;
}
// returns an error response or null
private Response saveIdps() {
if (!rep.hasIdps()) return null;
for (IdentityProviderRepresentation idp : idpsToOverwrite) {
IdentityProviderResource.updateIdpFromRep(idp, realm, session);
overwritten(idp);
}
for (IdentityProviderRepresentation idp : rep.getIdentityProviders()) {
if (idpsToOverwrite.contains(idp)) continue;
try {
IdentityProviderModel identityProvider = RepresentationToModel.toModel(idp);
realm.addIdentityProvider(identityProvider);
added(idp);
} catch (Exception e) {
if (session.getTransaction().isActive()) session.getTransaction().setRollbackOnly();
return ErrorResponse.error(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR);
}
}
return null;
}
// returns an error response or null
private Response prepareUsers() {
Set<UserRepresentation> toSkip = new HashSet<>();
for (UserRepresentation user : rep.getUsers()) {
if (session.users().getUserByUsername(user.getUsername(), realm) != null) {
switch (rep.getPolicy()) {
case SKIP: toSkip.addResult(user); break;
case OVERWRITE: usersToOverwrite.addResult(user); break;
default: return ErrorResponse.exists("User '" + user.getUsername() + "' already exists");
}
}
if ((user.getEmail() != null) && (session.users().getUserByEmail(user.getEmail(), realm) != null)) {
switch (rep.getPolicy()) {
case SKIP: toSkip.addResult(user); break;
case OVERWRITE: usersToOverwrite.addResult(user); break;
default: FAIL: return ErrorResponse.exists("User email '" + user.getEmail() + "' already exists");
}
}
}
for (UserRepresentation user : toSkip) {
rep.getUsers().remove(user);
skipped(user);
}
return null;
}
// returns an error response or null
private Response saveUsers() {
if (!rep.hasUsers()) return null;
for (UserRepresentation user: usersToOverwrite) {
System.out.println("overwriting user " + user.getUsername());
UserModel userModel = session.users().getUserByUsername(user.getUsername(), realm);
UsersResource.updateUserFromRep(userModel, user, null, realm, session);
overwritten(user);
}
for (UserRepresentation user : rep.getUsers()) {
if (usersToOverwrite.contains(user)) continue;
try {
System.out.println("saving user " + user.getUsername());
Map<String, ClientModel> apps = realm.getClientNameMap();
UserModel userModel = RepresentationToModel.createUser(session, realm, user, apps);
added(user);
} catch (Exception e) {
//e.printStackTrace();
if (session.getTransaction().isActive()) session.getTransaction().setRollbackOnly();
return ErrorResponse.error(e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR);
}
}
return null;
}
*/
}