Export/import refactoring to use same representation as admin endpoints
This commit is contained in:
parent
c4ff4e030a
commit
24a492ffe0
79 changed files with 3120 additions and 1103 deletions
|
@ -11,9 +11,16 @@ public class CredentialRepresentation {
|
|||
public static final String CLIENT_CERT = "cert";
|
||||
|
||||
protected String type;
|
||||
protected String value;
|
||||
protected String device;
|
||||
|
||||
// Plain-text value of credential (used for example during import from manually created JSON file)
|
||||
protected String value;
|
||||
|
||||
// Value stored in DB (used for example during export/import)
|
||||
protected String hashedSaltedValue;
|
||||
protected String salt;
|
||||
protected Integer hashIterations;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
@ -37,4 +44,28 @@ public class CredentialRepresentation {
|
|||
public void setDevice(String device) {
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
public String getHashedSaltedValue() {
|
||||
return hashedSaltedValue;
|
||||
}
|
||||
|
||||
public void setHashedSaltedValue(String hashedSaltedValue) {
|
||||
this.hashedSaltedValue = hashedSaltedValue;
|
||||
}
|
||||
|
||||
public String getSalt() {
|
||||
return salt;
|
||||
}
|
||||
|
||||
public void setSalt(String salt) {
|
||||
this.salt = salt;
|
||||
}
|
||||
|
||||
public Integer getHashIterations() {
|
||||
return hashIterations;
|
||||
}
|
||||
|
||||
public void setHashIterations(Integer hashIterations) {
|
||||
this.hashIterations = hashIterations;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import java.util.List;
|
|||
public class OAuthClientRepresentation {
|
||||
protected String id;
|
||||
protected String name;
|
||||
protected String baseUrl;
|
||||
protected List<String> redirectUris;
|
||||
protected List<String> webOrigins;
|
||||
protected Boolean enabled;
|
||||
|
@ -44,14 +43,6 @@ public class OAuthClientRepresentation {
|
|||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getBaseUrl() {
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
public void setBaseUrl(String baseUrl) {
|
||||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
public List<String> getRedirectUris() {
|
||||
return redirectUris;
|
||||
}
|
||||
|
|
|
@ -423,4 +423,28 @@ public class RealmRepresentation {
|
|||
public void setFailureFactor(Integer failureFactor) {
|
||||
this.failureFactor = failureFactor;
|
||||
}
|
||||
|
||||
public boolean isAuditEnabled() {
|
||||
return auditEnabled;
|
||||
}
|
||||
|
||||
public void setAuditEnabled(boolean auditEnabled) {
|
||||
this.auditEnabled = auditEnabled;
|
||||
}
|
||||
|
||||
public long getAuditExpiration() {
|
||||
return auditExpiration;
|
||||
}
|
||||
|
||||
public void setAuditExpiration(long auditExpiration) {
|
||||
this.auditExpiration = auditExpiration;
|
||||
}
|
||||
|
||||
public List<String> getAuditListeners() {
|
||||
return auditListeners;
|
||||
}
|
||||
|
||||
public void setAuditListeners(List<String> auditListeners) {
|
||||
this.auditListeners = auditListeners;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,32 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-invalidation-cache-model</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-core-asl</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-mapper-asl</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.iharder</groupId>
|
||||
<artifactId>base64</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class ExportImportConfig {
|
||||
|
||||
public static final String ACTION = "keycloak.migration.action";
|
||||
public static final String ACTION_EXPORT = "export";
|
||||
public static final String ACTION_IMPORT = "import";
|
||||
|
||||
public static final String PROVIDER = "keycloak.migration.provider";
|
||||
public static final String PROVIDER_DEFAULT = "zip";
|
||||
|
||||
// Name of the realm to export. If null, then full export will be triggered
|
||||
public static final String REALM_NAME = "keycloak.migration.realmName";
|
||||
|
||||
// used for "dir" provider
|
||||
public static final String DIR = "keycloak.migration.dir";
|
||||
// used for "zip" provider
|
||||
public static final String ZIP_FILE = "keycloak.migration.zipFile";
|
||||
public static final String ZIP_PASSWORD = "keycloak.migration.zipPassword";
|
||||
// used for "singleFile" provider
|
||||
public static final String FILE = "keycloak.migration.file";
|
||||
|
||||
// Number of users per file used in "dir" and "zip" providers. -1 means adding users to same file with realm. 0 means adding to separate file with unlimited page number
|
||||
public static final String USERS_PER_FILE = "keycloak.migration.usersPerFile";
|
||||
public static final Integer DEFAULT_USERS_PER_FILE = 5000;
|
||||
|
||||
// Strategy used during import data
|
||||
public static final String STRATEGY = "keycloak.migration.strategy";
|
||||
public static final Strategy DEFAULT_STRATEGY = Strategy.OVERWRITE_EXISTING;
|
||||
|
||||
public static String getAction() {
|
||||
return System.getProperty(ACTION);
|
||||
}
|
||||
|
||||
public static void setAction(String exportImportAction) {
|
||||
System.setProperty(ACTION, exportImportAction);
|
||||
}
|
||||
|
||||
public static String getProvider() {
|
||||
return System.getProperty(PROVIDER, PROVIDER_DEFAULT);
|
||||
}
|
||||
|
||||
public static void setProvider(String exportImportProvider) {
|
||||
System.setProperty(PROVIDER, exportImportProvider);
|
||||
}
|
||||
|
||||
public static String getRealmName() {
|
||||
return System.getProperty(REALM_NAME);
|
||||
}
|
||||
|
||||
public static void setRealmName(String realmName) {
|
||||
if (realmName != null) {
|
||||
System.setProperty(REALM_NAME, realmName);
|
||||
} else {
|
||||
System.getProperties().remove(REALM_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getDir() {
|
||||
return System.getProperty(DIR);
|
||||
}
|
||||
|
||||
public static String setDir(String dir) {
|
||||
return System.setProperty(DIR, dir);
|
||||
}
|
||||
|
||||
public static String getZipFile() {
|
||||
return System.getProperty(ZIP_FILE);
|
||||
}
|
||||
|
||||
public static void setZipFile(String exportImportZipFile) {
|
||||
System.setProperty(ZIP_FILE, exportImportZipFile);
|
||||
}
|
||||
|
||||
public static String getZipPassword() {
|
||||
return System.getProperty(ZIP_PASSWORD);
|
||||
}
|
||||
|
||||
public static void setZipPassword(String exportImportZipPassword) {
|
||||
System.setProperty(ZIP_PASSWORD, exportImportZipPassword);
|
||||
}
|
||||
|
||||
public static String getFile() {
|
||||
return System.getProperty(FILE);
|
||||
}
|
||||
|
||||
public static void setFile(String file) {
|
||||
System.setProperty(FILE, file);
|
||||
}
|
||||
|
||||
public static Integer getUsersPerFile() {
|
||||
String usersPerFile = System.getProperty(USERS_PER_FILE, String.valueOf(DEFAULT_USERS_PER_FILE));
|
||||
return Integer.parseInt(usersPerFile.trim());
|
||||
}
|
||||
|
||||
public static void setUsersPerFile(Integer usersPerFile) {
|
||||
System.setProperty(USERS_PER_FILE, String.valueOf(usersPerFile));
|
||||
}
|
||||
|
||||
public static Strategy getStrategy() {
|
||||
String strategy = System.getProperty(STRATEGY, DEFAULT_STRATEGY.toString());
|
||||
return Enum.valueOf(Strategy.class, strategy);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ExportImportManager {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ExportImportManager.class);
|
||||
|
||||
public void checkExportImport(KeycloakSessionFactory sessionFactory) {
|
||||
String exportImportAction = ExportImportConfig.getAction();
|
||||
String realmName = ExportImportConfig.getRealmName();
|
||||
|
||||
boolean export = false;
|
||||
boolean importt = false;
|
||||
if (ExportImportConfig.ACTION_EXPORT.equals(exportImportAction)) {
|
||||
export = true;
|
||||
} else if (ExportImportConfig.ACTION_IMPORT.equals(exportImportAction)) {
|
||||
importt = true;
|
||||
}
|
||||
|
||||
if (export || importt) {
|
||||
String exportImportProviderId = ExportImportConfig.getProvider();
|
||||
logger.debug("Will use provider: " + exportImportProviderId);
|
||||
KeycloakSession session = sessionFactory.create();
|
||||
|
||||
try {
|
||||
if (export) {
|
||||
ExportProvider exportProvider = session.getProvider(ExportProvider.class, exportImportProviderId);
|
||||
|
||||
if (realmName == null) {
|
||||
logger.info("Full model export requested");
|
||||
exportProvider.exportModel(session);
|
||||
} else {
|
||||
logger.infof("Export of realm '%s' requested", realmName);
|
||||
exportProvider.exportRealm(session, realmName);
|
||||
}
|
||||
logger.info("Export finished successfully");
|
||||
} else {
|
||||
ImportProvider importProvider = session.getProvider(ImportProvider.class, exportImportProviderId);
|
||||
Strategy strategy = ExportImportConfig.getStrategy();
|
||||
if (realmName == null) {
|
||||
logger.infof("Full model import requested. Strategy: %s", strategy.toString());
|
||||
importProvider.importModel(session, strategy);
|
||||
} else {
|
||||
logger.infof("Import of realm '%s' requested. Strategy: %s", realmName, strategy.toString());
|
||||
importProvider.importRealm(session, realmName, strategy);
|
||||
}
|
||||
logger.info("Import finished successfully");
|
||||
}
|
||||
} catch (Throwable ioe) {
|
||||
logger.error("Error during export/import", ioe);
|
||||
} finally {
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public interface ExportImportProvider {
|
||||
|
||||
void checkExportImport(KeycloakSessionFactory sessionFactory);
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.provider.Provider;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public interface ExportProvider extends Provider {
|
||||
|
||||
void exportModel(KeycloakSession session) throws IOException;
|
||||
|
||||
void exportRealm(KeycloakSession session, String realmName) throws IOException;
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public interface ExportProviderFactory extends ProviderFactory<ExportProvider> {
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ExportSpi implements Spi {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "export";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return ExportProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return ExportProviderFactory.class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.provider.Provider;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public interface ImportProvider extends Provider {
|
||||
|
||||
void importModel(KeycloakSession session, Strategy strategy) throws IOException;
|
||||
|
||||
void importRealm(KeycloakSession session, String realmName, Strategy strategy) throws IOException;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public interface ImportProviderFactory extends ProviderFactory<ImportProvider> {
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ImportSpi implements Spi {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "import";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return ImportProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return ImportProviderFactory.class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public enum Strategy {
|
||||
|
||||
IGNORE_EXISTING, // Ignore existing user entries
|
||||
OVERWRITE_EXISTING // Overwrite existing user entries
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package org.keycloak.exportimport.util;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Task to be executed inside transaction
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public interface ExportImportJob {
|
||||
|
||||
public void run() throws IOException;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package org.keycloak.exportimport.util;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakTransaction;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ExportImportUtils {
|
||||
|
||||
/**
|
||||
* Wrap given runnable job into KeycloakTransaction. Assumption is that session already exists and it doesn't need to be closed when finished
|
||||
*
|
||||
* @param session
|
||||
* @param job
|
||||
*/
|
||||
public static void runJobInTransaction(KeycloakSession session, ExportImportJob job) throws IOException {
|
||||
KeycloakTransaction tx = session.getTransaction();
|
||||
try {
|
||||
tx.begin();
|
||||
|
||||
job.run();
|
||||
|
||||
if (tx.isActive()) {
|
||||
if (tx.getRollbackOnly()) {
|
||||
tx.rollback();
|
||||
} else {
|
||||
tx.commit();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (tx.isActive()) {
|
||||
tx.rollback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String getMasterRealmAdminApplicationName(RealmModel realm) {
|
||||
return realm.getName() + "-realm";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,365 @@
|
|||
package org.keycloak.exportimport.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.iharder.Base64;
|
||||
import org.codehaus.jackson.JsonEncoding;
|
||||
import org.codehaus.jackson.JsonFactory;
|
||||
import org.codehaus.jackson.JsonGenerator;
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.codehaus.jackson.map.SerializationConfig;
|
||||
import org.keycloak.exportimport.Strategy;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.AuthenticationLinkModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.OAuthClientModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleContainerModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.SocialLinkModel;
|
||||
import org.keycloak.models.UserCredentialValueModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.representations.idm.ApplicationRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticationLinkRepresentation;
|
||||
import org.keycloak.representations.idm.ClaimRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.OAuthClientRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.representations.idm.RolesRepresentation;
|
||||
import org.keycloak.representations.idm.ScopeMappingRepresentation;
|
||||
import org.keycloak.representations.idm.SocialLinkRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ExportUtils {
|
||||
|
||||
public static RealmRepresentation exportRealm(RealmModel realm, boolean includeUsers) {
|
||||
RealmRepresentation rep = ModelToRepresentation.toRepresentation(realm);
|
||||
|
||||
// Audit
|
||||
rep.setAuditEnabled(realm.isAuditEnabled());
|
||||
if (realm.getAuditExpiration() != 0) {
|
||||
rep.setAuditExpiration(realm.getAuditExpiration());
|
||||
}
|
||||
|
||||
if (realm.getAuditListeners() != null) {
|
||||
rep.setAuditListeners(new LinkedList<String>(realm.getAuditListeners()));
|
||||
}
|
||||
|
||||
// Applications
|
||||
List<ApplicationModel> applications = realm.getApplications();
|
||||
List<ApplicationRepresentation> appReps = new ArrayList<ApplicationRepresentation>();
|
||||
for (ApplicationModel app : applications) {
|
||||
ApplicationRepresentation appRep = exportApplication(app);
|
||||
appReps.add(appRep);
|
||||
}
|
||||
rep.setApplications(appReps);
|
||||
|
||||
// OAuth clients
|
||||
List<OAuthClientModel> oauthClients = realm.getOAuthClients();
|
||||
List<OAuthClientRepresentation> oauthClientReps = new ArrayList<OAuthClientRepresentation>();
|
||||
for (OAuthClientModel oauthClient : oauthClients) {
|
||||
OAuthClientRepresentation clientRep = ModelToRepresentation.toRepresentation(oauthClient);
|
||||
oauthClientReps.add(clientRep);
|
||||
}
|
||||
rep.setOauthClients(oauthClientReps);
|
||||
|
||||
// Roles
|
||||
List<RoleRepresentation> realmRoleReps = null;
|
||||
Map<String, List<RoleRepresentation>> appRolesReps = new HashMap<String, List<RoleRepresentation>>();
|
||||
|
||||
Set<RoleModel> realmRoles = realm.getRoles();
|
||||
if (realmRoles != null && realmRoles.size() > 0) {
|
||||
realmRoleReps = exportRoles(realmRoles);
|
||||
}
|
||||
for (ApplicationModel app : applications) {
|
||||
Set<RoleModel> currentAppRoles = app.getRoles();
|
||||
List<RoleRepresentation> currentAppRoleReps = exportRoles(currentAppRoles);
|
||||
appRolesReps.put(app.getName(), currentAppRoleReps);
|
||||
}
|
||||
|
||||
RolesRepresentation rolesRep = new RolesRepresentation();
|
||||
if (realmRoleReps != null) {
|
||||
rolesRep.setRealm(realmRoleReps);
|
||||
}
|
||||
if (appRolesReps.size() > 0) {
|
||||
rolesRep.setApplication(appRolesReps);
|
||||
}
|
||||
rep.setRoles(rolesRep);
|
||||
|
||||
// Scopes
|
||||
List<ClientModel> allClients = new ArrayList<ClientModel>(applications);
|
||||
allClients.addAll(realm.getOAuthClients());
|
||||
Map<String, List<ScopeMappingRepresentation>> appScopeReps = new HashMap<String, List<ScopeMappingRepresentation>>();
|
||||
|
||||
for (ClientModel client : allClients) {
|
||||
Set<RoleModel> clientScopes = client.getScopeMappings();
|
||||
ScopeMappingRepresentation scopeMappingRep = null;
|
||||
for (RoleModel scope : clientScopes) {
|
||||
if (scope.getContainer() instanceof RealmModel) {
|
||||
if (scopeMappingRep == null) {
|
||||
scopeMappingRep = rep.scopeMapping(client.getClientId());
|
||||
}
|
||||
scopeMappingRep.role(scope.getName());
|
||||
} else {
|
||||
ApplicationModel app = (ApplicationModel)scope.getContainer();
|
||||
String appName = app.getName();
|
||||
List<ScopeMappingRepresentation> currentAppScopes = appScopeReps.get(appName);
|
||||
if (currentAppScopes == null) {
|
||||
currentAppScopes = new ArrayList<ScopeMappingRepresentation>();
|
||||
appScopeReps.put(appName, currentAppScopes);
|
||||
}
|
||||
|
||||
ScopeMappingRepresentation currentClientScope = null;
|
||||
for (ScopeMappingRepresentation scopeMapping : currentAppScopes) {
|
||||
if (scopeMapping.getClient().equals(client.getClientId())) {
|
||||
currentClientScope = scopeMapping;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (currentClientScope == null) {
|
||||
currentClientScope = new ScopeMappingRepresentation();
|
||||
currentClientScope.setClient(client.getClientId());
|
||||
currentAppScopes.add(currentClientScope);
|
||||
}
|
||||
currentClientScope.role(scope.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (appScopeReps.size() > 0) {
|
||||
rep.setApplicationScopeMappings(appScopeReps);
|
||||
}
|
||||
|
||||
// Finally users if needed
|
||||
if (includeUsers) {
|
||||
List<UserModel> allUsers = realm.getUsers();
|
||||
List<UserRepresentation> users = new ArrayList<UserRepresentation>();
|
||||
for (UserModel user : allUsers) {
|
||||
UserRepresentation userRep = exportUser(realm, user);
|
||||
users.add(userRep);
|
||||
}
|
||||
|
||||
if (users.size() > 0) {
|
||||
rep.setUsers(users);
|
||||
}
|
||||
}
|
||||
|
||||
return rep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Full export of application including claims and secret
|
||||
* @param app
|
||||
* @return full ApplicationRepresentation
|
||||
*/
|
||||
public static ApplicationRepresentation exportApplication(ApplicationModel app) {
|
||||
ApplicationRepresentation appRep = ModelToRepresentation.toRepresentation(app);
|
||||
|
||||
appRep.setSecret(app.getSecret());
|
||||
ClaimRepresentation claimRep = ModelToRepresentation.toRepresentation((ClientModel)app);
|
||||
appRep.setClaims(claimRep);
|
||||
return appRep;
|
||||
}
|
||||
|
||||
public static List<RoleRepresentation> exportRoles(Collection<RoleModel> roles) {
|
||||
List<RoleRepresentation> roleReps = new ArrayList<RoleRepresentation>();
|
||||
|
||||
for (RoleModel role : roles) {
|
||||
RoleRepresentation roleRep = exportRole(role);
|
||||
roleReps.add(roleRep);
|
||||
}
|
||||
return roleReps;
|
||||
}
|
||||
|
||||
public static List<String> getRoleNames(Collection<RoleModel> roles) {
|
||||
List<String> roleNames = new ArrayList<String>();
|
||||
for (RoleModel role : roles) {
|
||||
roleNames.add(role.getName());
|
||||
}
|
||||
return roleNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Full export of role including composite roles
|
||||
* @param role
|
||||
* @return RoleRepresentation with all stuff filled (including composite roles)
|
||||
*/
|
||||
public static RoleRepresentation exportRole(RoleModel role) {
|
||||
RoleRepresentation roleRep = ModelToRepresentation.toRepresentation(role);
|
||||
|
||||
Set<RoleModel> composites = role.getComposites();
|
||||
if (composites != null && composites.size() > 0) {
|
||||
Set<String> compositeRealmRoles = null;
|
||||
Map<String, List<String>> compositeAppRoles = null;
|
||||
|
||||
for (RoleModel composite : composites) {
|
||||
RoleContainerModel crContainer = composite.getContainer();
|
||||
if (crContainer instanceof RealmModel) {
|
||||
|
||||
if (compositeRealmRoles == null) {
|
||||
compositeRealmRoles = new HashSet<String>();
|
||||
}
|
||||
compositeRealmRoles.add(composite.getName());
|
||||
} else {
|
||||
if (compositeAppRoles == null) {
|
||||
compositeAppRoles = new HashMap<String, List<String>>();
|
||||
}
|
||||
|
||||
ApplicationModel app = (ApplicationModel)crContainer;
|
||||
String appName = app.getName();
|
||||
List<String> currentAppComposites = compositeAppRoles.get(appName);
|
||||
if (currentAppComposites == null) {
|
||||
currentAppComposites = new ArrayList<String>();
|
||||
compositeAppRoles.put(appName, currentAppComposites);
|
||||
}
|
||||
currentAppComposites.add(composite.getName());
|
||||
}
|
||||
}
|
||||
|
||||
RoleRepresentation.Composites compRep = new RoleRepresentation.Composites();
|
||||
if (compositeRealmRoles != null) {
|
||||
compRep.setRealm(compositeRealmRoles);
|
||||
}
|
||||
if (compositeAppRoles != null) {
|
||||
compRep.setApplication(compositeAppRoles);
|
||||
}
|
||||
|
||||
roleRep.setComposites(compRep);
|
||||
}
|
||||
|
||||
return roleRep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Full export of user (including role mappings and credentials)
|
||||
*
|
||||
* @param user
|
||||
* @return fully exported user representation
|
||||
*/
|
||||
public static UserRepresentation exportUser(RealmModel realm, UserModel user) {
|
||||
UserRepresentation userRep = ModelToRepresentation.toRepresentation(user);
|
||||
|
||||
// AuthenticationLink
|
||||
AuthenticationLinkModel authLink = user.getAuthenticationLink();
|
||||
if (authLink != null) {
|
||||
AuthenticationLinkRepresentation authLinkRepresentation = exportAuthLink(authLink);
|
||||
userRep.setAuthenticationLink(authLinkRepresentation);
|
||||
}
|
||||
|
||||
// Social links
|
||||
Set<SocialLinkModel> socialLinks = realm.getSocialLinks(user);
|
||||
List<SocialLinkRepresentation> socialLinkReps = new ArrayList<SocialLinkRepresentation>();
|
||||
for (SocialLinkModel socialLink : socialLinks) {
|
||||
SocialLinkRepresentation socialLinkRep = exportSocialLink(socialLink);
|
||||
socialLinkReps.add(socialLinkRep);
|
||||
}
|
||||
if (socialLinkReps.size() > 0) {
|
||||
userRep.setSocialLinks(socialLinkReps);
|
||||
}
|
||||
|
||||
// Role mappings
|
||||
Set<RoleModel> roles = user.getRoleMappings();
|
||||
List<String> realmRoleNames = new ArrayList<String>();
|
||||
Map<String, List<String>> appRoleNames = new HashMap<String, List<String>>();
|
||||
for (RoleModel role : roles) {
|
||||
if (role.getContainer() instanceof RealmModel) {
|
||||
realmRoleNames.add(role.getName());
|
||||
} else {
|
||||
ApplicationModel app = (ApplicationModel)role.getContainer();
|
||||
String appName = app.getName();
|
||||
List<String> currentAppRoles = appRoleNames.get(appName);
|
||||
if (currentAppRoles == null) {
|
||||
currentAppRoles = new ArrayList<String>();
|
||||
appRoleNames.put(appName, currentAppRoles);
|
||||
}
|
||||
|
||||
currentAppRoles.add(role.getName());
|
||||
}
|
||||
}
|
||||
|
||||
if (realmRoleNames.size() > 0) {
|
||||
userRep.setRealmRoles(realmRoleNames);
|
||||
}
|
||||
if (appRoleNames.size() > 0) {
|
||||
userRep.setApplicationRoles(appRoleNames);
|
||||
}
|
||||
|
||||
// Credentials
|
||||
List<UserCredentialValueModel> creds = user.getCredentialsDirectly();
|
||||
List<CredentialRepresentation> credReps = new ArrayList<CredentialRepresentation>();
|
||||
for (UserCredentialValueModel cred : creds) {
|
||||
CredentialRepresentation credRep = exportCredential(cred);
|
||||
credReps.add(credRep);
|
||||
}
|
||||
userRep.setCredentials(credReps);
|
||||
|
||||
return userRep;
|
||||
}
|
||||
|
||||
public static AuthenticationLinkRepresentation exportAuthLink(AuthenticationLinkModel authLinkModel) {
|
||||
AuthenticationLinkRepresentation authLinkRep = new AuthenticationLinkRepresentation();
|
||||
authLinkRep.setAuthProvider(authLinkModel.getAuthProvider());
|
||||
authLinkRep.setAuthUserId(authLinkModel.getAuthUserId());
|
||||
return authLinkRep;
|
||||
}
|
||||
|
||||
public static SocialLinkRepresentation exportSocialLink(SocialLinkModel socialLink) {
|
||||
SocialLinkRepresentation socialLinkRep = new SocialLinkRepresentation();
|
||||
socialLinkRep.setSocialProvider(socialLink.getSocialProvider());
|
||||
socialLinkRep.setSocialUserId(socialLink.getSocialUserId());
|
||||
socialLinkRep.setSocialUsername(socialLink.getSocialUsername());
|
||||
return socialLinkRep;
|
||||
}
|
||||
|
||||
public static CredentialRepresentation exportCredential(UserCredentialValueModel userCred) {
|
||||
CredentialRepresentation credRep = new CredentialRepresentation();
|
||||
credRep.setType(userCred.getType());
|
||||
credRep.setDevice(userCred.getDevice());
|
||||
credRep.setHashedSaltedValue(userCred.getValue());
|
||||
credRep.setSalt(Base64.encodeBytes(userCred.getSalt()));
|
||||
credRep.setHashIterations(userCred.getHashIterations());
|
||||
return credRep;
|
||||
}
|
||||
|
||||
// Streaming API
|
||||
|
||||
public static void exportUsersToStream(RealmModel realm, List<UserModel> usersToExport, ObjectMapper mapper, OutputStream os) throws IOException {
|
||||
JsonFactory factory = mapper.getJsonFactory();
|
||||
JsonGenerator generator = factory.createJsonGenerator(os, JsonEncoding.UTF8);
|
||||
try {
|
||||
if (mapper.isEnabled(SerializationConfig.Feature.INDENT_OUTPUT)) {
|
||||
generator.useDefaultPrettyPrinter();
|
||||
}
|
||||
generator.writeStartObject();
|
||||
generator.writeStringField("realm", realm.getName());
|
||||
// generator.writeStringField("strategy", strategy.toString());
|
||||
generator.writeFieldName("users");
|
||||
generator.writeStartArray();
|
||||
|
||||
for (UserModel user : usersToExport) {
|
||||
UserRepresentation userRep = ExportUtils.exportUser(realm, user);
|
||||
generator.writeObject(userRep);
|
||||
}
|
||||
|
||||
generator.writeEndArray();
|
||||
generator.writeEndObject();
|
||||
} finally {
|
||||
generator.close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
package org.keycloak.exportimport.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.codehaus.jackson.JsonEncoding;
|
||||
import org.codehaus.jackson.JsonFactory;
|
||||
import org.codehaus.jackson.JsonGenerator;
|
||||
import org.codehaus.jackson.JsonParser;
|
||||
import org.codehaus.jackson.JsonToken;
|
||||
import org.codehaus.jackson.io.SerializedString;
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.exportimport.Strategy;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelProvider;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ImportUtils {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ImportUtils.class);
|
||||
|
||||
/**
|
||||
* Fully import realm from representation, save it to model and return model of newly created realm
|
||||
*
|
||||
* @param session
|
||||
* @param rep
|
||||
* @param strategy specifies whether to overwrite or ignore existing realm or user entries
|
||||
* @return newly imported realm (or existing realm if ignoreExisting is true and realm of this name already exists)
|
||||
*/
|
||||
public static RealmModel importRealm(KeycloakSession session, RealmRepresentation rep, Strategy strategy) {
|
||||
String realmName = rep.getRealm();
|
||||
ModelProvider model = session.getModel();
|
||||
RealmModel realm = model.getRealmByName(realmName);
|
||||
|
||||
if (realm != null) {
|
||||
if (strategy == Strategy.IGNORE_EXISTING) {
|
||||
logger.infof("Realm '%s' already exists. Import skipped", realmName);
|
||||
return realm;
|
||||
} else {
|
||||
logger.infof("Realm '%s' already exists. Removing it before import", realmName);
|
||||
model.removeRealm(realm.getId());
|
||||
}
|
||||
}
|
||||
|
||||
realm = rep.getId() != null ? model.createRealm(rep.getId(), realmName) : model.createRealm(realmName);
|
||||
|
||||
RepresentationToModel.importRealm(rep, realm);
|
||||
|
||||
refreshMasterAdminApps(model, realm);
|
||||
|
||||
logger.infof("Realm '%s' imported", realmName);
|
||||
return realm;
|
||||
}
|
||||
|
||||
private static void refreshMasterAdminApps(ModelProvider model, RealmModel realm) {
|
||||
String adminRealmId = Config.getAdminRealm();
|
||||
if (adminRealmId.equals(realm.getId())) {
|
||||
// We just imported master realm. All 'masterAdminApps' need to be refreshed
|
||||
RealmModel adminRealm = realm;
|
||||
for (RealmModel currentRealm : model.getRealms()) {
|
||||
ApplicationModel masterApp = adminRealm.getApplicationByName(ExportImportUtils.getMasterRealmAdminApplicationName(currentRealm));
|
||||
currentRealm.setMasterAdminApp(masterApp);
|
||||
}
|
||||
} else {
|
||||
// Need to refresh masterApp for current realm
|
||||
RealmModel adminRealm = model.getRealm(adminRealmId);
|
||||
ApplicationModel masterApp = adminRealm.getApplicationByName(ExportImportUtils.getMasterRealmAdminApplicationName(realm));
|
||||
realm.setMasterAdminApp(masterApp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fully import realm (or more realms from particular stream)
|
||||
*
|
||||
* @param session
|
||||
* @param mapper
|
||||
* @param is
|
||||
* @param strategy
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void importFromStream(KeycloakSession session, ObjectMapper mapper, InputStream is, Strategy strategy) throws IOException {
|
||||
JsonFactory factory = mapper.getJsonFactory();
|
||||
JsonParser parser = factory.createJsonParser(is);
|
||||
try {
|
||||
parser.nextToken();
|
||||
|
||||
if (parser.getCurrentToken() == JsonToken.START_ARRAY) {
|
||||
// Case with more realms in stream
|
||||
parser.nextToken();
|
||||
while (parser.getCurrentToken() == JsonToken.START_OBJECT) {
|
||||
RealmRepresentation realmRep = parser.readValueAs(RealmRepresentation.class);
|
||||
parser.nextToken();
|
||||
importRealm(session, realmRep, strategy);
|
||||
}
|
||||
} else if (parser.getCurrentToken() == JsonToken.START_OBJECT) {
|
||||
// Case with single realm in stream
|
||||
RealmRepresentation realmRep = parser.readValueAs(RealmRepresentation.class);
|
||||
importRealm(session, realmRep, strategy);
|
||||
}
|
||||
} finally {
|
||||
parser.close();
|
||||
}
|
||||
}
|
||||
|
||||
// Assuming that it's invoked inside transaction
|
||||
public static void importUsersFromStream(KeycloakSession session, String realmName, ObjectMapper mapper, InputStream is) throws IOException {
|
||||
ModelProvider model = session.getModel();
|
||||
JsonFactory factory = mapper.getJsonFactory();
|
||||
JsonParser parser = factory.createJsonParser(is);
|
||||
try {
|
||||
parser.nextToken();
|
||||
|
||||
while (parser.nextToken() == JsonToken.FIELD_NAME) {
|
||||
if ("realm".equals(parser.getText())) {
|
||||
parser.nextToken();
|
||||
String currRealmName = parser.getText();
|
||||
if (!currRealmName.equals(realmName)) {
|
||||
throw new IllegalStateException("Trying to import users into invalid realm. Realm name: " + realmName + ", Expected realm name: " + realmName);
|
||||
}
|
||||
} else if ("users".equals(parser.getText())) {
|
||||
parser.nextToken();
|
||||
|
||||
if (parser.getCurrentToken() == JsonToken.START_ARRAY) {
|
||||
parser.nextToken();
|
||||
}
|
||||
|
||||
// TODO: support for more transactions per single users file (if needed)
|
||||
List<UserRepresentation> userReps = new ArrayList<UserRepresentation>();
|
||||
while (parser.getCurrentToken() == JsonToken.START_OBJECT) {
|
||||
UserRepresentation user = parser.readValueAs(UserRepresentation.class);
|
||||
userReps.add(user);
|
||||
parser.nextToken();
|
||||
}
|
||||
|
||||
importUsers(model, realmName, userReps);
|
||||
|
||||
if (parser.getCurrentToken() == JsonToken.END_ARRAY) {
|
||||
parser.nextToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
parser.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void importUsers(ModelProvider model, String realmName, List<UserRepresentation> userReps) {
|
||||
RealmModel realm = model.getRealmByName(realmName);
|
||||
Map<String, ApplicationModel> apps = realm.getApplicationNameMap();
|
||||
for (UserRepresentation user : userReps) {
|
||||
RepresentationToModel.createUser(realm, user, apps);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
package org.keycloak.exportimport.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.exportimport.ExportImportConfig;
|
||||
import org.keycloak.exportimport.ExportProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public abstract class MultipleStepsExportProvider implements ExportProvider {
|
||||
|
||||
protected final Logger logger = Logger.getLogger(getClass());
|
||||
|
||||
@Override
|
||||
public void exportModel(final KeycloakSession session) throws IOException {
|
||||
final RealmsHolder holder = new RealmsHolder();
|
||||
|
||||
// Import users into same file with realm
|
||||
ExportImportUtils.runJobInTransaction(session, new ExportImportJob() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
List<RealmModel> realms = session.getModel().getRealms();
|
||||
holder.realms = realms;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
for (RealmModel realm : holder.realms) {
|
||||
exportRealm(session, realm.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportRealm(final KeycloakSession session, final String realmName) throws IOException {
|
||||
final int usersPerFile = ExportImportConfig.getUsersPerFile();
|
||||
final UsersHolder usersHolder = new UsersHolder();
|
||||
final boolean exportUsersIntoSameFile = usersPerFile < 0;
|
||||
|
||||
ExportImportUtils.runJobInTransaction(session, new ExportImportJob() {
|
||||
|
||||
@Override
|
||||
public void run() throws IOException {
|
||||
RealmModel realm = session.getModel().getRealmByName(realmName);
|
||||
RealmRepresentation rep = ExportUtils.exportRealm(realm, exportUsersIntoSameFile);
|
||||
writeRealm(realmName + "-realm.json", rep);
|
||||
logger.info("Realm '" + realmName + "' - data exported");
|
||||
|
||||
// Count total number of users
|
||||
if (!exportUsersIntoSameFile) {
|
||||
// TODO: getUsersCount method on model
|
||||
usersHolder.totalCount = realm.getUsers().size();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if (!exportUsersIntoSameFile) {
|
||||
|
||||
usersHolder.currentPageStart = 0;
|
||||
|
||||
// usersPerFile==0 means exporting all users into single file (but separate to realm)
|
||||
final int countPerPage = usersPerFile == 0 ? usersHolder.totalCount : usersPerFile;
|
||||
|
||||
while (usersHolder.currentPageStart < usersHolder.totalCount) {
|
||||
if (usersHolder.currentPageStart + countPerPage < usersHolder.totalCount) {
|
||||
usersHolder.currentPageEnd = usersHolder.currentPageStart + countPerPage;
|
||||
} else {
|
||||
usersHolder.currentPageEnd = usersHolder.totalCount;
|
||||
}
|
||||
|
||||
ExportImportUtils.runJobInTransaction(session, new ExportImportJob() {
|
||||
|
||||
@Override
|
||||
public void run() throws IOException {
|
||||
RealmModel realm = session.getModel().getRealmByName(realmName);
|
||||
// TODO: pagination
|
||||
List<UserModel> users = realm.getUsers();
|
||||
usersHolder.users = users.subList(usersHolder.currentPageStart, usersHolder.currentPageEnd);
|
||||
|
||||
writeUsers(realmName + "-users-" + (usersHolder.currentPageStart / countPerPage) + ".json", realm, usersHolder.users);
|
||||
|
||||
logger.info("Users " + usersHolder.currentPageStart + "-" + usersHolder.currentPageEnd + " exported");
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
usersHolder.currentPageStart = usersHolder.currentPageEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void writeRealm(String fileName, RealmRepresentation rep) throws IOException;
|
||||
|
||||
protected abstract void writeUsers(String fileName, RealmModel realm, List<UserModel> users) throws IOException;
|
||||
|
||||
public static class RealmsHolder {
|
||||
List<RealmModel> realms;
|
||||
|
||||
}
|
||||
|
||||
public static class UsersHolder {
|
||||
List<UserModel> users;
|
||||
int totalCount;
|
||||
int currentPageStart;
|
||||
int currentPageEnd;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
org.keycloak.exportimport.ExportSpi
|
||||
org.keycloak.exportimport.ImportSpi
|
66
export-import/export-import-dir/pom.xml
Normal file
66
export-import/export-import-dir/pom.xml
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>keycloak-export-import-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-export-import-dir</artifactId>
|
||||
<name>Keycloak Export Import To Directory</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-export-import-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-core-asl</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-mapper-asl</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,73 @@
|
|||
package org.keycloak.exportimport.dir;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.keycloak.exportimport.util.ExportUtils;
|
||||
import org.keycloak.exportimport.util.MultipleStepsExportProvider;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class DirExportProvider extends MultipleStepsExportProvider {
|
||||
|
||||
private final File rootDirectory;
|
||||
|
||||
public DirExportProvider() {
|
||||
// Determine system tmp directory
|
||||
String tempDir = System.getProperty("java.io.tmpdir");
|
||||
|
||||
this.rootDirectory = new File(tempDir + "/keycloak-export");
|
||||
this.rootDirectory.mkdirs();
|
||||
|
||||
logger.infof("Exporting into directory %s", this.rootDirectory.getAbsolutePath());
|
||||
}
|
||||
|
||||
public DirExportProvider(File rootDirectory) {
|
||||
this.rootDirectory = rootDirectory;
|
||||
this.rootDirectory.mkdirs();
|
||||
|
||||
logger.infof("Exporting into directory %s", this.rootDirectory.getAbsolutePath());
|
||||
}
|
||||
|
||||
public static boolean recursiveDeleteDir(File dirPath) {
|
||||
if (dirPath.exists()) {
|
||||
File[] files = dirPath.listFiles();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
if (files[i].isDirectory()) {
|
||||
recursiveDeleteDir(files[i]);
|
||||
} else {
|
||||
files[i].delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dirPath.exists())
|
||||
return dirPath.delete();
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeRealm(String fileName, RealmRepresentation rep) throws IOException {
|
||||
File file = new File(this.rootDirectory, fileName);
|
||||
FileOutputStream stream = new FileOutputStream(file);
|
||||
JsonSerialization.prettyMapper.writeValue(stream, rep);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeUsers(String fileName, RealmModel realm, List<UserModel> users) throws IOException {
|
||||
File file = new File(this.rootDirectory, fileName);
|
||||
FileOutputStream os = new FileOutputStream(file);
|
||||
ExportUtils.exportUsersToStream(realm, users, JsonSerialization.prettyMapper, os);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package org.keycloak.exportimport.dir;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.exportimport.ExportImportConfig;
|
||||
import org.keycloak.exportimport.ExportProvider;
|
||||
import org.keycloak.exportimport.ExportProviderFactory;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class DirExportProviderFactory implements ExportProviderFactory {
|
||||
|
||||
public static final String PROVIDER_ID = "dir";
|
||||
|
||||
@Override
|
||||
public ExportProvider create(KeycloakSession session) {
|
||||
String dir = ExportImportConfig.getDir();
|
||||
return dir!=null ? new DirExportProvider(new File(dir)) : new DirExportProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package org.keycloak.exportimport.dir;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.exportimport.ExportImportConfig;
|
||||
import org.keycloak.exportimport.ImportProvider;
|
||||
import org.keycloak.exportimport.Strategy;
|
||||
import org.keycloak.exportimport.util.ExportImportJob;
|
||||
import org.keycloak.exportimport.util.ExportImportUtils;
|
||||
import org.keycloak.exportimport.util.ImportUtils;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class DirImportProvider implements ImportProvider {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DirImportProvider.class);
|
||||
|
||||
private final File rootDirectory;
|
||||
|
||||
public DirImportProvider() {
|
||||
// Determine system tmp directory
|
||||
String tempDir = System.getProperty("java.io.tmpdir");
|
||||
|
||||
// Delete and recreate directory inside tmp
|
||||
this.rootDirectory = new File(tempDir + "/keycloak-export");
|
||||
if (!this.rootDirectory .exists()) {
|
||||
throw new IllegalStateException("Directory " + this.rootDirectory + " doesn't exists");
|
||||
}
|
||||
|
||||
logger.infof("Importing from directory %s", this.rootDirectory.getAbsolutePath());
|
||||
}
|
||||
|
||||
public DirImportProvider(File rootDirectory) {
|
||||
this.rootDirectory = rootDirectory;
|
||||
|
||||
logger.infof("Importing from directory %s", this.rootDirectory.getAbsolutePath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importModel(KeycloakSession session, Strategy strategy) throws IOException {
|
||||
File[] realmFiles = this.rootDirectory.listFiles(new FilenameFilter() {
|
||||
|
||||
@Override
|
||||
public boolean accept(File dir, String name) {
|
||||
return (name.endsWith("-realm.json"));
|
||||
}
|
||||
});
|
||||
|
||||
for (File file : realmFiles) {
|
||||
String fileName = file.getName();
|
||||
|
||||
// Parse "foo" from "foo-realm.json"
|
||||
String realmName = fileName.substring(0, fileName.length() - 11);
|
||||
importRealm(session, realmName, strategy);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importRealm(final KeycloakSession session, final String realmName, final Strategy strategy) throws IOException {
|
||||
File realmFile = new File(this.rootDirectory + File.separator + realmName + "-realm.json");
|
||||
File[] userFiles = this.rootDirectory.listFiles(new FilenameFilter() {
|
||||
|
||||
@Override
|
||||
public boolean accept(File dir, String name) {
|
||||
return (name.startsWith(realmName)) && (name.endsWith(".json")) && (name.substring(realmName.length()).contains("-users-") );
|
||||
}
|
||||
});
|
||||
|
||||
// Import realm first
|
||||
FileInputStream is = new FileInputStream(realmFile);
|
||||
final RealmRepresentation realmRep = JsonSerialization.readValue(is, RealmRepresentation.class);
|
||||
|
||||
ExportImportUtils.runJobInTransaction(session, new ExportImportJob() {
|
||||
|
||||
@Override
|
||||
public void run() throws IOException {
|
||||
ImportUtils.importRealm(session, realmRep, strategy);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Import users
|
||||
for (File userFile : userFiles) {
|
||||
final FileInputStream fis = new FileInputStream(userFile);
|
||||
ExportImportUtils.runJobInTransaction(session, new ExportImportJob() {
|
||||
|
||||
@Override
|
||||
public void run() throws IOException {
|
||||
ImportUtils.importUsersFromStream(session, realmName, JsonSerialization.mapper, fis);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package org.keycloak.exportimport.dir;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.exportimport.ExportImportConfig;
|
||||
import org.keycloak.exportimport.ImportProvider;
|
||||
import org.keycloak.exportimport.ImportProviderFactory;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class DirImportProviderFactory implements ImportProviderFactory {
|
||||
|
||||
@Override
|
||||
public ImportProvider create(KeycloakSession session) {
|
||||
String dir = ExportImportConfig.getDir();
|
||||
return dir!=null ? new DirImportProvider(new File(dir)) : new DirImportProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return DirExportProviderFactory.PROVIDER_ID;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.keycloak.exportimport.dir.DirExportProviderFactory
|
|
@ -0,0 +1 @@
|
|||
org.keycloak.exportimport.dir.DirImportProviderFactory
|
|
@ -1,58 +0,0 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class ExportImportConfig {
|
||||
|
||||
public static final String ACTION = "keycloak.migration.action";
|
||||
public static final String PROVIDER = "keycloak.migration.provider";
|
||||
public static final String PROVIDER_DEFAULT = "zip";
|
||||
|
||||
// used for "directory" provider
|
||||
public static final String DIR = "keycloak.migration.dir";
|
||||
// used for "zip" provider
|
||||
public static final String FILE = "keycloak.migration.zipFile";
|
||||
public static final String PASSWORD = "keycloak.migration.zipPassword";
|
||||
|
||||
public static String getAction() {
|
||||
return System.getProperty(ACTION);
|
||||
}
|
||||
|
||||
public static void setAction(String exportImportAction) {
|
||||
System.setProperty(ACTION, exportImportAction);
|
||||
}
|
||||
|
||||
public static String getProvider() {
|
||||
return System.getProperty(PROVIDER, PROVIDER_DEFAULT);
|
||||
}
|
||||
|
||||
public static void setProvider(String exportImportProvider) {
|
||||
System.setProperty(PROVIDER, exportImportProvider);
|
||||
}
|
||||
|
||||
public static String getDir() {
|
||||
return System.getProperty(DIR);
|
||||
}
|
||||
|
||||
public static String setDir(String dir) {
|
||||
return System.setProperty(DIR, dir);
|
||||
}
|
||||
|
||||
public static String getZipFile() {
|
||||
return System.getProperty(FILE);
|
||||
}
|
||||
|
||||
public static void setZipFile(String exportImportZipFile) {
|
||||
System.setProperty(FILE, exportImportZipFile);
|
||||
}
|
||||
|
||||
public static String getZipPassword() {
|
||||
return System.getProperty(PASSWORD);
|
||||
}
|
||||
|
||||
public static void setZipPassword(String exportImportZipPassword) {
|
||||
System.setProperty(PASSWORD, exportImportZipPassword);
|
||||
}
|
||||
|
||||
}
|
|
@ -12,14 +12,13 @@ import org.keycloak.util.ProviderLoader;
|
|||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ExportImportProviderImpl implements ExportImportProvider {
|
||||
public class ExportImportProviderImpl {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ExportImportProviderImpl.class);
|
||||
|
||||
public static final String ACTION_EXPORT = "export";
|
||||
public static final String ACTION_IMPORT = "import";
|
||||
|
||||
@Override
|
||||
public void checkExportImport(KeycloakSessionFactory sessionFactory) {
|
||||
String exportImportAction = ExportImportConfig.getAction();
|
||||
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ExportImportUtils {
|
||||
|
||||
public RealmRepresentation exportRealm(RealmModel realm, boolean includeUsers) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public RealmRepresentation exportUsers(RealmModel realm, int start, int count) {
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
package org.keycloak.exportimport;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.model.test.AbstractModelTest;
|
||||
import org.keycloak.model.test.ImportTest;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.services.managers.ApplianceBootstrap;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.resources.KeycloakApplication;
|
||||
import org.keycloak.util.ProviderLoader;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public abstract class ExportImportTestBase {
|
||||
|
||||
protected KeycloakSessionFactory factory;
|
||||
|
||||
protected KeycloakSession session;
|
||||
protected RealmManager realmManager;
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
System.getProperties().remove("keycloak.model.provider");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExportImport() throws Exception {
|
||||
// Init JPA model
|
||||
System.setProperty("keycloak.model.provider", getExportModelProvider());
|
||||
factory = KeycloakApplication.createSessionFactory();
|
||||
|
||||
// Bootstrap admin realm
|
||||
beginTransaction();
|
||||
new ApplianceBootstrap().bootstrap(session, "/auth");
|
||||
commitTransaction();
|
||||
|
||||
// Classic import of realm to JPA model
|
||||
beginTransaction();
|
||||
RealmRepresentation rep = AbstractModelTest.loadJson("testrealm.json");
|
||||
realmManager = new RealmManager(session);
|
||||
RealmModel realm = realmManager.createRealm("demo", rep.getRealm());
|
||||
realmManager.importRealm(rep, realm);
|
||||
|
||||
commitTransaction();
|
||||
|
||||
// Full export of realm
|
||||
exportModel(factory);
|
||||
|
||||
beginTransaction();
|
||||
realm = session.model().getRealm("demo");
|
||||
String wburkeId = realm.getUser("wburke").getId();
|
||||
String appId = realm.getApplicationByName("Application").getId();
|
||||
|
||||
// Commit transaction and close JPA now
|
||||
commitTransaction();
|
||||
factory.close();
|
||||
|
||||
// Bootstrap mongo session and factory
|
||||
System.setProperty("keycloak.model.provider", getImportModelProvider());
|
||||
factory = KeycloakApplication.createSessionFactory();
|
||||
|
||||
// Full import of previous export into mongo
|
||||
importModel(factory);
|
||||
|
||||
// Verify it's imported in mongo (reusing ImportTest)
|
||||
beginTransaction();
|
||||
RealmModel importedRealm = session.model().getRealm("demo");
|
||||
System.out.println("Exported realm: " + realm + ", Imported realm: " + importedRealm);
|
||||
|
||||
Assert.assertEquals(wburkeId, importedRealm.getUser("wburke").getId());
|
||||
Assert.assertEquals(appId, importedRealm.getApplicationByName("Application").getId());
|
||||
ImportTest.assertDataImportedInRealm(importedRealm);
|
||||
|
||||
// Commit and close Mongo
|
||||
commitTransaction();
|
||||
factory.close();
|
||||
}
|
||||
|
||||
protected abstract String getExportModelProvider();
|
||||
|
||||
protected abstract String getImportModelProvider();
|
||||
|
||||
protected abstract void exportModel(KeycloakSessionFactory factory);
|
||||
|
||||
protected abstract void importModel(KeycloakSessionFactory factory);
|
||||
|
||||
protected void beginTransaction() {
|
||||
session = factory.create();
|
||||
session.getTransaction().begin();
|
||||
realmManager = new RealmManager(session);
|
||||
}
|
||||
|
||||
protected void commitTransaction() {
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
}
|
||||
|
||||
protected ExportImportProvider getExportImportProvider() {
|
||||
Iterator<ExportImportProvider> providers = ProviderLoader.load(ExportImportProvider.class).iterator();
|
||||
|
||||
if (providers.hasNext()) {
|
||||
return providers.next();
|
||||
} else {
|
||||
throw new IllegalStateException("ExportImportProvider not found");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,29 +10,5 @@ import org.keycloak.models.KeycloakSessionFactory;
|
|||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
@Ignore
|
||||
public class JPAToMongoExportImportTest extends ExportImportTestBase {
|
||||
|
||||
@Override
|
||||
protected String getExportModelProvider() {
|
||||
return "jpa";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getImportModelProvider() {
|
||||
return "mongo";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exportModel(KeycloakSessionFactory factory) {
|
||||
ExportImportConfig.setAction(ExportImportProviderImpl.ACTION_EXPORT);
|
||||
ExportImportConfig.setProvider(TmpDirExportImportIOProvider.PROVIDER_ID);
|
||||
getExportImportProvider().checkExportImport(factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void importModel(KeycloakSessionFactory factory) {
|
||||
ExportImportConfig.setAction(ExportImportProviderImpl.ACTION_IMPORT);
|
||||
ExportImportConfig.setProvider(TmpDirExportImportIOProvider.PROVIDER_ID);
|
||||
getExportImportProvider().checkExportImport(factory);
|
||||
}
|
||||
public class JPAToMongoExportImportTest {
|
||||
}
|
||||
|
|
|
@ -13,59 +13,5 @@ import java.io.File;
|
|||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
@Ignore
|
||||
public class MongoToJPAExportImportTest extends ExportImportTestBase {
|
||||
|
||||
private static final String zipFile = "keycloak-export.zip";
|
||||
|
||||
@Override
|
||||
protected String getExportModelProvider() {
|
||||
return "mongo";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getImportModelProvider() {
|
||||
return "jpa";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exportModel(KeycloakSessionFactory factory) {
|
||||
ExportImportConfig.setAction(ExportImportProviderImpl.ACTION_EXPORT);
|
||||
ExportImportConfig.setProvider(EncryptedZIPIOProvider.PROVIDER_ID);
|
||||
File zipFile = getZipFile();
|
||||
ExportImportConfig.setZipFile(zipFile.getAbsolutePath());
|
||||
ExportImportConfig.setZipPassword("password123");
|
||||
|
||||
if (zipFile.exists()) {
|
||||
zipFile.delete();
|
||||
}
|
||||
|
||||
new ExportImportProviderImpl().checkExportImport(factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void importModel(KeycloakSessionFactory factory) {
|
||||
ExportImportConfig.setAction(ExportImportProviderImpl.ACTION_IMPORT);
|
||||
ExportImportConfig.setProvider(EncryptedZIPIOProvider.PROVIDER_ID);
|
||||
File zipFile = getZipFile();
|
||||
ExportImportConfig.setZipFile(zipFile.getAbsolutePath());
|
||||
ExportImportConfig.setZipPassword("password-invalid");
|
||||
|
||||
// Try invalid password
|
||||
try {
|
||||
new ExportImportProviderImpl().checkExportImport(factory);
|
||||
Assert.fail("Not expected to be here. Exception should be thrown");
|
||||
} catch (Exception e) {};
|
||||
|
||||
ExportImportConfig.setZipPassword("password123");
|
||||
new ExportImportProviderImpl().checkExportImport(factory);
|
||||
|
||||
if (zipFile.exists()) {
|
||||
zipFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private File getZipFile() {
|
||||
String tempDir = System.getProperty("java.io.tmpdir");
|
||||
return new File(tempDir + File.separator + "keycloak-export.zip");
|
||||
}
|
||||
public class MongoToJPAExportImportTest {
|
||||
}
|
||||
|
|
65
export-import/export-import-single-file/pom.xml
Normal file
65
export-import/export-import-single-file/pom.xml
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>keycloak-export-import-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-export-import-single-file</artifactId>
|
||||
<name>Keycloak Export Import To Single File</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-export-import-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-core-asl</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-mapper-asl</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,84 @@
|
|||
package org.keycloak.exportimport.singlefile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.exportimport.ExportProvider;
|
||||
import org.keycloak.exportimport.util.ExportImportJob;
|
||||
import org.keycloak.exportimport.util.ExportImportUtils;
|
||||
import org.keycloak.exportimport.util.ExportUtils;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class SingleFileExportProvider implements ExportProvider {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SingleFileExportProvider.class);
|
||||
|
||||
private File file;
|
||||
|
||||
public SingleFileExportProvider(File file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public void setFile(File file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportModel(final KeycloakSession session) throws IOException {
|
||||
logger.infof("Exporting model into file %s", this.file.getAbsolutePath());
|
||||
ExportImportUtils.runJobInTransaction(session, new ExportImportJob() {
|
||||
|
||||
@Override
|
||||
public void run() throws IOException {
|
||||
List<RealmModel> realms = session.getModel().getRealms();
|
||||
List<RealmRepresentation> reps = new ArrayList<RealmRepresentation>();
|
||||
for (RealmModel realm : realms) {
|
||||
reps.add(ExportUtils.exportRealm(realm, true));
|
||||
}
|
||||
|
||||
writeToFile(reps);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportRealm(final KeycloakSession session, final String realmName) throws IOException {
|
||||
logger.infof("Exporting realm '%s' into file %s", realmName, this.file.getAbsolutePath());
|
||||
ExportImportUtils.runJobInTransaction(session, new ExportImportJob() {
|
||||
|
||||
@Override
|
||||
public void run() throws IOException {
|
||||
RealmModel realm = session.getModel().getRealmByName(realmName);
|
||||
RealmRepresentation realmRep = ExportUtils.exportRealm(realm, true);
|
||||
writeToFile(realmRep);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
private ObjectMapper getObjectMapper() {
|
||||
return JsonSerialization.prettyMapper;
|
||||
}
|
||||
|
||||
private void writeToFile(Object reps) throws IOException {
|
||||
FileOutputStream stream = new FileOutputStream(this.file);
|
||||
getObjectMapper().writeValue(stream, reps);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package org.keycloak.exportimport.singlefile;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.exportimport.ExportImportConfig;
|
||||
import org.keycloak.exportimport.ExportProvider;
|
||||
import org.keycloak.exportimport.ExportProviderFactory;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class SingleFileExportProviderFactory implements ExportProviderFactory {
|
||||
|
||||
public static final String PROVIDER_ID = "singleFile";
|
||||
|
||||
@Override
|
||||
public ExportProvider create(KeycloakSession session) {
|
||||
String fileName = ExportImportConfig.getFile();
|
||||
return new SingleFileExportProvider(new File(fileName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package org.keycloak.exportimport.singlefile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.exportimport.ImportProvider;
|
||||
import org.keycloak.exportimport.Strategy;
|
||||
import org.keycloak.exportimport.util.ExportImportJob;
|
||||
import org.keycloak.exportimport.util.ExportImportUtils;
|
||||
import org.keycloak.exportimport.util.ExportUtils;
|
||||
import org.keycloak.exportimport.util.ImportUtils;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class SingleFileImportProvider implements ImportProvider {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SingleFileImportProvider.class);
|
||||
|
||||
private File file;
|
||||
|
||||
public SingleFileImportProvider(File file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importModel(final KeycloakSession session, final Strategy strategy) throws IOException {
|
||||
logger.infof("Full importing from file %s", this.file.getAbsolutePath());
|
||||
ExportImportUtils.runJobInTransaction(session, new ExportImportJob() {
|
||||
|
||||
@Override
|
||||
public void run() throws IOException {
|
||||
FileInputStream is = new FileInputStream(file);
|
||||
ImportUtils.importFromStream(session, JsonSerialization.mapper, is, strategy);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importRealm(KeycloakSession session, String realmName, Strategy strategy) throws IOException {
|
||||
// TODO: just that single realm in case that file contains many realms?
|
||||
importModel(session, strategy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package org.keycloak.exportimport.singlefile;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.exportimport.ExportImportConfig;
|
||||
import org.keycloak.exportimport.ImportProvider;
|
||||
import org.keycloak.exportimport.ImportProviderFactory;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class SingleFileImportProviderFactory implements ImportProviderFactory {
|
||||
|
||||
@Override
|
||||
public ImportProvider create(KeycloakSession session) {
|
||||
String fileName = ExportImportConfig.getFile();
|
||||
return new SingleFileImportProvider(new File(fileName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return SingleFileExportProviderFactory.PROVIDER_ID;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.keycloak.exportimport.singlefile.SingleFileExportProviderFactory
|
|
@ -0,0 +1 @@
|
|||
org.keycloak.exportimport.singlefile.SingleFileImportProviderFactory
|
70
export-import/export-import-zip/pom.xml
Normal file
70
export-import/export-import-zip/pom.xml
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>keycloak-export-import-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-export-import-zip</artifactId>
|
||||
<name>Keycloak Export Import To Encrypted ZIP</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-export-import-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-core-asl</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-mapper-asl</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.idyl</groupId>
|
||||
<artifactId>winzipaes</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${maven.compiler.source}</source>
|
||||
<target>${maven.compiler.target}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,73 @@
|
|||
package org.keycloak.exportimport.zip;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import de.idyl.winzipaes.AesZipFileEncrypter;
|
||||
import de.idyl.winzipaes.impl.AESEncrypter;
|
||||
import de.idyl.winzipaes.impl.AESEncrypterBC;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.exportimport.util.ExportUtils;
|
||||
import org.keycloak.exportimport.util.MultipleStepsExportProvider;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ZipExportProvider extends MultipleStepsExportProvider {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ZipExportProvider.class);
|
||||
|
||||
private final AesZipFileEncrypter encrypter;
|
||||
private final String password;
|
||||
|
||||
public ZipExportProvider(File zipFile, String password) {
|
||||
if (zipFile.exists()) {
|
||||
throw new IllegalStateException("File " + zipFile.getAbsolutePath() + " already exists");
|
||||
}
|
||||
this.password = password;
|
||||
|
||||
try {
|
||||
AESEncrypter encrypter = new AESEncrypterBC();
|
||||
this.encrypter = new AesZipFileEncrypter(zipFile, encrypter);
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
}
|
||||
logger.infof("Exporting into zip file %s", zipFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeRealm(String fileName, RealmRepresentation rep) throws IOException {
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
JsonSerialization.mapper.writeValue(stream, rep);
|
||||
|
||||
byte[] byteArray = stream.toByteArray();
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(byteArray);
|
||||
this.encrypter.add(fileName, bis, this.password);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeUsers(String fileName, RealmModel realm, List<UserModel> users) throws IOException {
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
ExportUtils.exportUsersToStream(realm, users, JsonSerialization.mapper, stream);
|
||||
|
||||
byte[] byteArray = stream.toByteArray();
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(byteArray);
|
||||
this.encrypter.add(fileName, bis, this.password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
this.encrypter.close();
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package org.keycloak.exportimport.zip;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.exportimport.ExportImportConfig;
|
||||
import org.keycloak.exportimport.ExportProvider;
|
||||
import org.keycloak.exportimport.ExportProviderFactory;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ZipExportProviderFactory implements ExportProviderFactory {
|
||||
|
||||
|
||||
public static final String PROVIDER_ID = "zip";
|
||||
|
||||
@Override
|
||||
public ExportProvider create(KeycloakSession session) {
|
||||
String fileName = ExportImportConfig.getZipFile();
|
||||
String password = ExportImportConfig.getZipPassword();
|
||||
if (fileName == null) {
|
||||
throw new IllegalArgumentException("ZIP file for export not provided");
|
||||
}
|
||||
if (password == null) {
|
||||
throw new IllegalArgumentException("Password for encrypting ZIP not provided");
|
||||
}
|
||||
return new ZipExportProvider(new File(fileName), password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package org.keycloak.exportimport.zip;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.zip.DataFormatException;
|
||||
|
||||
import de.idyl.winzipaes.AesZipFileDecrypter;
|
||||
import de.idyl.winzipaes.impl.AESDecrypter;
|
||||
import de.idyl.winzipaes.impl.AESDecrypterBC;
|
||||
import de.idyl.winzipaes.impl.ExtZipEntry;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.exportimport.ImportProvider;
|
||||
import org.keycloak.exportimport.Strategy;
|
||||
import org.keycloak.exportimport.util.ExportImportJob;
|
||||
import org.keycloak.exportimport.util.ExportImportUtils;
|
||||
import org.keycloak.exportimport.util.ImportUtils;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ZipImportProvider implements ImportProvider {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ZipImportProvider.class);
|
||||
|
||||
private final AesZipFileDecrypter decrypter;
|
||||
private final String password;
|
||||
|
||||
public ZipImportProvider(File zipFile, String password) {
|
||||
try {
|
||||
if (!zipFile.exists()) {
|
||||
throw new IllegalStateException("File " + zipFile.getAbsolutePath() + " doesn't exists");
|
||||
}
|
||||
|
||||
AESDecrypter decrypter = new AESDecrypterBC();
|
||||
this.decrypter = new AesZipFileDecrypter(zipFile, decrypter);
|
||||
this.password = password;
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
}
|
||||
logger.infof("Importing from ZIP file %s", zipFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importModel(KeycloakSession session, Strategy strategy) throws IOException {
|
||||
for (ExtZipEntry entry : this.decrypter.getEntryList()) {
|
||||
String entryName = entry.getName();
|
||||
if (entryName.endsWith("-realm.json")) {
|
||||
// Parse "foo" from "foo-realm.json"
|
||||
String realmName = entryName.substring(0, entryName.length() - 11);
|
||||
importRealm(session, realmName, strategy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importRealm(final KeycloakSession session, final String realmName, final Strategy strategy) throws IOException {
|
||||
try {
|
||||
// Import realm first
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
this.decrypter.extractEntry(this.decrypter.getEntry(realmName + "-realm.json"), bos, this.password);
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
|
||||
final RealmRepresentation realmRep = JsonSerialization.mapper.readValue(bis, RealmRepresentation.class);
|
||||
|
||||
ExportImportUtils.runJobInTransaction(session, new ExportImportJob() {
|
||||
|
||||
@Override
|
||||
public void run() throws IOException {
|
||||
ImportUtils.importRealm(session, realmRep, strategy);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
// Import users
|
||||
for (ExtZipEntry entry : this.decrypter.getEntryList()) {
|
||||
String name = entry.getName();
|
||||
if ( (name.startsWith(realmName)) && (name.endsWith(".json")) && (name.substring(realmName.length()).contains("-users-")) ) {
|
||||
bos = new ByteArrayOutputStream();
|
||||
this.decrypter.extractEntry(entry, bos, this.password);
|
||||
final ByteArrayInputStream bis2 = new ByteArrayInputStream(bos.toByteArray());
|
||||
|
||||
ExportImportUtils.runJobInTransaction(session, new ExportImportJob() {
|
||||
|
||||
@Override
|
||||
public void run() throws IOException {
|
||||
ImportUtils.importUsersFromStream(session, realmName, JsonSerialization.mapper, bis2);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new RuntimeException(dfe);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
this.decrypter.close();
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package org.keycloak.exportimport.zip;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.exportimport.ExportImportConfig;
|
||||
import org.keycloak.exportimport.ImportProvider;
|
||||
import org.keycloak.exportimport.ImportProviderFactory;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ZipImportProviderFactory implements ImportProviderFactory {
|
||||
|
||||
@Override
|
||||
public ImportProvider create(KeycloakSession session) {
|
||||
String fileName = ExportImportConfig.getZipFile();
|
||||
String password = ExportImportConfig.getZipPassword();
|
||||
if (fileName == null) {
|
||||
throw new IllegalArgumentException("ZIP file for import not provided");
|
||||
}
|
||||
if (password == null) {
|
||||
throw new IllegalArgumentException("Password for decrypting ZIP not provided");
|
||||
}
|
||||
return new ZipImportProvider(new File(fileName), password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ZipExportProviderFactory.PROVIDER_ID;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.keycloak.exportimport.zip.ZipExportProviderFactory
|
|
@ -0,0 +1 @@
|
|||
org.keycloak.exportimport.zip.ZipImportProviderFactory
|
|
@ -17,6 +17,9 @@
|
|||
<modules>
|
||||
<module>export-import-api</module>
|
||||
<module>export-import-impl</module>
|
||||
<module>export-import-dir</module>
|
||||
<module>export-import-single-file</module>
|
||||
<module>export-import-zip</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -30,6 +30,11 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
|
|
|
@ -3,6 +3,9 @@ package org.keycloak.models.utils;
|
|||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.security.Key;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Set;
|
||||
|
@ -10,8 +13,11 @@ import java.util.UUID;
|
|||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.bouncycastle.openssl.PEMWriter;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.util.PemUtils;
|
||||
|
||||
|
@ -65,6 +71,23 @@ public final class KeycloakModelUtils {
|
|||
return PemUtils.removeBeginEnd(s);
|
||||
}
|
||||
|
||||
public static void generateRealmKeys(RealmModel realm) {
|
||||
KeyPair keyPair = null;
|
||||
try {
|
||||
keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
realm.setPrivateKey(keyPair.getPrivate());
|
||||
realm.setPublicKey(keyPair.getPublic());
|
||||
}
|
||||
|
||||
public static UserCredentialModel generateSecret(ClientModel app) {
|
||||
UserCredentialModel secret = UserCredentialModel.generateSecret();
|
||||
app.setSecret(secret.getValue());
|
||||
return secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deep search if given role is descendant of composite role
|
||||
*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package org.keycloak.services.managers;
|
||||
package org.keycloak.models.utils;
|
||||
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.AuthenticationProviderModel;
|
||||
|
@ -13,9 +13,11 @@ import org.keycloak.models.SocialLinkModel;
|
|||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.representations.idm.ApplicationRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticationProviderRepresentation;
|
||||
import org.keycloak.representations.idm.ClaimRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.OAuthClientRepresentation;
|
||||
import org.keycloak.representations.idm.RealmAuditRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
|
@ -29,6 +31,7 @@ import java.util.HashSet;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
|
@ -201,4 +204,53 @@ public class ModelToRepresentation {
|
|||
}
|
||||
return rep;
|
||||
}
|
||||
|
||||
public static ApplicationRepresentation toRepresentation(ApplicationModel applicationModel) {
|
||||
ApplicationRepresentation rep = new ApplicationRepresentation();
|
||||
rep.setId(applicationModel.getId());
|
||||
rep.setName(applicationModel.getName());
|
||||
rep.setEnabled(applicationModel.isEnabled());
|
||||
rep.setAdminUrl(applicationModel.getManagementUrl());
|
||||
rep.setPublicClient(applicationModel.isPublicClient());
|
||||
rep.setBearerOnly(applicationModel.isBearerOnly());
|
||||
rep.setSurrogateAuthRequired(applicationModel.isSurrogateAuthRequired());
|
||||
rep.setBaseUrl(applicationModel.getBaseUrl());
|
||||
rep.setNotBefore(applicationModel.getNotBefore());
|
||||
|
||||
Set<String> redirectUris = applicationModel.getRedirectUris();
|
||||
if (redirectUris != null) {
|
||||
rep.setRedirectUris(new LinkedList<String>(redirectUris));
|
||||
}
|
||||
|
||||
Set<String> webOrigins = applicationModel.getWebOrigins();
|
||||
if (webOrigins != null) {
|
||||
rep.setWebOrigins(new LinkedList<String>(webOrigins));
|
||||
}
|
||||
|
||||
if (!applicationModel.getDefaultRoles().isEmpty()) {
|
||||
rep.setDefaultRoles(applicationModel.getDefaultRoles().toArray(new String[0]));
|
||||
}
|
||||
|
||||
return rep;
|
||||
}
|
||||
|
||||
public static OAuthClientRepresentation toRepresentation(OAuthClientModel model) {
|
||||
OAuthClientRepresentation rep = new OAuthClientRepresentation();
|
||||
rep.setId(model.getId());
|
||||
rep.setName(model.getClientId());
|
||||
rep.setEnabled(model.isEnabled());
|
||||
rep.setPublicClient(model.isPublicClient());
|
||||
rep.setDirectGrantsOnly(model.isDirectGrantsOnly());
|
||||
Set<String> redirectUris = model.getRedirectUris();
|
||||
if (redirectUris != null) {
|
||||
rep.setRedirectUris(new LinkedList<String>(redirectUris));
|
||||
}
|
||||
|
||||
Set<String> webOrigins = model.getWebOrigins();
|
||||
if (webOrigins != null) {
|
||||
rep.setWebOrigins(new LinkedList<String>(webOrigins));
|
||||
}
|
||||
rep.setNotBefore(model.getNotBefore());
|
||||
return rep;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,671 @@
|
|||
package org.keycloak.models.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.iharder.Base64;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.AuthenticationLinkModel;
|
||||
import org.keycloak.models.AuthenticationProviderModel;
|
||||
import org.keycloak.models.ClaimMask;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.OAuthClientModel;
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.SocialLinkModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserCredentialValueModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.ApplicationRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticationLinkRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticationProviderRepresentation;
|
||||
import org.keycloak.representations.idm.ClaimRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.OAuthClientRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.representations.idm.ScopeMappingRepresentation;
|
||||
import org.keycloak.representations.idm.SocialLinkRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
|
||||
public class RepresentationToModel {
|
||||
|
||||
private static Logger logger = Logger.getLogger(RepresentationToModel.class);
|
||||
|
||||
public static void importRealm(RealmRepresentation rep, RealmModel newRealm) {
|
||||
newRealm.setName(rep.getRealm());
|
||||
if (rep.isEnabled() != null) newRealm.setEnabled(rep.isEnabled());
|
||||
if (rep.isSocial() != null) newRealm.setSocial(rep.isSocial());
|
||||
if (rep.isBruteForceProtected() != null) newRealm.setBruteForceProtected(rep.isBruteForceProtected());
|
||||
if (rep.getMaxFailureWaitSeconds() != null) newRealm.setMaxFailureWaitSeconds(rep.getMaxFailureWaitSeconds());
|
||||
if (rep.getMinimumQuickLoginWaitSeconds() != null) newRealm.setMinimumQuickLoginWaitSeconds(rep.getMinimumQuickLoginWaitSeconds());
|
||||
if (rep.getWaitIncrementSeconds() != null) newRealm.setWaitIncrementSeconds(rep.getWaitIncrementSeconds());
|
||||
if (rep.getQuickLoginCheckMilliSeconds() != null) newRealm.setQuickLoginCheckMilliSeconds(rep.getQuickLoginCheckMilliSeconds());
|
||||
if (rep.getMaxDeltaTimeSeconds() != null) newRealm.setMaxDeltaTimeSeconds(rep.getMaxDeltaTimeSeconds());
|
||||
if (rep.getFailureFactor() != null) newRealm.setFailureFactor(rep.getFailureFactor());
|
||||
|
||||
if (rep.getNotBefore() != null) newRealm.setNotBefore(rep.getNotBefore());
|
||||
|
||||
if (rep.getAccessTokenLifespan() != null) newRealm.setAccessTokenLifespan(rep.getAccessTokenLifespan());
|
||||
else newRealm.setAccessTokenLifespan(300);
|
||||
|
||||
if (rep.getSsoSessionIdleTimeout() != null) newRealm.setSsoSessionIdleTimeout(rep.getSsoSessionIdleTimeout());
|
||||
else newRealm.setSsoSessionIdleTimeout(600);
|
||||
if (rep.getSsoSessionMaxLifespan() != null) newRealm.setSsoSessionMaxLifespan(rep.getSsoSessionMaxLifespan());
|
||||
else newRealm.setSsoSessionMaxLifespan(36000);
|
||||
|
||||
if (rep.getAccessCodeLifespan() != null) newRealm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
|
||||
else newRealm.setAccessCodeLifespan(60);
|
||||
|
||||
if (rep.getAccessCodeLifespanUserAction() != null)
|
||||
newRealm.setAccessCodeLifespanUserAction(rep.getAccessCodeLifespanUserAction());
|
||||
else newRealm.setAccessCodeLifespanUserAction(300);
|
||||
|
||||
if (rep.isSslNotRequired() != null) newRealm.setSslNotRequired(rep.isSslNotRequired());
|
||||
if (rep.isPasswordCredentialGrantAllowed() != null) newRealm.setPasswordCredentialGrantAllowed(rep.isPasswordCredentialGrantAllowed());
|
||||
if (rep.isRegistrationAllowed() != null) newRealm.setRegistrationAllowed(rep.isRegistrationAllowed());
|
||||
if (rep.isRememberMe() != null) newRealm.setRememberMe(rep.isRememberMe());
|
||||
if (rep.isVerifyEmail() != null) newRealm.setVerifyEmail(rep.isVerifyEmail());
|
||||
if (rep.isResetPasswordAllowed() != null) newRealm.setResetPasswordAllowed(rep.isResetPasswordAllowed());
|
||||
if (rep.isUpdateProfileOnInitialSocialLogin() != null)
|
||||
newRealm.setUpdateProfileOnInitialSocialLogin(rep.isUpdateProfileOnInitialSocialLogin());
|
||||
if (rep.getPrivateKey() == null || rep.getPublicKey() == null) {
|
||||
KeycloakModelUtils.generateRealmKeys(newRealm);
|
||||
} else {
|
||||
newRealm.setPrivateKeyPem(rep.getPrivateKey());
|
||||
newRealm.setPublicKeyPem(rep.getPublicKey());
|
||||
}
|
||||
if (rep.getLoginTheme() != null) newRealm.setLoginTheme(rep.getLoginTheme());
|
||||
if (rep.getAccountTheme() != null) newRealm.setAccountTheme(rep.getAccountTheme());
|
||||
if (rep.getAdminTheme() != null) newRealm.setAdminTheme(rep.getAdminTheme());
|
||||
if (rep.getEmailTheme() != null) newRealm.setEmailTheme(rep.getEmailTheme());
|
||||
|
||||
if (rep.getRequiredCredentials() != null) {
|
||||
for (String requiredCred : rep.getRequiredCredentials()) {
|
||||
addRequiredCredential(newRealm, requiredCred);
|
||||
}
|
||||
} else {
|
||||
addRequiredCredential(newRealm, CredentialRepresentation.PASSWORD);
|
||||
}
|
||||
|
||||
if (rep.getPasswordPolicy() != null) newRealm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy()));
|
||||
|
||||
if (rep.getApplications() != null) {
|
||||
Map<String, ApplicationModel> appMap = createApplications(rep, newRealm);
|
||||
}
|
||||
|
||||
if (rep.getRoles() != null) {
|
||||
if (rep.getRoles().getRealm() != null) { // realm roles
|
||||
for (RoleRepresentation roleRep : rep.getRoles().getRealm()) {
|
||||
createRole(newRealm, roleRep);
|
||||
}
|
||||
}
|
||||
if (rep.getRoles().getApplication() != null) {
|
||||
for (Map.Entry<String, List<RoleRepresentation>> entry : rep.getRoles().getApplication().entrySet()) {
|
||||
ApplicationModel app = newRealm.getApplicationByName(entry.getKey());
|
||||
if (app == null) {
|
||||
throw new RuntimeException("App doesn't exist in role definitions: " + entry.getKey());
|
||||
}
|
||||
for (RoleRepresentation roleRep : entry.getValue()) {
|
||||
// Application role may already exists (for example if it is defaultRole)
|
||||
RoleModel role = app.getRole(roleRep.getName());
|
||||
if (role == null) {
|
||||
role = app.addRole(roleRep.getName());
|
||||
}
|
||||
role.setDescription(roleRep.getDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
// now that all roles are created, re-iterate and set up composites
|
||||
if (rep.getRoles().getRealm() != null) { // realm roles
|
||||
for (RoleRepresentation roleRep : rep.getRoles().getRealm()) {
|
||||
RoleModel role = newRealm.getRole(roleRep.getName());
|
||||
addComposites(role, roleRep, newRealm);
|
||||
}
|
||||
}
|
||||
if (rep.getRoles().getApplication() != null) {
|
||||
for (Map.Entry<String, List<RoleRepresentation>> entry : rep.getRoles().getApplication().entrySet()) {
|
||||
ApplicationModel app = newRealm.getApplicationByName(entry.getKey());
|
||||
if (app == null) {
|
||||
throw new RuntimeException("App doesn't exist in role definitions: " + entry.getKey());
|
||||
}
|
||||
for (RoleRepresentation roleRep : entry.getValue()) {
|
||||
RoleModel role = app.getRole(roleRep.getName());
|
||||
addComposites(role, roleRep, newRealm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (rep.getDefaultRoles() != null) {
|
||||
for (String roleString : rep.getDefaultRoles()) {
|
||||
newRealm.addDefaultRole(roleString.trim());
|
||||
}
|
||||
}
|
||||
|
||||
if (rep.getOauthClients() != null) {
|
||||
createOAuthClients(rep, newRealm);
|
||||
}
|
||||
|
||||
|
||||
// Now that all possible roles and applications are created, create scope mappings
|
||||
|
||||
Map<String, ApplicationModel> appMap = newRealm.getApplicationNameMap();
|
||||
|
||||
if (rep.getApplicationScopeMappings() != null) {
|
||||
|
||||
for (Map.Entry<String, List<ScopeMappingRepresentation>> entry : rep.getApplicationScopeMappings().entrySet()) {
|
||||
ApplicationModel app = appMap.get(entry.getKey());
|
||||
if (app == null) {
|
||||
throw new RuntimeException("Unable to find application role mappings for app: " + entry.getKey());
|
||||
}
|
||||
createApplicationScopeMappings(newRealm, app, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (rep.getScopeMappings() != null) {
|
||||
for (ScopeMappingRepresentation scope : rep.getScopeMappings()) {
|
||||
ClientModel client = newRealm.findClient(scope.getClient());
|
||||
for (String roleString : scope.getRoles()) {
|
||||
RoleModel role = newRealm.getRole(roleString.trim());
|
||||
if (role == null) {
|
||||
role = newRealm.addRole(roleString.trim());
|
||||
}
|
||||
client.addScopeMapping(role);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (rep.getSmtpServer() != null) {
|
||||
newRealm.setSmtpConfig(new HashMap(rep.getSmtpServer()));
|
||||
}
|
||||
|
||||
if (rep.getSocialProviders() != null) {
|
||||
newRealm.setSocialConfig(new HashMap(rep.getSocialProviders()));
|
||||
}
|
||||
if (rep.getLdapServer() != null) {
|
||||
newRealm.setLdapServerConfig(new HashMap(rep.getLdapServer()));
|
||||
}
|
||||
|
||||
if (rep.getAuthenticationProviders() != null) {
|
||||
List<AuthenticationProviderModel> authProviderModels = convertAuthenticationProviders(rep.getAuthenticationProviders());
|
||||
newRealm.setAuthenticationProviders(authProviderModels);
|
||||
} else {
|
||||
List<AuthenticationProviderModel> authProviderModels = Arrays.asList(AuthenticationProviderModel.DEFAULT_PROVIDER);
|
||||
newRealm.setAuthenticationProviders(authProviderModels);
|
||||
}
|
||||
|
||||
// create users and their role mappings and social mappings
|
||||
|
||||
if (rep.getUsers() != null) {
|
||||
for (UserRepresentation userRep : rep.getUsers()) {
|
||||
UserModel user = createUser(newRealm, userRep, appMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateRealm(RealmRepresentation rep, RealmModel realm) {
|
||||
if (rep.getRealm() != null) {
|
||||
realm.setName(rep.getRealm());
|
||||
}
|
||||
if (rep.isEnabled() != null) realm.setEnabled(rep.isEnabled());
|
||||
if (rep.isSocial() != null) realm.setSocial(rep.isSocial());
|
||||
if (rep.isBruteForceProtected() != null) realm.setBruteForceProtected(rep.isBruteForceProtected());
|
||||
if (rep.getMaxFailureWaitSeconds() != null) realm.setMaxFailureWaitSeconds(rep.getMaxFailureWaitSeconds());
|
||||
if (rep.getMinimumQuickLoginWaitSeconds() != null) realm.setMinimumQuickLoginWaitSeconds(rep.getMinimumQuickLoginWaitSeconds());
|
||||
if (rep.getWaitIncrementSeconds() != null) realm.setWaitIncrementSeconds(rep.getWaitIncrementSeconds());
|
||||
if (rep.getQuickLoginCheckMilliSeconds() != null) realm.setQuickLoginCheckMilliSeconds(rep.getQuickLoginCheckMilliSeconds());
|
||||
if (rep.getMaxDeltaTimeSeconds() != null) realm.setMaxDeltaTimeSeconds(rep.getMaxDeltaTimeSeconds());
|
||||
if (rep.getFailureFactor() != null) realm.setFailureFactor(rep.getFailureFactor());
|
||||
if (rep.isPasswordCredentialGrantAllowed() != null) realm.setPasswordCredentialGrantAllowed(rep.isPasswordCredentialGrantAllowed());
|
||||
if (rep.isRegistrationAllowed() != null) realm.setRegistrationAllowed(rep.isRegistrationAllowed());
|
||||
if (rep.isRememberMe() != null) realm.setRememberMe(rep.isRememberMe());
|
||||
if (rep.isVerifyEmail() != null) realm.setVerifyEmail(rep.isVerifyEmail());
|
||||
if (rep.isResetPasswordAllowed() != null) realm.setResetPasswordAllowed(rep.isResetPasswordAllowed());
|
||||
if (rep.isUpdateProfileOnInitialSocialLogin() != null)
|
||||
realm.setUpdateProfileOnInitialSocialLogin(rep.isUpdateProfileOnInitialSocialLogin());
|
||||
if (rep.isSslNotRequired() != null) realm.setSslNotRequired((rep.isSslNotRequired()));
|
||||
if (rep.getAccessCodeLifespan() != null) realm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
|
||||
if (rep.getAccessCodeLifespanUserAction() != null)
|
||||
realm.setAccessCodeLifespanUserAction(rep.getAccessCodeLifespanUserAction());
|
||||
if (rep.getNotBefore() != null) realm.setNotBefore(rep.getNotBefore());
|
||||
if (rep.getAccessTokenLifespan() != null) realm.setAccessTokenLifespan(rep.getAccessTokenLifespan());
|
||||
if (rep.getSsoSessionIdleTimeout() != null) realm.setSsoSessionIdleTimeout(rep.getSsoSessionIdleTimeout());
|
||||
if (rep.getSsoSessionMaxLifespan() != null) realm.setSsoSessionMaxLifespan(rep.getSsoSessionMaxLifespan());
|
||||
if (rep.getRequiredCredentials() != null) {
|
||||
realm.updateRequiredCredentials(rep.getRequiredCredentials());
|
||||
}
|
||||
if (rep.getLoginTheme() != null) realm.setLoginTheme(rep.getLoginTheme());
|
||||
if (rep.getAccountTheme() != null) realm.setAccountTheme(rep.getAccountTheme());
|
||||
if (rep.getAdminTheme() != null) realm.setAdminTheme(rep.getAdminTheme());
|
||||
if (rep.getEmailTheme() != null) realm.setEmailTheme(rep.getEmailTheme());
|
||||
|
||||
if (rep.getPasswordPolicy() != null) realm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy()));
|
||||
|
||||
if (rep.getDefaultRoles() != null) {
|
||||
realm.updateDefaultRoles(rep.getDefaultRoles().toArray(new String[rep.getDefaultRoles().size()]));
|
||||
}
|
||||
|
||||
if (rep.getSmtpServer() != null) {
|
||||
realm.setSmtpConfig(new HashMap(rep.getSmtpServer()));
|
||||
}
|
||||
|
||||
if (rep.getSocialProviders() != null) {
|
||||
realm.setSocialConfig(new HashMap(rep.getSocialProviders()));
|
||||
}
|
||||
|
||||
if (rep.getLdapServer() != null) {
|
||||
realm.setLdapServerConfig(new HashMap(rep.getLdapServer()));
|
||||
}
|
||||
if (rep.getAuthenticationProviders() != null) {
|
||||
List<AuthenticationProviderModel> authProviderModels = convertAuthenticationProviders(rep.getAuthenticationProviders());
|
||||
realm.setAuthenticationProviders(authProviderModels);
|
||||
}
|
||||
|
||||
if ("GENERATE".equals(rep.getPublicKey())) {
|
||||
KeycloakModelUtils.generateRealmKeys(realm);
|
||||
}
|
||||
}
|
||||
|
||||
// Basic realm stuff
|
||||
|
||||
public static void addRequiredCredential(RealmModel newRealm, String requiredCred) {
|
||||
newRealm.addRequiredCredential(requiredCred);
|
||||
}
|
||||
|
||||
|
||||
private static List<AuthenticationProviderModel> convertAuthenticationProviders(List<AuthenticationProviderRepresentation> authenticationProviders) {
|
||||
List<AuthenticationProviderModel> result = new ArrayList<AuthenticationProviderModel>();
|
||||
|
||||
for (AuthenticationProviderRepresentation representation : authenticationProviders) {
|
||||
AuthenticationProviderModel model = new AuthenticationProviderModel(representation.getProviderName(),
|
||||
representation.isPasswordUpdateSupported(), representation.getConfig());
|
||||
result.add(model);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Roles
|
||||
|
||||
public static void createRole(RealmModel newRealm, RoleRepresentation roleRep) {
|
||||
RoleModel role = roleRep.getId()!=null ? newRealm.addRole(roleRep.getId(), roleRep.getName()) : newRealm.addRole(roleRep.getName());
|
||||
if (roleRep.getDescription() != null) role.setDescription(roleRep.getDescription());
|
||||
}
|
||||
|
||||
private static void addComposites(RoleModel role, RoleRepresentation roleRep, RealmModel realm) {
|
||||
if (roleRep.getComposites() == null) return;
|
||||
if (roleRep.getComposites().getRealm() != null) {
|
||||
for (String roleStr : roleRep.getComposites().getRealm()) {
|
||||
RoleModel realmRole = realm.getRole(roleStr);
|
||||
if (realmRole == null) throw new RuntimeException("Unable to find composite realm role: " + roleStr);
|
||||
role.addCompositeRole(realmRole);
|
||||
}
|
||||
}
|
||||
if (roleRep.getComposites().getApplication() != null) {
|
||||
for (Map.Entry<String, List<String>> entry : roleRep.getComposites().getApplication().entrySet()) {
|
||||
ApplicationModel app = realm.getApplicationByName(entry.getKey());
|
||||
if (app == null) {
|
||||
throw new RuntimeException("App doesn't exist in role definitions: " + roleRep.getName());
|
||||
}
|
||||
for (String roleStr : entry.getValue()) {
|
||||
RoleModel appRole = app.getRole(roleStr);
|
||||
if (appRole == null) throw new RuntimeException("Unable to find composite app role: " + roleStr);
|
||||
role.addCompositeRole(appRole);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// APPLICATIONS
|
||||
|
||||
private static Map<String, ApplicationModel> createApplications(RealmRepresentation rep, RealmModel realm) {
|
||||
Map<String, ApplicationModel> appMap = new HashMap<String, ApplicationModel>();
|
||||
for (ApplicationRepresentation resourceRep : rep.getApplications()) {
|
||||
ApplicationModel app = createApplication(realm, resourceRep);
|
||||
appMap.put(app.getName(), app);
|
||||
}
|
||||
return appMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does not create scope or role mappings!
|
||||
*
|
||||
* @param realm
|
||||
* @param resourceRep
|
||||
* @return
|
||||
*/
|
||||
public static ApplicationModel createApplication(RealmModel realm, ApplicationRepresentation resourceRep) {
|
||||
logger.debug("************ CREATE APPLICATION: {0}" + resourceRep.getName());
|
||||
ApplicationModel applicationModel = resourceRep.getId()!=null ? realm.addApplication(resourceRep.getId(), resourceRep.getName()) : realm.addApplication(resourceRep.getName());
|
||||
if (resourceRep.isEnabled() != null) applicationModel.setEnabled(resourceRep.isEnabled());
|
||||
applicationModel.setManagementUrl(resourceRep.getAdminUrl());
|
||||
if (resourceRep.isSurrogateAuthRequired() != null)
|
||||
applicationModel.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired());
|
||||
applicationModel.setBaseUrl(resourceRep.getBaseUrl());
|
||||
if (resourceRep.isBearerOnly() != null) applicationModel.setBearerOnly(resourceRep.isBearerOnly());
|
||||
if (resourceRep.isPublicClient() != null) applicationModel.setPublicClient(resourceRep.isPublicClient());
|
||||
applicationModel.updateApplication();
|
||||
|
||||
if (resourceRep.getNotBefore() != null) {
|
||||
applicationModel.setNotBefore(resourceRep.getNotBefore());
|
||||
}
|
||||
|
||||
applicationModel.setSecret(resourceRep.getSecret());
|
||||
if (applicationModel.getSecret() == null) {
|
||||
KeycloakModelUtils.generateSecret(applicationModel);
|
||||
}
|
||||
|
||||
|
||||
if (resourceRep.getRedirectUris() != null) {
|
||||
for (String redirectUri : resourceRep.getRedirectUris()) {
|
||||
applicationModel.addRedirectUri(redirectUri);
|
||||
}
|
||||
}
|
||||
if (resourceRep.getWebOrigins() != null) {
|
||||
for (String webOrigin : resourceRep.getWebOrigins()) {
|
||||
logger.debugv("Application: {0} webOrigin: {1}", resourceRep.getName(), webOrigin);
|
||||
applicationModel.addWebOrigin(webOrigin);
|
||||
}
|
||||
} else {
|
||||
// add origins from redirect uris
|
||||
if (resourceRep.getRedirectUris() != null) {
|
||||
Set<String> origins = new HashSet<String>();
|
||||
for (String redirectUri : resourceRep.getRedirectUris()) {
|
||||
logger.info("add redirectUri to origin: " + redirectUri);
|
||||
if (redirectUri.startsWith("http:")) {
|
||||
URI uri = URI.create(redirectUri);
|
||||
String origin = uri.getScheme() + "://" + uri.getHost();
|
||||
if (uri.getPort() != -1) {
|
||||
origin += ":" + uri.getPort();
|
||||
}
|
||||
logger.debugv("adding default application origin: {0}" , origin);
|
||||
origins.add(origin);
|
||||
}
|
||||
}
|
||||
if (origins.size() > 0) {
|
||||
applicationModel.setWebOrigins(origins);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (resourceRep.getDefaultRoles() != null) {
|
||||
applicationModel.updateDefaultRoles(resourceRep.getDefaultRoles());
|
||||
}
|
||||
|
||||
if (resourceRep.getClaims() != null) {
|
||||
setClaims(applicationModel, resourceRep.getClaims());
|
||||
} else {
|
||||
applicationModel.setAllowedClaimsMask(ClaimMask.USERNAME);
|
||||
}
|
||||
|
||||
return applicationModel;
|
||||
}
|
||||
|
||||
public static void updateApplication(ApplicationRepresentation rep, ApplicationModel resource) {
|
||||
if (rep.getName() != null) resource.setName(rep.getName());
|
||||
if (rep.isEnabled() != null) resource.setEnabled(rep.isEnabled());
|
||||
if (rep.isBearerOnly() != null) resource.setBearerOnly(rep.isBearerOnly());
|
||||
if (rep.isPublicClient() != null) resource.setPublicClient(rep.isPublicClient());
|
||||
if (rep.getAdminUrl() != null) resource.setManagementUrl(rep.getAdminUrl());
|
||||
if (rep.getBaseUrl() != null) resource.setBaseUrl(rep.getBaseUrl());
|
||||
if (rep.isSurrogateAuthRequired() != null) resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired());
|
||||
resource.updateApplication();
|
||||
|
||||
if (rep.getNotBefore() != null) {
|
||||
resource.setNotBefore(rep.getNotBefore());
|
||||
}
|
||||
if (rep.getDefaultRoles() != null) {
|
||||
resource.updateDefaultRoles(rep.getDefaultRoles());
|
||||
}
|
||||
|
||||
List<String> redirectUris = rep.getRedirectUris();
|
||||
if (redirectUris != null) {
|
||||
resource.setRedirectUris(new HashSet<String>(redirectUris));
|
||||
}
|
||||
|
||||
List<String> webOrigins = rep.getWebOrigins();
|
||||
if (webOrigins != null) {
|
||||
resource.setWebOrigins(new HashSet<String>(webOrigins));
|
||||
}
|
||||
|
||||
if (rep.getClaims() != null) {
|
||||
setClaims(resource, rep.getClaims());
|
||||
}
|
||||
}
|
||||
|
||||
public static void setClaims(ClientModel model, ClaimRepresentation rep) {
|
||||
long mask = model.getAllowedClaimsMask();
|
||||
if (rep.getAddress()) {
|
||||
mask |= ClaimMask.ADDRESS;
|
||||
} else {
|
||||
mask &= ~ClaimMask.ADDRESS;
|
||||
}
|
||||
if (rep.getEmail()) {
|
||||
mask |= ClaimMask.EMAIL;
|
||||
} else {
|
||||
mask &= ~ClaimMask.EMAIL;
|
||||
}
|
||||
if (rep.getGender()) {
|
||||
mask |= ClaimMask.GENDER;
|
||||
} else {
|
||||
mask &= ~ClaimMask.GENDER;
|
||||
}
|
||||
if (rep.getLocale()) {
|
||||
mask |= ClaimMask.LOCALE;
|
||||
} else {
|
||||
mask &= ~ClaimMask.LOCALE;
|
||||
}
|
||||
if (rep.getName()) {
|
||||
mask |= ClaimMask.NAME;
|
||||
} else {
|
||||
mask &= ~ClaimMask.NAME;
|
||||
}
|
||||
if (rep.getPhone()) {
|
||||
mask |= ClaimMask.PHONE;
|
||||
} else {
|
||||
mask &= ~ClaimMask.PHONE;
|
||||
}
|
||||
if (rep.getPicture()) {
|
||||
mask |= ClaimMask.PICTURE;
|
||||
} else {
|
||||
mask &= ~ClaimMask.PICTURE;
|
||||
}
|
||||
if (rep.getProfile()) {
|
||||
mask |= ClaimMask.PROFILE;
|
||||
} else {
|
||||
mask &= ~ClaimMask.PROFILE;
|
||||
}
|
||||
if (rep.getUsername()) {
|
||||
mask |= ClaimMask.USERNAME;
|
||||
} else {
|
||||
mask &= ~ClaimMask.USERNAME;
|
||||
}
|
||||
if (rep.getWebsite()) {
|
||||
mask |= ClaimMask.WEBSITE;
|
||||
} else {
|
||||
mask &= ~ClaimMask.WEBSITE;
|
||||
}
|
||||
model.setAllowedClaimsMask(mask);
|
||||
}
|
||||
|
||||
// OAuth clients
|
||||
|
||||
private static void createOAuthClients(RealmRepresentation realmRep, RealmModel realm) {
|
||||
for (OAuthClientRepresentation rep : realmRep.getOauthClients()) {
|
||||
createOAuthClient(rep, realm);
|
||||
}
|
||||
}
|
||||
|
||||
public static OAuthClientModel createOAuthClient(String id, String name, RealmModel realm) {
|
||||
OAuthClientModel model = id!=null ? realm.addOAuthClient(id, name) : realm.addOAuthClient(name);
|
||||
KeycloakModelUtils.generateSecret(model);
|
||||
return model;
|
||||
}
|
||||
|
||||
public static OAuthClientModel createOAuthClient(OAuthClientRepresentation rep, RealmModel realm) {
|
||||
OAuthClientModel model = createOAuthClient(rep.getId(), rep.getName(), realm);
|
||||
updateOAuthClient(rep, model);
|
||||
return model;
|
||||
}
|
||||
|
||||
public static void updateOAuthClient(OAuthClientRepresentation rep, OAuthClientModel model) {
|
||||
if (rep.getName() != null) model.setClientId(rep.getName());
|
||||
if (rep.isEnabled() != null) model.setEnabled(rep.isEnabled());
|
||||
if (rep.isPublicClient() != null) model.setPublicClient(rep.isPublicClient());
|
||||
if (rep.isDirectGrantsOnly() != null) model.setDirectGrantsOnly(rep.isDirectGrantsOnly());
|
||||
if (rep.getClaims() != null) {
|
||||
setClaims(model, rep.getClaims());
|
||||
}
|
||||
if (rep.getNotBefore() != null) {
|
||||
model.setNotBefore(rep.getNotBefore());
|
||||
}
|
||||
if (rep.getSecret() != null) model.setSecret(rep.getSecret());
|
||||
List<String> redirectUris = rep.getRedirectUris();
|
||||
if (redirectUris != null) {
|
||||
model.setRedirectUris(new HashSet<String>(redirectUris));
|
||||
}
|
||||
|
||||
List<String> webOrigins = rep.getWebOrigins();
|
||||
if (webOrigins != null) {
|
||||
model.setWebOrigins(new HashSet<String>(webOrigins));
|
||||
}
|
||||
|
||||
if (rep.getClaims() != null) {
|
||||
setClaims(model, rep.getClaims());
|
||||
}
|
||||
|
||||
if (rep.getNotBefore() != null) {
|
||||
model.setNotBefore(rep.getNotBefore());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Scope mappings
|
||||
|
||||
public static void createApplicationScopeMappings(RealmModel realm, ApplicationModel applicationModel, List<ScopeMappingRepresentation> mappings) {
|
||||
for (ScopeMappingRepresentation mapping : mappings) {
|
||||
ClientModel client = realm.findClient(mapping.getClient());
|
||||
for (String roleString : mapping.getRoles()) {
|
||||
RoleModel role = applicationModel.getRole(roleString.trim());
|
||||
if (role == null) {
|
||||
role = applicationModel.addRole(roleString.trim());
|
||||
}
|
||||
client.addScopeMapping(role);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Users
|
||||
|
||||
public static UserModel createUser(RealmModel newRealm, UserRepresentation userRep, Map<String, ApplicationModel> appMap) {
|
||||
UserModel user = newRealm.addUser(userRep.getId(), userRep.getUsername(), false);
|
||||
user.setEnabled(userRep.isEnabled());
|
||||
user.setEmail(userRep.getEmail());
|
||||
user.setFirstName(userRep.getFirstName());
|
||||
user.setLastName(userRep.getLastName());
|
||||
if (userRep.getAttributes() != null) {
|
||||
for (Map.Entry<String, String> entry : userRep.getAttributes().entrySet()) {
|
||||
user.setAttribute(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
if (userRep.getRequiredActions() != null) {
|
||||
for (String requiredAction : userRep.getRequiredActions()) {
|
||||
user.addRequiredAction(UserModel.RequiredAction.valueOf(requiredAction));
|
||||
}
|
||||
}
|
||||
if (userRep.getCredentials() != null) {
|
||||
for (CredentialRepresentation cred : userRep.getCredentials()) {
|
||||
updateCredential(user, cred);
|
||||
}
|
||||
}
|
||||
if (userRep.getAuthenticationLink() != null) {
|
||||
AuthenticationLinkRepresentation link = userRep.getAuthenticationLink();
|
||||
AuthenticationLinkModel authLink = new AuthenticationLinkModel(link.getAuthProvider(), link.getAuthUserId());
|
||||
user.setAuthenticationLink(authLink);
|
||||
}
|
||||
if (userRep.getSocialLinks() != null) {
|
||||
for (SocialLinkRepresentation socialLink : userRep.getSocialLinks()) {
|
||||
SocialLinkModel mappingModel = new SocialLinkModel(socialLink.getSocialProvider(), socialLink.getSocialUserId(), socialLink.getSocialUsername());
|
||||
newRealm.addSocialLink(user, mappingModel);
|
||||
}
|
||||
}
|
||||
if (userRep.getRealmRoles() != null) {
|
||||
for (String roleString : userRep.getRealmRoles()) {
|
||||
RoleModel role = newRealm.getRole(roleString.trim());
|
||||
if (role == null) {
|
||||
role = newRealm.addRole(roleString.trim());
|
||||
}
|
||||
user.grantRole(role);
|
||||
}
|
||||
}
|
||||
if (userRep.getApplicationRoles() != null) {
|
||||
for (Map.Entry<String, List<String>> entry : userRep.getApplicationRoles().entrySet()) {
|
||||
ApplicationModel app = appMap.get(entry.getKey());
|
||||
if (app == null) {
|
||||
throw new RuntimeException("Unable to find application role mappings for app: " + entry.getKey());
|
||||
}
|
||||
createApplicationRoleMappings(app, user, entry.getValue());
|
||||
}
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
// Detect if it is "plain-text" or "hashed" representation and update model according to it
|
||||
private static void updateCredential(UserModel user, CredentialRepresentation cred) {
|
||||
if (cred.getValue() != null) {
|
||||
UserCredentialModel plainTextCred = convertCredential(cred);
|
||||
user.updateCredential(plainTextCred);
|
||||
} else {
|
||||
UserCredentialValueModel hashedCred = new UserCredentialValueModel();
|
||||
hashedCred.setType(cred.getType());
|
||||
hashedCred.setDevice(cred.getDevice());
|
||||
hashedCred.setHashIterations(cred.getHashIterations());
|
||||
try {
|
||||
hashedCred.setSalt(Base64.decode(cred.getSalt()));
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
}
|
||||
hashedCred.setValue(cred.getHashedSaltedValue());
|
||||
user.updateCredentialDirectly(hashedCred);
|
||||
}
|
||||
}
|
||||
|
||||
public static UserCredentialModel convertCredential(CredentialRepresentation cred) {
|
||||
UserCredentialModel credential = new UserCredentialModel();
|
||||
credential.setType(cred.getType());
|
||||
credential.setValue(cred.getValue());
|
||||
return credential;
|
||||
}
|
||||
|
||||
// Role mappings
|
||||
|
||||
public static void createApplicationRoleMappings(ApplicationModel applicationModel, UserModel user, List<String> roleNames) {
|
||||
if (user == null) {
|
||||
throw new RuntimeException("User not found");
|
||||
}
|
||||
|
||||
for (String roleName : roleNames) {
|
||||
RoleModel role = applicationModel.getRole(roleName.trim());
|
||||
if (role == null) {
|
||||
role = applicationModel.addRole(roleName.trim());
|
||||
}
|
||||
user.grantRole(role);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -5,7 +5,6 @@ import org.junit.FixMethodOrder;
|
|||
import org.junit.Test;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.OAuthClientModel;
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
|
@ -16,10 +15,8 @@ import org.keycloak.models.SocialLinkModel;
|
|||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserCredentialValueModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.UserSessionProvider;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.services.managers.OAuthClientManager;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -151,8 +148,9 @@ public class AdapterTest extends AbstractModelTest {
|
|||
public void testOAuthClient() throws Exception {
|
||||
test1CreateRealm();
|
||||
|
||||
OAuthClientModel oauth = new OAuthClientManager(realmModel).create("oauth-client");
|
||||
oauth = realmModel.getOAuthClient("oauth-client");
|
||||
RepresentationToModel.createOAuthClient(null, "oauth-client", realmModel);
|
||||
OAuthClientModel oauth = realmModel.getOAuthClient("oauth-client");
|
||||
Assert.assertNotNull(oauth);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -7,6 +7,8 @@ import org.keycloak.models.ApplicationModel;
|
|||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.representations.idm.ApplicationRepresentation;
|
||||
import org.keycloak.services.managers.ApplicationManager;
|
||||
|
||||
|
@ -57,10 +59,10 @@ public class ApplicationModelTest extends AbstractModelTest {
|
|||
|
||||
@Test
|
||||
public void json() {
|
||||
ApplicationRepresentation representation = appManager.toRepresentation(application);
|
||||
ApplicationRepresentation representation = ModelToRepresentation.toRepresentation(application);
|
||||
|
||||
RealmModel realm = realmManager.createRealm("copy");
|
||||
ApplicationModel copy = appManager.createApplication(realm, representation);
|
||||
ApplicationModel copy = RepresentationToModel.createApplication(realm, representation);
|
||||
|
||||
assertEquals(application, copy);
|
||||
}
|
||||
|
|
|
@ -4,13 +4,10 @@ import org.junit.Assert;
|
|||
import org.junit.Test;
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.services.managers.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class ModelTest extends AbstractModelTest {
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ public class LDAPKeycloakCredentialHandler extends LDAPPlainTextPasswordCredenti
|
|||
|
||||
@Override
|
||||
public void setup(LDAPIdentityStore store) {
|
||||
// TODO: Don't setup it here once PLIDM-508 is fixed
|
||||
// TODO: Don't setup it here once PLINK-508 is fixed
|
||||
if (store.getConfig().isActiveDirectory() || Boolean.getBoolean("keycloak.ldap.ad.skipUserAccountControlAfterPasswordUpdate")) {
|
||||
String userAccountControlProp = System.getProperty("keycloak.ldap.ad.userAccountControlAfterPasswordUpdate");
|
||||
this.userAccountControlAfterPasswordUpdate = userAccountControlProp!=null ? userAccountControlProp : "512";
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
@ -58,7 +59,7 @@ public class ApplianceBootstrap {
|
|||
realm.setAccessCodeLifespanUserAction(300);
|
||||
realm.setSslNotRequired(true);
|
||||
realm.setRegistrationAllowed(false);
|
||||
manager.generateRealmKeys(realm);
|
||||
KeycloakModelUtils.generateRealmKeys(realm);
|
||||
realm.setAuthenticationProviders(Arrays.asList(AuthenticationProviderModel.DEFAULT_PROVIDER));
|
||||
|
||||
realm.setAuditListeners(Collections.singleton("jboss-logging"));
|
||||
|
|
|
@ -4,26 +4,15 @@ import org.codehaus.jackson.annotate.JsonProperty;
|
|||
import org.codehaus.jackson.annotate.JsonPropertyOrder;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.ClaimMask;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionProvider;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.representations.adapters.config.BaseRealmConfig;
|
||||
import org.keycloak.representations.idm.ApplicationRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.ScopeMappingRepresentation;
|
||||
import org.keycloak.representations.idm.UserRoleMappingRepresentation;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
|
@ -41,112 +30,9 @@ public class ApplicationManager {
|
|||
public ApplicationManager() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Does not create scope or role mappings!
|
||||
*
|
||||
* @param realm
|
||||
* @param resourceRep
|
||||
* @return
|
||||
*/
|
||||
public ApplicationModel createApplication(RealmModel realm, ApplicationRepresentation resourceRep) {
|
||||
logger.debug("************ CREATE APPLICATION: {0}" + resourceRep.getName());
|
||||
ApplicationModel applicationModel = realm.addApplication(resourceRep.getName());
|
||||
if (resourceRep.isEnabled() != null) applicationModel.setEnabled(resourceRep.isEnabled());
|
||||
applicationModel.setManagementUrl(resourceRep.getAdminUrl());
|
||||
if (resourceRep.isSurrogateAuthRequired() != null)
|
||||
applicationModel.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired());
|
||||
applicationModel.setBaseUrl(resourceRep.getBaseUrl());
|
||||
if (resourceRep.isBearerOnly() != null) applicationModel.setBearerOnly(resourceRep.isBearerOnly());
|
||||
if (resourceRep.isPublicClient() != null) applicationModel.setPublicClient(resourceRep.isPublicClient());
|
||||
applicationModel.updateApplication();
|
||||
|
||||
if (resourceRep.getNotBefore() != null) {
|
||||
applicationModel.setNotBefore(resourceRep.getNotBefore());
|
||||
}
|
||||
|
||||
applicationModel.setSecret(resourceRep.getSecret());
|
||||
if (applicationModel.getSecret() == null) {
|
||||
generateSecret(applicationModel);
|
||||
}
|
||||
|
||||
|
||||
if (resourceRep.getRedirectUris() != null) {
|
||||
for (String redirectUri : resourceRep.getRedirectUris()) {
|
||||
applicationModel.addRedirectUri(redirectUri);
|
||||
}
|
||||
}
|
||||
if (resourceRep.getWebOrigins() != null) {
|
||||
for (String webOrigin : resourceRep.getWebOrigins()) {
|
||||
logger.debugv("Application: {0} webOrigin: {1}", resourceRep.getName(), webOrigin);
|
||||
applicationModel.addWebOrigin(webOrigin);
|
||||
}
|
||||
} else {
|
||||
// add origins from redirect uris
|
||||
if (resourceRep.getRedirectUris() != null) {
|
||||
Set<String> origins = new HashSet<String>();
|
||||
for (String redirectUri : resourceRep.getRedirectUris()) {
|
||||
logger.info("add redirectUri to origin: " + redirectUri);
|
||||
if (redirectUri.startsWith("http:")) {
|
||||
URI uri = URI.create(redirectUri);
|
||||
String origin = uri.getScheme() + "://" + uri.getHost();
|
||||
if (uri.getPort() != -1) {
|
||||
origin += ":" + uri.getPort();
|
||||
}
|
||||
logger.debugv("adding default application origin: {0}" , origin);
|
||||
origins.add(origin);
|
||||
}
|
||||
}
|
||||
if (origins.size() > 0) {
|
||||
applicationModel.setWebOrigins(origins);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (resourceRep.getDefaultRoles() != null) {
|
||||
applicationModel.updateDefaultRoles(resourceRep.getDefaultRoles());
|
||||
}
|
||||
|
||||
if (resourceRep.getClaims() != null) {
|
||||
ClaimManager.setClaims(applicationModel, resourceRep.getClaims());
|
||||
} else {
|
||||
applicationModel.setAllowedClaimsMask(ClaimMask.USERNAME);
|
||||
}
|
||||
|
||||
return applicationModel;
|
||||
}
|
||||
|
||||
public void createRoleMappings(ApplicationModel applicationModel, UserModel user, List<String> roleNames) {
|
||||
for (String roleName : roleNames) {
|
||||
if (user == null) {
|
||||
throw new RuntimeException("User not found");
|
||||
}
|
||||
|
||||
RoleModel role = applicationModel.getRole(roleName.trim());
|
||||
if (role == null) {
|
||||
role = applicationModel.addRole(roleName.trim());
|
||||
}
|
||||
user.grantRole(role);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void createScopeMappings(RealmModel realm, ApplicationModel applicationModel, List<ScopeMappingRepresentation> mappings) {
|
||||
for (ScopeMappingRepresentation mapping : mappings) {
|
||||
for (String roleString : mapping.getRoles()) {
|
||||
RoleModel role = applicationModel.getRole(roleString.trim());
|
||||
if (role == null) {
|
||||
role = applicationModel.addRole(roleString.trim());
|
||||
}
|
||||
ClientModel client = realm.findClient(mapping.getClient());
|
||||
client.addScopeMapping(role);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ApplicationModel createApplication(RealmModel realm, String name) {
|
||||
ApplicationModel app = realm.addApplication(name);
|
||||
generateSecret(app);
|
||||
KeycloakModelUtils.generateSecret(app);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
@ -163,74 +49,6 @@ public class ApplicationManager {
|
|||
}
|
||||
}
|
||||
|
||||
public UserCredentialModel generateSecret(ApplicationModel app) {
|
||||
UserCredentialModel secret = UserCredentialModel.generateSecret();
|
||||
app.setSecret(secret.getValue());
|
||||
return secret;
|
||||
}
|
||||
|
||||
public void updateApplication(ApplicationRepresentation rep, ApplicationModel resource) {
|
||||
if (rep.getName() != null) resource.setName(rep.getName());
|
||||
if (rep.isEnabled() != null) resource.setEnabled(rep.isEnabled());
|
||||
if (rep.isBearerOnly() != null) resource.setBearerOnly(rep.isBearerOnly());
|
||||
if (rep.isPublicClient() != null) resource.setPublicClient(rep.isPublicClient());
|
||||
if (rep.getAdminUrl() != null) resource.setManagementUrl(rep.getAdminUrl());
|
||||
if (rep.getBaseUrl() != null) resource.setBaseUrl(rep.getBaseUrl());
|
||||
if (rep.isSurrogateAuthRequired() != null) resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired());
|
||||
resource.updateApplication();
|
||||
|
||||
if (rep.getNotBefore() != null) {
|
||||
resource.setNotBefore(rep.getNotBefore());
|
||||
}
|
||||
if (rep.getDefaultRoles() != null) {
|
||||
resource.updateDefaultRoles(rep.getDefaultRoles());
|
||||
}
|
||||
|
||||
List<String> redirectUris = rep.getRedirectUris();
|
||||
if (redirectUris != null) {
|
||||
resource.setRedirectUris(new HashSet<String>(redirectUris));
|
||||
}
|
||||
|
||||
List<String> webOrigins = rep.getWebOrigins();
|
||||
if (webOrigins != null) {
|
||||
resource.setWebOrigins(new HashSet<String>(webOrigins));
|
||||
}
|
||||
|
||||
if (rep.getClaims() != null) {
|
||||
ClaimManager.setClaims(resource, rep.getClaims());
|
||||
}
|
||||
}
|
||||
|
||||
public ApplicationRepresentation toRepresentation(ApplicationModel applicationModel) {
|
||||
ApplicationRepresentation rep = new ApplicationRepresentation();
|
||||
rep.setId(applicationModel.getId());
|
||||
rep.setName(applicationModel.getName());
|
||||
rep.setEnabled(applicationModel.isEnabled());
|
||||
rep.setAdminUrl(applicationModel.getManagementUrl());
|
||||
rep.setPublicClient(applicationModel.isPublicClient());
|
||||
rep.setBearerOnly(applicationModel.isBearerOnly());
|
||||
rep.setSurrogateAuthRequired(applicationModel.isSurrogateAuthRequired());
|
||||
rep.setBaseUrl(applicationModel.getBaseUrl());
|
||||
rep.setNotBefore(applicationModel.getNotBefore());
|
||||
|
||||
Set<String> redirectUris = applicationModel.getRedirectUris();
|
||||
if (redirectUris != null) {
|
||||
rep.setRedirectUris(new LinkedList<String>(redirectUris));
|
||||
}
|
||||
|
||||
Set<String> webOrigins = applicationModel.getWebOrigins();
|
||||
if (webOrigins != null) {
|
||||
rep.setWebOrigins(new LinkedList<String>(webOrigins));
|
||||
}
|
||||
|
||||
if (!applicationModel.getDefaultRoles().isEmpty()) {
|
||||
rep.setDefaultRoles(applicationModel.getDefaultRoles().toArray(new String[0]));
|
||||
}
|
||||
|
||||
return rep;
|
||||
|
||||
}
|
||||
|
||||
@JsonPropertyOrder({"realm", "realm-public-key", "bearer-only", "auth-server-url", "ssl-not-required",
|
||||
"resource", "public-client", "credentials",
|
||||
"use-resource-role-mappings"})
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
package org.keycloak.services.managers;
|
||||
|
||||
import org.keycloak.models.ClaimMask;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.representations.idm.ClaimRepresentation;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class ClaimManager {
|
||||
public static void setClaims(ClientModel model, ClaimRepresentation rep) {
|
||||
long mask = model.getAllowedClaimsMask();
|
||||
if (rep.getAddress()) {
|
||||
mask |= ClaimMask.ADDRESS;
|
||||
} else {
|
||||
mask &= ~ClaimMask.ADDRESS;
|
||||
}
|
||||
if (rep.getEmail()) {
|
||||
mask |= ClaimMask.EMAIL;
|
||||
} else {
|
||||
mask &= ~ClaimMask.EMAIL;
|
||||
}
|
||||
if (rep.getGender()) {
|
||||
mask |= ClaimMask.GENDER;
|
||||
} else {
|
||||
mask &= ~ClaimMask.GENDER;
|
||||
}
|
||||
if (rep.getLocale()) {
|
||||
mask |= ClaimMask.LOCALE;
|
||||
} else {
|
||||
mask &= ~ClaimMask.LOCALE;
|
||||
}
|
||||
if (rep.getName()) {
|
||||
mask |= ClaimMask.NAME;
|
||||
} else {
|
||||
mask &= ~ClaimMask.NAME;
|
||||
}
|
||||
if (rep.getPhone()) {
|
||||
mask |= ClaimMask.PHONE;
|
||||
} else {
|
||||
mask &= ~ClaimMask.PHONE;
|
||||
}
|
||||
if (rep.getPicture()) {
|
||||
mask |= ClaimMask.PICTURE;
|
||||
} else {
|
||||
mask &= ~ClaimMask.PICTURE;
|
||||
}
|
||||
if (rep.getProfile()) {
|
||||
mask |= ClaimMask.PROFILE;
|
||||
} else {
|
||||
mask &= ~ClaimMask.PROFILE;
|
||||
}
|
||||
if (rep.getUsername()) {
|
||||
mask |= ClaimMask.USERNAME;
|
||||
} else {
|
||||
mask &= ~ClaimMask.USERNAME;
|
||||
}
|
||||
if (rep.getWebsite()) {
|
||||
mask |= ClaimMask.WEBSITE;
|
||||
} else {
|
||||
mask &= ~ClaimMask.WEBSITE;
|
||||
}
|
||||
model.setAllowedClaimsMask(mask);
|
||||
}
|
||||
}
|
|
@ -2,22 +2,15 @@ package org.keycloak.services.managers;
|
|||
|
||||
import org.codehaus.jackson.annotate.JsonProperty;
|
||||
import org.codehaus.jackson.annotate.JsonPropertyOrder;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.OAuthClientModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserSessionProvider;
|
||||
import org.keycloak.representations.adapters.config.BaseRealmConfig;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.OAuthClientRepresentation;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
|
@ -26,35 +19,11 @@ import java.util.Set;
|
|||
public class OAuthClientManager {
|
||||
|
||||
private RealmManager realmManager;
|
||||
protected RealmModel realm;
|
||||
|
||||
public OAuthClientManager(RealmModel realm) {
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
public OAuthClientManager(RealmManager realmManager) {
|
||||
this.realmManager = realmManager;
|
||||
}
|
||||
|
||||
public UserCredentialModel generateSecret(OAuthClientModel app) {
|
||||
UserCredentialModel secret = UserCredentialModel.generateSecret();
|
||||
app.setSecret(secret.getValue());
|
||||
return secret;
|
||||
}
|
||||
|
||||
|
||||
public OAuthClientModel create(String name) {
|
||||
OAuthClientModel model = realm.addOAuthClient(name);
|
||||
generateSecret(model);
|
||||
return model;
|
||||
}
|
||||
|
||||
public OAuthClientModel create(OAuthClientRepresentation rep) {
|
||||
OAuthClientModel model = create(rep.getName());
|
||||
update(rep, model);
|
||||
return model;
|
||||
}
|
||||
|
||||
public boolean removeClient(RealmModel realm, OAuthClientModel client) {
|
||||
if (realm.removeOAuthClient(client.getId())) {
|
||||
UserSessionProvider sessions = realmManager.getSession().sessions();
|
||||
|
@ -67,58 +36,6 @@ public class OAuthClientManager {
|
|||
}
|
||||
}
|
||||
|
||||
public void update(OAuthClientRepresentation rep, OAuthClientModel model) {
|
||||
if (rep.getName() != null) model.setClientId(rep.getName());
|
||||
if (rep.isEnabled() != null) model.setEnabled(rep.isEnabled());
|
||||
if (rep.isPublicClient() != null) model.setPublicClient(rep.isPublicClient());
|
||||
if (rep.isDirectGrantsOnly() != null) model.setDirectGrantsOnly(rep.isDirectGrantsOnly());
|
||||
if (rep.getClaims() != null) {
|
||||
ClaimManager.setClaims(model, rep.getClaims());
|
||||
}
|
||||
if (rep.getNotBefore() != null) {
|
||||
model.setNotBefore(rep.getNotBefore());
|
||||
}
|
||||
if (rep.getSecret() != null) model.setSecret(rep.getSecret());
|
||||
List<String> redirectUris = rep.getRedirectUris();
|
||||
if (redirectUris != null) {
|
||||
model.setRedirectUris(new HashSet<String>(redirectUris));
|
||||
}
|
||||
|
||||
List<String> webOrigins = rep.getWebOrigins();
|
||||
if (webOrigins != null) {
|
||||
model.setWebOrigins(new HashSet<String>(webOrigins));
|
||||
}
|
||||
|
||||
if (rep.getClaims() != null) {
|
||||
ClaimManager.setClaims(model, rep.getClaims());
|
||||
}
|
||||
|
||||
if (rep.getNotBefore() != null) {
|
||||
model.setNotBefore(rep.getNotBefore());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static OAuthClientRepresentation toRepresentation(OAuthClientModel model) {
|
||||
OAuthClientRepresentation rep = new OAuthClientRepresentation();
|
||||
rep.setId(model.getId());
|
||||
rep.setName(model.getClientId());
|
||||
rep.setEnabled(model.isEnabled());
|
||||
rep.setPublicClient(model.isPublicClient());
|
||||
rep.setDirectGrantsOnly(model.isDirectGrantsOnly());
|
||||
Set<String> redirectUris = model.getRedirectUris();
|
||||
if (redirectUris != null) {
|
||||
rep.setRedirectUris(new LinkedList<String>(redirectUris));
|
||||
}
|
||||
|
||||
Set<String> webOrigins = model.getWebOrigins();
|
||||
if (webOrigins != null) {
|
||||
rep.setWebOrigins(new LinkedList<String>(webOrigins));
|
||||
}
|
||||
rep.setNotBefore(model.getNotBefore());
|
||||
return rep;
|
||||
}
|
||||
|
||||
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-not-required",
|
||||
"resource", "public-client", "credentials"})
|
||||
public static class InstallationAdapterConfig extends BaseRealmConfig {
|
||||
|
|
|
@ -1,48 +1,25 @@
|
|||
package org.keycloak.services.managers;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.exportimport.util.ExportImportUtils;
|
||||
import org.keycloak.models.AccountRoles;
|
||||
import org.keycloak.models.AdminRoles;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.AuthenticationLinkModel;
|
||||
import org.keycloak.models.AuthenticationProviderModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelProvider;
|
||||
import org.keycloak.models.OAuthClientModel;
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.SocialLinkModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserModel.RequiredAction;
|
||||
import org.keycloak.models.UserSessionProvider;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.representations.idm.ApplicationRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticationLinkRepresentation;
|
||||
import org.keycloak.representations.idm.AuthenticationProviderRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.OAuthClientRepresentation;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.representations.idm.RealmAuditRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.representations.idm.ScopeMappingRepresentation;
|
||||
import org.keycloak.representations.idm.SocialLinkRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Per request object
|
||||
|
@ -128,10 +105,6 @@ public class RealmManager {
|
|||
adminConsole.addScopeMapping(adminRole);
|
||||
}
|
||||
|
||||
public String getMasterRealmAdminApplicationName(RealmModel realm) {
|
||||
return realm.getName() + "-realm";
|
||||
}
|
||||
|
||||
public String getRealmAdminApplicationName(RealmModel realm) {
|
||||
return "realm-management";
|
||||
}
|
||||
|
@ -162,80 +135,6 @@ public class RealmManager {
|
|||
return removed;
|
||||
}
|
||||
|
||||
public void generateRealmKeys(RealmModel realm) {
|
||||
KeyPair keyPair = null;
|
||||
try {
|
||||
keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
realm.setPrivateKey(keyPair.getPrivate());
|
||||
realm.setPublicKey(keyPair.getPublic());
|
||||
}
|
||||
|
||||
public void updateRealm(RealmRepresentation rep, RealmModel realm) {
|
||||
if (rep.getRealm() != null) {
|
||||
realm.setName(rep.getRealm());
|
||||
}
|
||||
if (rep.isEnabled() != null) realm.setEnabled(rep.isEnabled());
|
||||
if (rep.isSocial() != null) realm.setSocial(rep.isSocial());
|
||||
if (rep.isBruteForceProtected() != null) realm.setBruteForceProtected(rep.isBruteForceProtected());
|
||||
if (rep.getMaxFailureWaitSeconds() != null) realm.setMaxFailureWaitSeconds(rep.getMaxFailureWaitSeconds());
|
||||
if (rep.getMinimumQuickLoginWaitSeconds() != null) realm.setMinimumQuickLoginWaitSeconds(rep.getMinimumQuickLoginWaitSeconds());
|
||||
if (rep.getWaitIncrementSeconds() != null) realm.setWaitIncrementSeconds(rep.getWaitIncrementSeconds());
|
||||
if (rep.getQuickLoginCheckMilliSeconds() != null) realm.setQuickLoginCheckMilliSeconds(rep.getQuickLoginCheckMilliSeconds());
|
||||
if (rep.getMaxDeltaTimeSeconds() != null) realm.setMaxDeltaTimeSeconds(rep.getMaxDeltaTimeSeconds());
|
||||
if (rep.getFailureFactor() != null) realm.setFailureFactor(rep.getFailureFactor());
|
||||
if (rep.isPasswordCredentialGrantAllowed() != null) realm.setPasswordCredentialGrantAllowed(rep.isPasswordCredentialGrantAllowed());
|
||||
if (rep.isRegistrationAllowed() != null) realm.setRegistrationAllowed(rep.isRegistrationAllowed());
|
||||
if (rep.isRememberMe() != null) realm.setRememberMe(rep.isRememberMe());
|
||||
if (rep.isVerifyEmail() != null) realm.setVerifyEmail(rep.isVerifyEmail());
|
||||
if (rep.isResetPasswordAllowed() != null) realm.setResetPasswordAllowed(rep.isResetPasswordAllowed());
|
||||
if (rep.isUpdateProfileOnInitialSocialLogin() != null)
|
||||
realm.setUpdateProfileOnInitialSocialLogin(rep.isUpdateProfileOnInitialSocialLogin());
|
||||
if (rep.isSslNotRequired() != null) realm.setSslNotRequired((rep.isSslNotRequired()));
|
||||
if (rep.getAccessCodeLifespan() != null) realm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
|
||||
if (rep.getAccessCodeLifespanUserAction() != null)
|
||||
realm.setAccessCodeLifespanUserAction(rep.getAccessCodeLifespanUserAction());
|
||||
if (rep.getNotBefore() != null) realm.setNotBefore(rep.getNotBefore());
|
||||
if (rep.getAccessTokenLifespan() != null) realm.setAccessTokenLifespan(rep.getAccessTokenLifespan());
|
||||
if (rep.getSsoSessionIdleTimeout() != null) realm.setSsoSessionIdleTimeout(rep.getSsoSessionIdleTimeout());
|
||||
if (rep.getSsoSessionMaxLifespan() != null) realm.setSsoSessionMaxLifespan(rep.getSsoSessionMaxLifespan());
|
||||
if (rep.getRequiredCredentials() != null) {
|
||||
realm.updateRequiredCredentials(rep.getRequiredCredentials());
|
||||
}
|
||||
if (rep.getLoginTheme() != null) realm.setLoginTheme(rep.getLoginTheme());
|
||||
if (rep.getAccountTheme() != null) realm.setAccountTheme(rep.getAccountTheme());
|
||||
if (rep.getAdminTheme() != null) realm.setAdminTheme(rep.getAdminTheme());
|
||||
if (rep.getEmailTheme() != null) realm.setEmailTheme(rep.getEmailTheme());
|
||||
|
||||
if (rep.getPasswordPolicy() != null) realm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy()));
|
||||
|
||||
if (rep.getDefaultRoles() != null) {
|
||||
realm.updateDefaultRoles(rep.getDefaultRoles().toArray(new String[rep.getDefaultRoles().size()]));
|
||||
}
|
||||
|
||||
if (rep.getSmtpServer() != null) {
|
||||
realm.setSmtpConfig(new HashMap(rep.getSmtpServer()));
|
||||
}
|
||||
|
||||
if (rep.getSocialProviders() != null) {
|
||||
realm.setSocialConfig(new HashMap(rep.getSocialProviders()));
|
||||
}
|
||||
|
||||
if (rep.getLdapServer() != null) {
|
||||
realm.setLdapServerConfig(new HashMap(rep.getLdapServer()));
|
||||
}
|
||||
if (rep.getAuthenticationProviders() != null) {
|
||||
List<AuthenticationProviderModel> authProviderModels = convertAuthenticationProviders(rep.getAuthenticationProviders());
|
||||
realm.setAuthenticationProviders(authProviderModels);
|
||||
}
|
||||
|
||||
if ("GENERATE".equals(rep.getPublicKey())) {
|
||||
generateRealmKeys(realm);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateRealmAudit(RealmAuditRepresentation rep, RealmModel realm) {
|
||||
realm.setAuditEnabled(rep.isAuditEnabled());
|
||||
realm.setAuditExpiration(rep.getAuditExpiration() != null ? rep.getAuditExpiration() : 0);
|
||||
|
@ -262,7 +161,7 @@ public class RealmManager {
|
|||
|
||||
ApplicationManager applicationManager = new ApplicationManager(new RealmManager(session));
|
||||
|
||||
ApplicationModel realmAdminApp = applicationManager.createApplication(adminRealm, getMasterRealmAdminApplicationName(realm));
|
||||
ApplicationModel realmAdminApp = applicationManager.createApplication(adminRealm, ExportImportUtils.getMasterRealmAdminApplicationName(realm));
|
||||
realmAdminApp.setBearerOnly(true);
|
||||
realm.setMasterAdminApp(realmAdminApp);
|
||||
|
||||
|
@ -319,273 +218,7 @@ public class RealmManager {
|
|||
}
|
||||
|
||||
public void importRealm(RealmRepresentation rep, RealmModel newRealm) {
|
||||
newRealm.setName(rep.getRealm());
|
||||
if (rep.isEnabled() != null) newRealm.setEnabled(rep.isEnabled());
|
||||
if (rep.isSocial() != null) newRealm.setSocial(rep.isSocial());
|
||||
if (rep.isBruteForceProtected() != null) newRealm.setBruteForceProtected(rep.isBruteForceProtected());
|
||||
if (rep.getMaxFailureWaitSeconds() != null) newRealm.setMaxFailureWaitSeconds(rep.getMaxFailureWaitSeconds());
|
||||
if (rep.getMinimumQuickLoginWaitSeconds() != null) newRealm.setMinimumQuickLoginWaitSeconds(rep.getMinimumQuickLoginWaitSeconds());
|
||||
if (rep.getWaitIncrementSeconds() != null) newRealm.setWaitIncrementSeconds(rep.getWaitIncrementSeconds());
|
||||
if (rep.getQuickLoginCheckMilliSeconds() != null) newRealm.setQuickLoginCheckMilliSeconds(rep.getQuickLoginCheckMilliSeconds());
|
||||
if (rep.getMaxDeltaTimeSeconds() != null) newRealm.setMaxDeltaTimeSeconds(rep.getMaxDeltaTimeSeconds());
|
||||
if (rep.getFailureFactor() != null) newRealm.setFailureFactor(rep.getFailureFactor());
|
||||
|
||||
if (rep.getNotBefore() != null) newRealm.setNotBefore(rep.getNotBefore());
|
||||
|
||||
if (rep.getAccessTokenLifespan() != null) newRealm.setAccessTokenLifespan(rep.getAccessTokenLifespan());
|
||||
else newRealm.setAccessTokenLifespan(300);
|
||||
|
||||
if (rep.getSsoSessionIdleTimeout() != null) newRealm.setSsoSessionIdleTimeout(rep.getSsoSessionIdleTimeout());
|
||||
else newRealm.setSsoSessionIdleTimeout(600);
|
||||
if (rep.getSsoSessionMaxLifespan() != null) newRealm.setSsoSessionMaxLifespan(rep.getSsoSessionMaxLifespan());
|
||||
else newRealm.setSsoSessionMaxLifespan(36000);
|
||||
|
||||
if (rep.getAccessCodeLifespan() != null) newRealm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
|
||||
else newRealm.setAccessCodeLifespan(60);
|
||||
|
||||
if (rep.getAccessCodeLifespanUserAction() != null)
|
||||
newRealm.setAccessCodeLifespanUserAction(rep.getAccessCodeLifespanUserAction());
|
||||
else newRealm.setAccessCodeLifespanUserAction(300);
|
||||
|
||||
if (rep.isSslNotRequired() != null) newRealm.setSslNotRequired(rep.isSslNotRequired());
|
||||
if (rep.isPasswordCredentialGrantAllowed() != null) newRealm.setPasswordCredentialGrantAllowed(rep.isPasswordCredentialGrantAllowed());
|
||||
if (rep.isRegistrationAllowed() != null) newRealm.setRegistrationAllowed(rep.isRegistrationAllowed());
|
||||
if (rep.isRememberMe() != null) newRealm.setRememberMe(rep.isRememberMe());
|
||||
if (rep.isVerifyEmail() != null) newRealm.setVerifyEmail(rep.isVerifyEmail());
|
||||
if (rep.isResetPasswordAllowed() != null) newRealm.setResetPasswordAllowed(rep.isResetPasswordAllowed());
|
||||
if (rep.isUpdateProfileOnInitialSocialLogin() != null)
|
||||
newRealm.setUpdateProfileOnInitialSocialLogin(rep.isUpdateProfileOnInitialSocialLogin());
|
||||
if (rep.getPrivateKey() == null || rep.getPublicKey() == null) {
|
||||
generateRealmKeys(newRealm);
|
||||
} else {
|
||||
newRealm.setPrivateKeyPem(rep.getPrivateKey());
|
||||
newRealm.setPublicKeyPem(rep.getPublicKey());
|
||||
}
|
||||
if (rep.getLoginTheme() != null) newRealm.setLoginTheme(rep.getLoginTheme());
|
||||
if (rep.getAccountTheme() != null) newRealm.setAccountTheme(rep.getAccountTheme());
|
||||
if (rep.getAdminTheme() != null) newRealm.setAdminTheme(rep.getAdminTheme());
|
||||
if (rep.getEmailTheme() != null) newRealm.setEmailTheme(rep.getEmailTheme());
|
||||
|
||||
if (rep.getRequiredCredentials() != null) {
|
||||
for (String requiredCred : rep.getRequiredCredentials()) {
|
||||
addRequiredCredential(newRealm, requiredCred);
|
||||
}
|
||||
} else {
|
||||
addRequiredCredential(newRealm, CredentialRepresentation.PASSWORD);
|
||||
}
|
||||
|
||||
if (rep.getPasswordPolicy() != null) newRealm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy()));
|
||||
|
||||
if (rep.getApplications() != null) {
|
||||
Map<String, ApplicationModel> appMap = createApplications(rep, newRealm);
|
||||
}
|
||||
|
||||
if (rep.getRoles() != null) {
|
||||
if (rep.getRoles().getRealm() != null) { // realm roles
|
||||
for (RoleRepresentation roleRep : rep.getRoles().getRealm()) {
|
||||
createRole(newRealm, roleRep);
|
||||
}
|
||||
}
|
||||
if (rep.getRoles().getApplication() != null) {
|
||||
for (Map.Entry<String, List<RoleRepresentation>> entry : rep.getRoles().getApplication().entrySet()) {
|
||||
ApplicationModel app = newRealm.getApplicationByName(entry.getKey());
|
||||
if (app == null) {
|
||||
throw new RuntimeException("App doesn't exist in role definitions: " + entry.getKey());
|
||||
}
|
||||
for (RoleRepresentation roleRep : entry.getValue()) {
|
||||
RoleModel role = app.addRole(roleRep.getName());
|
||||
role.setDescription(roleRep.getDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
// now that all roles are created, re-iterate and set up composites
|
||||
if (rep.getRoles().getRealm() != null) { // realm roles
|
||||
for (RoleRepresentation roleRep : rep.getRoles().getRealm()) {
|
||||
RoleModel role = newRealm.getRole(roleRep.getName());
|
||||
addComposites(role, roleRep, newRealm);
|
||||
}
|
||||
}
|
||||
if (rep.getRoles().getApplication() != null) {
|
||||
for (Map.Entry<String, List<RoleRepresentation>> entry : rep.getRoles().getApplication().entrySet()) {
|
||||
ApplicationModel app = newRealm.getApplicationByName(entry.getKey());
|
||||
if (app == null) {
|
||||
throw new RuntimeException("App doesn't exist in role definitions: " + entry.getKey());
|
||||
}
|
||||
for (RoleRepresentation roleRep : entry.getValue()) {
|
||||
RoleModel role = app.getRole(roleRep.getName());
|
||||
addComposites(role, roleRep, newRealm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (rep.getDefaultRoles() != null) {
|
||||
for (String roleString : rep.getDefaultRoles()) {
|
||||
newRealm.addDefaultRole(roleString.trim());
|
||||
}
|
||||
}
|
||||
|
||||
if (rep.getOauthClients() != null) {
|
||||
createOAuthClients(rep, newRealm);
|
||||
}
|
||||
|
||||
|
||||
// Now that all possible roles and applications are created, create scope mappings
|
||||
|
||||
Map<String, ApplicationModel> appMap = newRealm.getApplicationNameMap();
|
||||
|
||||
if (rep.getApplicationScopeMappings() != null) {
|
||||
ApplicationManager manager = new ApplicationManager(this);
|
||||
for (Map.Entry<String, List<ScopeMappingRepresentation>> entry : rep.getApplicationScopeMappings().entrySet()) {
|
||||
ApplicationModel app = appMap.get(entry.getKey());
|
||||
if (app == null) {
|
||||
throw new RuntimeException("Unable to find application role mappings for app: " + entry.getKey());
|
||||
}
|
||||
manager.createScopeMappings(newRealm, app, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (rep.getScopeMappings() != null) {
|
||||
for (ScopeMappingRepresentation scope : rep.getScopeMappings()) {
|
||||
for (String roleString : scope.getRoles()) {
|
||||
RoleModel role = newRealm.getRole(roleString.trim());
|
||||
if (role == null) {
|
||||
role = newRealm.addRole(roleString.trim());
|
||||
}
|
||||
ClientModel client = newRealm.findClient(scope.getClient());
|
||||
client.addScopeMapping(role);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (rep.getSmtpServer() != null) {
|
||||
newRealm.setSmtpConfig(new HashMap(rep.getSmtpServer()));
|
||||
}
|
||||
|
||||
if (rep.getSocialProviders() != null) {
|
||||
newRealm.setSocialConfig(new HashMap(rep.getSocialProviders()));
|
||||
}
|
||||
if (rep.getLdapServer() != null) {
|
||||
newRealm.setLdapServerConfig(new HashMap(rep.getLdapServer()));
|
||||
}
|
||||
|
||||
if (rep.getAuthenticationProviders() != null) {
|
||||
List<AuthenticationProviderModel> authProviderModels = convertAuthenticationProviders(rep.getAuthenticationProviders());
|
||||
newRealm.setAuthenticationProviders(authProviderModels);
|
||||
} else {
|
||||
List<AuthenticationProviderModel> authProviderModels = Arrays.asList(AuthenticationProviderModel.DEFAULT_PROVIDER);
|
||||
newRealm.setAuthenticationProviders(authProviderModels);
|
||||
}
|
||||
|
||||
// create users and their role mappings and social mappings
|
||||
|
||||
if (rep.getUsers() != null) {
|
||||
for (UserRepresentation userRep : rep.getUsers()) {
|
||||
UserModel user = createUser(newRealm, userRep, appMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addComposites(RoleModel role, RoleRepresentation roleRep, RealmModel realm) {
|
||||
if (roleRep.getComposites() == null) return;
|
||||
if (roleRep.getComposites().getRealm() != null) {
|
||||
for (String roleStr : roleRep.getComposites().getRealm()) {
|
||||
RoleModel realmRole = realm.getRole(roleStr);
|
||||
if (realmRole == null) throw new RuntimeException("Unable to find composite realm role: " + roleStr);
|
||||
role.addCompositeRole(realmRole);
|
||||
}
|
||||
}
|
||||
if (roleRep.getComposites().getApplication() != null) {
|
||||
for (Map.Entry<String, List<String>> entry : roleRep.getComposites().getApplication().entrySet()) {
|
||||
ApplicationModel app = realm.getApplicationByName(entry.getKey());
|
||||
if (app == null) {
|
||||
throw new RuntimeException("App doesn't exist in role definitions: " + roleRep.getName());
|
||||
}
|
||||
for (String roleStr : entry.getValue()) {
|
||||
RoleModel appRole = app.getRole(roleStr);
|
||||
if (appRole == null) throw new RuntimeException("Unable to find composite app role: " + roleStr);
|
||||
role.addCompositeRole(appRole);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void createRole(RealmModel newRealm, RoleRepresentation roleRep) {
|
||||
RoleModel role = newRealm.addRole(roleRep.getName());
|
||||
if (roleRep.getDescription() != null) role.setDescription(roleRep.getDescription());
|
||||
}
|
||||
|
||||
public void createRole(RealmModel newRealm, ApplicationModel app, RoleRepresentation roleRep) {
|
||||
RoleModel role = app.addRole(roleRep.getName());
|
||||
if (roleRep.getDescription() != null) role.setDescription(roleRep.getDescription());
|
||||
}
|
||||
|
||||
|
||||
public UserModel createUser(RealmModel newRealm, UserRepresentation userRep, Map<String, ApplicationModel> appMap) {
|
||||
UserModel user = newRealm.addUser(userRep.getId(), userRep.getUsername(), false);
|
||||
user.setEnabled(userRep.isEnabled());
|
||||
user.setEmail(userRep.getEmail());
|
||||
user.setFirstName(userRep.getFirstName());
|
||||
user.setLastName(userRep.getLastName());
|
||||
if (userRep.getAttributes() != null) {
|
||||
for (Map.Entry<String, String> entry : userRep.getAttributes().entrySet()) {
|
||||
user.setAttribute(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
if (userRep.getRequiredActions() != null) {
|
||||
for (String requiredAction : userRep.getRequiredActions()) {
|
||||
user.addRequiredAction(RequiredAction.valueOf(requiredAction));
|
||||
}
|
||||
}
|
||||
if (userRep.getCredentials() != null) {
|
||||
for (CredentialRepresentation cred : userRep.getCredentials()) {
|
||||
UserCredentialModel credential = fromRepresentation(cred);
|
||||
user.updateCredential(credential);
|
||||
}
|
||||
}
|
||||
if (userRep.getAuthenticationLink() != null) {
|
||||
AuthenticationLinkRepresentation link = userRep.getAuthenticationLink();
|
||||
AuthenticationLinkModel authLink = new AuthenticationLinkModel(link.getAuthProvider(), link.getAuthUserId());
|
||||
user.setAuthenticationLink(authLink);
|
||||
}
|
||||
if (userRep.getSocialLinks() != null) {
|
||||
for (SocialLinkRepresentation socialLink : userRep.getSocialLinks()) {
|
||||
SocialLinkModel mappingModel = new SocialLinkModel(socialLink.getSocialProvider(), socialLink.getSocialUserId(), socialLink.getSocialUsername());
|
||||
newRealm.addSocialLink(user, mappingModel);
|
||||
}
|
||||
}
|
||||
if (userRep.getRealmRoles() != null) {
|
||||
for (String roleString : userRep.getRealmRoles()) {
|
||||
RoleModel role = newRealm.getRole(roleString.trim());
|
||||
if (role == null) {
|
||||
role = newRealm.addRole(roleString.trim());
|
||||
}
|
||||
user.grantRole(role);
|
||||
}
|
||||
}
|
||||
if (userRep.getApplicationRoles() != null) {
|
||||
ApplicationManager manager = new ApplicationManager(this);
|
||||
for (Map.Entry<String, List<String>> entry : userRep.getApplicationRoles().entrySet()) {
|
||||
ApplicationModel app = appMap.get(entry.getKey());
|
||||
if (app == null) {
|
||||
throw new RuntimeException("Unable to find application role mappings for app: " + entry.getKey());
|
||||
}
|
||||
manager.createRoleMappings(app, user, entry.getValue());
|
||||
}
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
public static UserCredentialModel fromRepresentation(CredentialRepresentation cred) {
|
||||
UserCredentialModel credential = new UserCredentialModel();
|
||||
credential.setType(cred.getType());
|
||||
credential.setValue(cred.getValue());
|
||||
return credential;
|
||||
RepresentationToModel.importRealm(rep, newRealm);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -606,37 +239,4 @@ public class RealmManager {
|
|||
return realmModel.searchForUser(searchString.trim());
|
||||
}
|
||||
|
||||
public void addRequiredCredential(RealmModel newRealm, String requiredCred) {
|
||||
newRealm.addRequiredCredential(requiredCred);
|
||||
}
|
||||
|
||||
protected Map<String, ApplicationModel> createApplications(RealmRepresentation rep, RealmModel realm) {
|
||||
Map<String, ApplicationModel> appMap = new HashMap<String, ApplicationModel>();
|
||||
ApplicationManager manager = new ApplicationManager(this);
|
||||
for (ApplicationRepresentation resourceRep : rep.getApplications()) {
|
||||
ApplicationModel app = manager.createApplication(realm, resourceRep);
|
||||
appMap.put(app.getName(), app);
|
||||
}
|
||||
return appMap;
|
||||
}
|
||||
|
||||
protected void createOAuthClients(RealmRepresentation realmRep, RealmModel realm) {
|
||||
OAuthClientManager manager = new OAuthClientManager(realm);
|
||||
for (OAuthClientRepresentation rep : realmRep.getOauthClients()) {
|
||||
OAuthClientModel app = manager.create(rep);
|
||||
}
|
||||
}
|
||||
|
||||
protected List<AuthenticationProviderModel> convertAuthenticationProviders(List<AuthenticationProviderRepresentation> authenticationProviders) {
|
||||
List<AuthenticationProviderModel> result = new ArrayList<AuthenticationProviderModel>();
|
||||
|
||||
for (AuthenticationProviderRepresentation representation : authenticationProviders) {
|
||||
AuthenticationProviderModel model = new AuthenticationProviderModel(representation.getProviderName(),
|
||||
representation.isPasswordUpdateSupported(), representation.getConfig());
|
||||
result.add(model);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ import org.keycloak.services.ForbiddenException;
|
|||
import org.keycloak.services.managers.AppAuthManager;
|
||||
import org.keycloak.services.managers.Auth;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.managers.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.services.messages.Messages;
|
||||
import org.keycloak.services.resources.flows.Flows;
|
||||
import org.keycloak.services.resources.flows.OAuthRedirect;
|
||||
|
|
|
@ -7,7 +7,7 @@ import org.jboss.resteasy.core.Dispatcher;
|
|||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.SkeletonKeyContextResolver;
|
||||
import org.keycloak.exportimport.ExportImportProvider;
|
||||
import org.keycloak.exportimport.ExportImportManager;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
@ -24,7 +24,6 @@ import org.keycloak.services.scheduled.ScheduledTaskRunner;
|
|||
import org.keycloak.services.util.JsonConfigProvider;
|
||||
import org.keycloak.timer.TimerProvider;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
import org.keycloak.util.ProviderLoader;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.ws.rs.core.Application;
|
||||
|
@ -38,7 +37,6 @@ import java.io.InputStream;
|
|||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
|
@ -81,7 +79,7 @@ public class KeycloakApplication extends Application {
|
|||
classes.add(JsResource.class);
|
||||
classes.add(WelcomeResource.class);
|
||||
|
||||
checkExportImportProvider();
|
||||
new ExportImportManager().checkExportImport(this.sessionFactory);
|
||||
|
||||
setupDefaultRealm(context.getContextPath());
|
||||
|
||||
|
@ -235,16 +233,4 @@ public class KeycloakApplication extends Application {
|
|||
}
|
||||
}
|
||||
|
||||
protected void checkExportImportProvider() {
|
||||
Iterator<ExportImportProvider> providers = ProviderLoader.load(ExportImportProvider.class).iterator();
|
||||
|
||||
if (providers.hasNext()) {
|
||||
ExportImportProvider exportImport = providers.next();
|
||||
exportImport.checkExportImport(sessionFactory);
|
||||
} else {
|
||||
log.warn("No ExportImportProvider found!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -10,13 +10,15 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.representations.adapters.action.SessionStats;
|
||||
import org.keycloak.representations.adapters.action.UserStats;
|
||||
import org.keycloak.representations.idm.ApplicationRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.UserSessionRepresentation;
|
||||
import org.keycloak.services.managers.ApplicationManager;
|
||||
import org.keycloak.services.managers.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.ResourceAdminManager;
|
||||
import org.keycloak.services.resources.KeycloakApplication;
|
||||
|
@ -97,7 +99,7 @@ public class ApplicationResource {
|
|||
|
||||
ApplicationManager applicationManager = new ApplicationManager(new RealmManager(session));
|
||||
try {
|
||||
applicationManager.updateApplication(rep, application);
|
||||
RepresentationToModel.updateApplication(rep, application);
|
||||
return Response.noContent().build();
|
||||
} catch (ModelDuplicateException e) {
|
||||
return Flows.errors().exists("Application " + rep.getName() + " already exists");
|
||||
|
@ -116,8 +118,7 @@ public class ApplicationResource {
|
|||
public ApplicationRepresentation getApplication() {
|
||||
auth.requireView();
|
||||
|
||||
ApplicationManager applicationManager = new ApplicationManager(new RealmManager(session));
|
||||
return applicationManager.toRepresentation(application);
|
||||
return ModelToRepresentation.toRepresentation(application);
|
||||
}
|
||||
|
||||
|
||||
|
@ -184,7 +185,7 @@ public class ApplicationResource {
|
|||
auth.requireManage();
|
||||
|
||||
logger.debug("regenerateSecret");
|
||||
UserCredentialModel cred = new ApplicationManager().generateSecret(application);
|
||||
UserCredentialModel cred = KeycloakModelUtils.generateSecret(application);
|
||||
CredentialRepresentation rep = ModelToRepresentation.toRepresentation(cred);
|
||||
return rep;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ import org.keycloak.models.ApplicationModel;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.representations.idm.ApplicationRepresentation;
|
||||
import org.keycloak.services.managers.ApplicationManager;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
|
@ -60,12 +62,11 @@ public class ApplicationsResource {
|
|||
|
||||
List<ApplicationRepresentation> rep = new ArrayList<ApplicationRepresentation>();
|
||||
List<ApplicationModel> applicationModels = realm.getApplications();
|
||||
ApplicationManager resourceManager = new ApplicationManager(new RealmManager(session));
|
||||
|
||||
boolean view = auth.hasView();
|
||||
for (ApplicationModel applicationModel : applicationModels) {
|
||||
if (view) {
|
||||
rep.add(resourceManager.toRepresentation(applicationModel));
|
||||
rep.add(ModelToRepresentation.toRepresentation(applicationModel));
|
||||
} else {
|
||||
ApplicationRepresentation app = new ApplicationRepresentation();
|
||||
app.setName(applicationModel.getName());
|
||||
|
@ -87,9 +88,8 @@ public class ApplicationsResource {
|
|||
public Response createApplication(final @Context UriInfo uriInfo, final ApplicationRepresentation rep) {
|
||||
auth.requireManage();
|
||||
|
||||
ApplicationManager resourceManager = new ApplicationManager(new RealmManager(session));
|
||||
try {
|
||||
ApplicationModel applicationModel = resourceManager.createApplication(realm, rep);
|
||||
ApplicationModel applicationModel = RepresentationToModel.createApplication(realm, rep);
|
||||
return Response.created(uriInfo.getAbsolutePathBuilder().path(applicationModel.getName()).build()).build();
|
||||
} catch (ModelDuplicateException e) {
|
||||
return Flows.errors().exists("Application " + rep.getName() + " already exists");
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package org.keycloak.services.resources.admin;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.representations.idm.ClaimRepresentation;
|
||||
import org.keycloak.services.managers.ClaimManager;
|
||||
import org.keycloak.services.managers.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
|
@ -47,6 +47,6 @@ public class ClaimResource {
|
|||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void updateClaims(ClaimRepresentation rep) {
|
||||
auth.requireManage();
|
||||
ClaimManager.setClaims(model, rep);
|
||||
RepresentationToModel.setClaims(model, rep);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,10 @@ import org.keycloak.models.ModelDuplicateException;
|
|||
import org.keycloak.models.OAuthClientModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.OAuthClientRepresentation;
|
||||
import org.keycloak.services.managers.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.services.managers.OAuthClientManager;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.resources.KeycloakApplication;
|
||||
|
@ -82,9 +83,8 @@ public class OAuthClientResource {
|
|||
public Response update(final OAuthClientRepresentation rep) {
|
||||
auth.requireManage();
|
||||
|
||||
OAuthClientManager manager = new OAuthClientManager(realm);
|
||||
try {
|
||||
manager.update(rep, oauthClient);
|
||||
RepresentationToModel.updateOAuthClient(rep, oauthClient);
|
||||
return Response.noContent().build();
|
||||
} catch (ModelDuplicateException e) {
|
||||
return Flows.errors().exists("Client " + rep.getName() + " already exists");
|
||||
|
@ -102,7 +102,7 @@ public class OAuthClientResource {
|
|||
public OAuthClientRepresentation getOAuthClient() {
|
||||
auth.requireView();
|
||||
|
||||
return OAuthClientManager.toRepresentation(oauthClient);
|
||||
return ModelToRepresentation.toRepresentation(oauthClient);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -118,7 +118,7 @@ public class OAuthClientResource {
|
|||
public String getInstallation() throws IOException {
|
||||
auth.requireView();
|
||||
|
||||
OAuthClientManager manager = new OAuthClientManager(realm);
|
||||
OAuthClientManager manager = new OAuthClientManager();
|
||||
Object rep = manager.toInstallationRepresentation(realm, oauthClient, getApplication().getBaseUri(uriInfo));
|
||||
|
||||
// TODO Temporary solution to pretty-print
|
||||
|
|
|
@ -8,6 +8,8 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.OAuthClientModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.representations.idm.OAuthClientRepresentation;
|
||||
import org.keycloak.services.managers.OAuthClientManager;
|
||||
import org.keycloak.services.resources.flows.Flows;
|
||||
|
@ -65,7 +67,7 @@ public class OAuthClientsResource {
|
|||
boolean view = auth.hasView();
|
||||
for (OAuthClientModel oauth : oauthModels) {
|
||||
if (view) {
|
||||
rep.add(OAuthClientManager.toRepresentation(oauth));
|
||||
rep.add(ModelToRepresentation.toRepresentation(oauth));
|
||||
} else {
|
||||
OAuthClientRepresentation client = new OAuthClientRepresentation();
|
||||
client.setName(oauth.getClientId());
|
||||
|
@ -87,9 +89,8 @@ public class OAuthClientsResource {
|
|||
public Response createOAuthClient(final @Context UriInfo uriInfo, final OAuthClientRepresentation rep) {
|
||||
auth.requireManage();
|
||||
|
||||
OAuthClientManager resourceManager = new OAuthClientManager(realm);
|
||||
try {
|
||||
OAuthClientModel oauth = resourceManager.create(rep);
|
||||
OAuthClientModel oauth = RepresentationToModel.createOAuthClient(rep, realm);
|
||||
return Response.created(uriInfo.getAbsolutePathBuilder().path(oauth.getId()).build()).build();
|
||||
} catch (ModelDuplicateException e) {
|
||||
return Flows.errors().exists("Client " + rep.getName() + " already exists");
|
||||
|
|
|
@ -13,11 +13,12 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.representations.adapters.action.SessionStats;
|
||||
import org.keycloak.representations.idm.RealmAuditRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.services.managers.LDAPConnectionTestManager;
|
||||
import org.keycloak.services.managers.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.ResourceAdminManager;
|
||||
import org.keycloak.services.managers.TokenManager;
|
||||
|
@ -138,7 +139,7 @@ public class RealmAdminResource {
|
|||
|
||||
logger.debug("updating realm: " + realm.getName());
|
||||
try {
|
||||
new RealmManager(session).updateRealm(rep, realm);
|
||||
RepresentationToModel.updateRealm(rep, realm);
|
||||
return Response.noContent().build();
|
||||
} catch (ModelDuplicateException e) {
|
||||
return Flows.errors().exists("Realm " + rep.getRealm() + " already exists");
|
||||
|
|
|
@ -14,7 +14,7 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.services.ForbiddenException;
|
||||
import org.keycloak.services.managers.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.TokenManager;
|
||||
import org.keycloak.services.resources.KeycloakApplication;
|
||||
|
|
|
@ -2,13 +2,12 @@ package org.keycloak.services.resources.admin;
|
|||
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.jboss.resteasy.spi.NotFoundException;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleContainerModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.services.managers.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.services.resources.flows.Flows;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
|
|
|
@ -5,7 +5,7 @@ import org.keycloak.models.ApplicationModel;
|
|||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.services.managers.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
|
|
|
@ -7,12 +7,10 @@ import org.keycloak.models.ClientModel;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.ApplicationMappingsRepresentation;
|
||||
import org.keycloak.representations.idm.MappingsRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.services.managers.ModelToRepresentation;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.keycloak.models.SocialLinkModel;
|
|||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.representations.adapters.action.UserStats;
|
||||
import org.keycloak.representations.idm.ApplicationMappingsRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
|
@ -26,7 +27,7 @@ import org.keycloak.representations.idm.SocialLinkRepresentation;
|
|||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.idm.UserSessionRepresentation;
|
||||
import org.keycloak.services.managers.AccessCodeEntry;
|
||||
import org.keycloak.services.managers.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.managers.ResourceAdminManager;
|
||||
import org.keycloak.services.managers.TokenManager;
|
||||
|
@ -760,7 +761,7 @@ public class UsersResource {
|
|||
throw new BadRequestException("No password provided");
|
||||
}
|
||||
|
||||
UserCredentialModel cred = RealmManager.fromRepresentation(pass);
|
||||
UserCredentialModel cred = RepresentationToModel.convertCredential(pass);
|
||||
user.updateCredential(cred);
|
||||
user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
|
||||
}
|
||||
|
|
|
@ -289,7 +289,17 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-export-import-impl</artifactId>
|
||||
<artifactId>keycloak-export-import-dir</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-export-import-single-file</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-export-import-zip</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.services.managers.ApplicationManager;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
|
@ -59,7 +60,7 @@ public class CompositeRoleTest {
|
|||
@Override
|
||||
protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
|
||||
RealmModel realm = manager.createRealm("Test");
|
||||
manager.generateRealmKeys(realm);
|
||||
KeycloakModelUtils.generateRealmKeys(realm);
|
||||
realmPublicKey = realm.getPublicKey();
|
||||
realm.setSsoSessionIdleTimeout(3000);
|
||||
realm.setAccessTokenLifespan(10000);
|
||||
|
|
|
@ -0,0 +1,269 @@
|
|||
package org.keycloak.testsuite.exportimport;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.exportimport.ExportImportConfig;
|
||||
import org.keycloak.exportimport.dir.DirExportProvider;
|
||||
import org.keycloak.exportimport.dir.DirExportProviderFactory;
|
||||
import org.keycloak.exportimport.singlefile.SingleFileExportProviderFactory;
|
||||
import org.keycloak.exportimport.zip.ZipExportProviderFactory;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ModelProvider;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||
import org.keycloak.testutils.KeycloakServer;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ExportImportTest {
|
||||
|
||||
@ClassRule
|
||||
public static KeycloakRule keycloakRule = new KeycloakRule( new KeycloakRule.KeycloakSetup() {
|
||||
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
addUser(appRealm, "user1", "password");
|
||||
addUser(appRealm, "user2", "password");
|
||||
addUser(appRealm, "user3", "password");
|
||||
addUser(adminstrationRealm, "admin2", "admin2");
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@Test
|
||||
public void testDirFullExportImport() throws Throwable {
|
||||
ExportImportConfig.setProvider(DirExportProviderFactory.PROVIDER_ID);
|
||||
String targetDirPath = getExportImportTestDirectory() + File.separator + "dirExport";
|
||||
DirExportProvider.recursiveDeleteDir(new File(targetDirPath));
|
||||
ExportImportConfig.setDir(targetDirPath);
|
||||
ExportImportConfig.setUsersPerFile(ExportImportConfig.DEFAULT_USERS_PER_FILE);
|
||||
|
||||
testFullExportImport();
|
||||
|
||||
// There should be 4 files in target directory (2 realm, 2 user)
|
||||
Assert.assertEquals(4, new File(targetDirPath).listFiles().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDirRealmExportImport() throws Throwable {
|
||||
ExportImportConfig.setProvider(DirExportProviderFactory.PROVIDER_ID);
|
||||
String targetDirPath = getExportImportTestDirectory() + File.separator + "dirRealmExport";
|
||||
DirExportProvider.recursiveDeleteDir(new File(targetDirPath));
|
||||
ExportImportConfig.setDir(targetDirPath);
|
||||
ExportImportConfig.setUsersPerFile(3);
|
||||
|
||||
testRealmExportImport();
|
||||
|
||||
// There should be 3 files in target directory (1 realm, 2 user)
|
||||
Assert.assertEquals(3, new File(targetDirPath).listFiles().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleFileFullExportImport() throws Throwable {
|
||||
ExportImportConfig.setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
|
||||
String targetFilePath = getExportImportTestDirectory() + File.separator + "singleFile-full.json";
|
||||
ExportImportConfig.setFile(targetFilePath);
|
||||
|
||||
testFullExportImport();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleFileRealmExportImport() throws Throwable {
|
||||
ExportImportConfig.setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
|
||||
String targetFilePath = getExportImportTestDirectory() + File.separator + "singleFile-realm.json";
|
||||
ExportImportConfig.setFile(targetFilePath);
|
||||
|
||||
testRealmExportImport();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZipFullExportImport() throws Throwable {
|
||||
ExportImportConfig.setProvider(ZipExportProviderFactory.PROVIDER_ID);
|
||||
String zipFilePath = getExportImportTestDirectory() + File.separator + "export-full.zip";
|
||||
new File(zipFilePath).delete();
|
||||
ExportImportConfig.setZipFile(zipFilePath);
|
||||
ExportImportConfig.setZipPassword("encPassword");
|
||||
ExportImportConfig.setUsersPerFile(ExportImportConfig.DEFAULT_USERS_PER_FILE);
|
||||
|
||||
testFullExportImport();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZipRealmExportImport() throws Throwable {
|
||||
ExportImportConfig.setProvider(ZipExportProviderFactory.PROVIDER_ID);
|
||||
String zipFilePath = getExportImportTestDirectory() + File.separator + "export-realm.zip";
|
||||
new File(zipFilePath).delete();
|
||||
ExportImportConfig.setZipFile(zipFilePath);
|
||||
ExportImportConfig.setZipPassword("encPassword");
|
||||
ExportImportConfig.setUsersPerFile(3);
|
||||
|
||||
testRealmExportImport();
|
||||
}
|
||||
|
||||
private void testFullExportImport() {
|
||||
ExportImportConfig.setAction(ExportImportConfig.ACTION_EXPORT);
|
||||
ExportImportConfig.setRealmName(null);
|
||||
|
||||
// Restart server, which triggers export
|
||||
keycloakRule.restartServer();
|
||||
|
||||
// Delete some realm (and some data in admin realm)
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
try {
|
||||
ModelProvider model = session.getModel();
|
||||
model.removeRealm(model.getRealmByName("test").getId());
|
||||
Assert.assertEquals(1, model.getRealms().size());
|
||||
|
||||
RealmModel master = model.getRealmByName(Config.getAdminRealm());
|
||||
master.removeUser("admin2");
|
||||
|
||||
assertNotAuthenticated(model, Config.getAdminRealm(), "admin2", "admin2");
|
||||
assertNotAuthenticated(model, "test", "test-user@localhost", "password");
|
||||
assertNotAuthenticated(model, "test", "user1", "password");
|
||||
assertNotAuthenticated(model, "test", "user2", "password");
|
||||
assertNotAuthenticated(model, "test", "user3", "password");
|
||||
} finally {
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
|
||||
// Configure import
|
||||
ExportImportConfig.setAction(ExportImportConfig.ACTION_IMPORT);
|
||||
|
||||
// Restart server, which triggers import
|
||||
keycloakRule.restartServer();
|
||||
|
||||
// Ensure data are imported back
|
||||
session = keycloakRule.startSession();
|
||||
try {
|
||||
ModelProvider model = session.getModel();
|
||||
Assert.assertEquals(2, model.getRealms().size());
|
||||
|
||||
assertAuthenticated(model, Config.getAdminRealm(), "admin2", "admin2");
|
||||
assertAuthenticated(model, "test", "test-user@localhost", "password");
|
||||
assertAuthenticated(model, "test", "user1", "password");
|
||||
assertAuthenticated(model, "test", "user2", "password");
|
||||
assertAuthenticated(model, "test", "user3", "password");
|
||||
|
||||
} finally {
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void testRealmExportImport() {
|
||||
ExportImportConfig.setAction(ExportImportConfig.ACTION_EXPORT);
|
||||
ExportImportConfig.setRealmName("test");
|
||||
|
||||
// Restart server, which triggers export
|
||||
keycloakRule.restartServer();
|
||||
|
||||
// Delete some realm (and some data in admin realm)
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
try {
|
||||
ModelProvider model = session.getModel();
|
||||
model.removeRealm(model.getRealmByName("test").getId());
|
||||
Assert.assertEquals(1, model.getRealms().size());
|
||||
|
||||
RealmModel master = model.getRealmByName(Config.getAdminRealm());
|
||||
master.removeUser("admin2");
|
||||
|
||||
assertNotAuthenticated(model, Config.getAdminRealm(), "admin2", "admin2");
|
||||
assertNotAuthenticated(model, "test", "test-user@localhost", "password");
|
||||
assertNotAuthenticated(model, "test", "user1", "password");
|
||||
assertNotAuthenticated(model, "test", "user2", "password");
|
||||
assertNotAuthenticated(model, "test", "user3", "password");
|
||||
} finally {
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
|
||||
// Configure import
|
||||
ExportImportConfig.setAction(ExportImportConfig.ACTION_IMPORT);
|
||||
|
||||
// Restart server, which triggers import
|
||||
keycloakRule.restartServer();
|
||||
|
||||
// Ensure data are imported back, but just for "test" realm
|
||||
session = keycloakRule.startSession();
|
||||
try {
|
||||
ModelProvider model = session.getModel();
|
||||
Assert.assertEquals(2, model.getRealms().size());
|
||||
|
||||
assertNotAuthenticated(model, Config.getAdminRealm(), "admin2", "admin2");
|
||||
assertAuthenticated(model, "test", "test-user@localhost", "password");
|
||||
assertAuthenticated(model, "test", "user1", "password");
|
||||
assertAuthenticated(model, "test", "user2", "password");
|
||||
assertAuthenticated(model, "test", "user3", "password");
|
||||
|
||||
addUser(model.getRealmByName(Config.getAdminRealm()), "admin2", "admin2");
|
||||
} finally {
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertAuthenticated(ModelProvider model, String realmName, String username, String password) {
|
||||
RealmModel realm = model.getRealmByName(realmName);
|
||||
if (realm == null) {
|
||||
Assert.fail("realm " + realmName + " not found");
|
||||
}
|
||||
|
||||
UserModel user = realm.getUser(username);
|
||||
if (user == null) {
|
||||
Assert.fail("user " + username + " not found");
|
||||
}
|
||||
|
||||
Assert.assertTrue(realm.validatePassword(user, password));
|
||||
}
|
||||
|
||||
private void assertNotAuthenticated(ModelProvider model, String realmName, String username, String password) {
|
||||
RealmModel realm = model.getRealmByName(realmName);
|
||||
if (realm == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
UserModel user = realm.getUser(username);
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.assertFalse(realm.validatePassword(user, password));
|
||||
}
|
||||
|
||||
private static void addUser(RealmModel appRealm, String username, String password) {
|
||||
UserModel user = appRealm.addUser(username);
|
||||
user.setEmail(username + "@test.com");
|
||||
user.setEnabled(true);
|
||||
|
||||
UserCredentialModel creds = new UserCredentialModel();
|
||||
creds.setType(CredentialRepresentation.PASSWORD);
|
||||
creds.setValue(password);
|
||||
user.updateCredential(creds);
|
||||
}
|
||||
|
||||
private String getExportImportTestDirectory() {
|
||||
String dirPath = null;
|
||||
String relativeDirExportImportPath = "testsuite" + File.separator + "integration" + File.separator + "target" + File.separator + "export-import";
|
||||
|
||||
if (System.getProperties().containsKey("maven.home")) {
|
||||
dirPath = System.getProperty("user.dir").replaceFirst("testsuite.integration.*", relativeDirExportImportPath);
|
||||
} else {
|
||||
for (String c : System.getProperty("java.class.path").split(File.pathSeparator)) {
|
||||
if (c.contains(File.separator + "testsuite" + File.separator + "integration")) {
|
||||
dirPath = c.replaceFirst("testsuite.integration.*", relativeDirExportImportPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String absolutePath = new File(dirPath).getAbsolutePath();
|
||||
return absolutePath;
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.services.managers.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.testutils.KeycloakServer;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
@ -146,4 +146,13 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
|
|||
}
|
||||
session.close();
|
||||
}
|
||||
|
||||
public void restartServer() {
|
||||
try {
|
||||
server.stop();
|
||||
server.start();
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package org.keycloak.test.tools;
|
||||
|
||||
import org.keycloak.exportimport.ExportImportConfig;
|
||||
import org.keycloak.exportimport.ExportImportProvider;
|
||||
import org.keycloak.exportimport.ExportProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
@ -231,10 +231,10 @@ public class PerfTools {
|
|||
ExportImportConfig.setProvider("dir");
|
||||
ExportImportConfig.setDir(dir);
|
||||
|
||||
Iterator<ExportImportProvider> providers = ProviderLoader.load(ExportImportProvider.class).iterator();
|
||||
Iterator<ExportProvider> providers = ProviderLoader.load(ExportProvider.class).iterator();
|
||||
|
||||
if (providers.hasNext()) {
|
||||
ExportImportProvider exportImport = providers.next();
|
||||
ExportProvider exportImport = providers.next();
|
||||
exportImport.checkExportImport(sessionFactory);
|
||||
} else {
|
||||
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
|
||||
|
|
Loading…
Reference in a new issue