Added 'keycloak-server.json' for configuring the server
Added SPI interface to detect SPI's Converted Model to SPI/Provider to be loaded through ProviderSessionFactory
This commit is contained in:
parent
a3ed02ea16
commit
855269f35d
97 changed files with 1354 additions and 1355 deletions
|
@ -5,10 +5,8 @@ import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
import org.keycloak.provider.ProviderFactoryLoader;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package org.keycloak.audit;
|
||||||
|
|
||||||
|
import org.keycloak.provider.Provider;
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
import org.keycloak.provider.Spi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class AuditListenerSpi implements Spi {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "audit-listener";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Provider> getProviderClass() {
|
||||||
|
return AuditListener.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||||
|
return AuditListenerFactory.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package org.keycloak.audit;
|
||||||
|
|
||||||
|
import org.keycloak.provider.Provider;
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
import org.keycloak.provider.Spi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class AuditProviderSpi implements Spi {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "audit";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Provider> getProviderClass() {
|
||||||
|
return AuditProvider.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||||
|
return AuditProviderFactory.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
org.keycloak.audit.AuditProviderSpi
|
||||||
|
org.keycloak.audit.AuditListenerSpi
|
|
@ -1,10 +1,10 @@
|
||||||
package org.keycloak.audit.log;
|
package org.keycloak.audit.log;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.Config;
|
||||||
import org.keycloak.audit.AuditListener;
|
import org.keycloak.audit.AuditListener;
|
||||||
import org.keycloak.audit.AuditListenerFactory;
|
import org.keycloak.audit.AuditListenerFactory;
|
||||||
import org.keycloak.provider.ProviderSession;
|
import org.keycloak.provider.ProviderSession;
|
||||||
import org.keycloak.provider.ProviderSessionFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
@ -21,7 +21,7 @@ public class JBossLoggingAuditListenerFactory implements AuditListenerFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init(Config.Scope config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -33,9 +33,4 @@ public class JBossLoggingAuditListenerFactory implements AuditListenerFactory {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean lazyLoad() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package org.keycloak.audit.jpa;
|
package org.keycloak.audit.jpa;
|
||||||
|
|
||||||
|
import org.keycloak.Config;
|
||||||
import org.keycloak.audit.AuditProvider;
|
import org.keycloak.audit.AuditProvider;
|
||||||
import org.keycloak.audit.AuditProviderFactory;
|
import org.keycloak.audit.AuditProviderFactory;
|
||||||
import org.keycloak.provider.ProviderSession;
|
import org.keycloak.provider.ProviderSession;
|
||||||
import org.keycloak.provider.ProviderSessionFactory;
|
|
||||||
|
|
||||||
import javax.persistence.EntityManagerFactory;
|
import javax.persistence.EntityManagerFactory;
|
||||||
import javax.persistence.Persistence;
|
import javax.persistence.Persistence;
|
||||||
|
@ -22,7 +22,7 @@ public class JpaAuditProviderFactory implements AuditProviderFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init(Config.Scope config) {
|
||||||
emf = Persistence.createEntityManagerFactory("jpa-keycloak-audit-store");
|
emf = Persistence.createEntityManagerFactory("jpa-keycloak-audit-store");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,9 +36,4 @@ public class JpaAuditProviderFactory implements AuditProviderFactory {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean lazyLoad() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,16 @@ package org.keycloak.audit.mongo;
|
||||||
|
|
||||||
import com.mongodb.DB;
|
import com.mongodb.DB;
|
||||||
import com.mongodb.MongoClient;
|
import com.mongodb.MongoClient;
|
||||||
|
import com.mongodb.MongoCredential;
|
||||||
|
import com.mongodb.ServerAddress;
|
||||||
import com.mongodb.WriteConcern;
|
import com.mongodb.WriteConcern;
|
||||||
|
import org.keycloak.Config;
|
||||||
import org.keycloak.audit.AuditProvider;
|
import org.keycloak.audit.AuditProvider;
|
||||||
import org.keycloak.audit.AuditProviderFactory;
|
import org.keycloak.audit.AuditProviderFactory;
|
||||||
import org.keycloak.provider.ProviderSession;
|
import org.keycloak.provider.ProviderSession;
|
||||||
import org.keycloak.provider.ProviderSessionFactory;
|
|
||||||
|
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
@ -29,11 +32,28 @@ public class MongoAuditProviderFactory implements AuditProviderFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init(Config.Scope config) {
|
||||||
try {
|
try {
|
||||||
client = new MongoClient(System.getProperty(MONGO_HOST, "localhost"), Integer.parseInt(System.getProperty(MONGO_PORT, "27017")));
|
String host = config.get("host", ServerAddress.defaultHost());
|
||||||
|
int port = config.getInt("port", ServerAddress.defaultPort());
|
||||||
|
String dbName = config.get("db", "keycloak-audit");
|
||||||
|
boolean clearOnStartup = config.getBoolean("clearOnStartup", false);
|
||||||
|
|
||||||
|
String user = config.get("user");
|
||||||
|
String password = config.get("password");
|
||||||
|
if (user != null && password != null) {
|
||||||
|
MongoCredential credential = MongoCredential.createMongoCRCredential(user, dbName, password.toCharArray());
|
||||||
|
client = new MongoClient(new ServerAddress(host, port), Collections.singletonList(credential));
|
||||||
|
} else {
|
||||||
|
client = new MongoClient(host, port);
|
||||||
|
}
|
||||||
|
|
||||||
client.setWriteConcern(WriteConcern.UNACKNOWLEDGED);
|
client.setWriteConcern(WriteConcern.UNACKNOWLEDGED);
|
||||||
db = client.getDB(System.getProperty(MONGO_DB_NAME, "keycloak-audit"));
|
db = client.getDB(dbName);
|
||||||
|
|
||||||
|
if (clearOnStartup) {
|
||||||
|
db.getCollection("audit").drop();
|
||||||
|
}
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
@ -49,9 +69,4 @@ public class MongoAuditProviderFactory implements AuditProviderFactory {
|
||||||
return ID;
|
return ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean lazyLoad() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,15 @@ import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.keycloak.Config;
|
||||||
import org.keycloak.audit.AuditProvider;
|
import org.keycloak.audit.AuditProvider;
|
||||||
import org.keycloak.audit.AuditProviderFactory;
|
import org.keycloak.audit.AuditProviderFactory;
|
||||||
import org.keycloak.audit.Event;
|
import org.keycloak.audit.Event;
|
||||||
import org.keycloak.provider.ProviderFactory;
|
import org.keycloak.provider.ProviderFactory;
|
||||||
import org.keycloak.provider.ProviderFactoryLoader;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
@ -23,9 +24,14 @@ public abstract class AbstractAuditProviderTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void before() {
|
public void before() {
|
||||||
ProviderFactoryLoader<AuditProvider> loader = ProviderFactoryLoader.create(AuditProviderFactory.class);
|
String providerId = getProviderId();
|
||||||
factory = loader.find(getProviderId());
|
ServiceLoader<AuditProviderFactory> factories = ServiceLoader.load(AuditProviderFactory.class);
|
||||||
factory.init();
|
for (AuditProviderFactory f : factories) {
|
||||||
|
if (f.getId().equals(providerId)) {
|
||||||
|
factory = f;
|
||||||
|
factory.init(Config.scope("audit", providerId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
provider = factory.create(null);
|
provider = factory.create(null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package org.keycloak.authentication;
|
||||||
|
|
||||||
|
import org.keycloak.provider.Provider;
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
import org.keycloak.provider.Spi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class AuthenticationSpi implements Spi {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "authentication";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Provider> getProviderClass() {
|
||||||
|
return AuthenticationProvider.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||||
|
return AuthenticationProviderFactory.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
org.keycloak.authentication.AuthenticationSpi
|
|
@ -1,10 +1,10 @@
|
||||||
package org.keycloak.authentication.model;
|
package org.keycloak.authentication.model;
|
||||||
|
|
||||||
|
import org.keycloak.Config;
|
||||||
import org.keycloak.authentication.AuthProviderConstants;
|
import org.keycloak.authentication.AuthProviderConstants;
|
||||||
import org.keycloak.authentication.AuthenticationProvider;
|
import org.keycloak.authentication.AuthenticationProvider;
|
||||||
import org.keycloak.authentication.AuthenticationProviderFactory;
|
import org.keycloak.authentication.AuthenticationProviderFactory;
|
||||||
import org.keycloak.provider.ProviderSession;
|
import org.keycloak.provider.ProviderSession;
|
||||||
import org.keycloak.provider.ProviderSessionFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
@ -17,7 +17,7 @@ public class ExternalModelAuthenticationProviderFactory implements Authenticatio
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init(Config.Scope config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -29,8 +29,4 @@ public class ExternalModelAuthenticationProviderFactory implements Authenticatio
|
||||||
return AuthProviderConstants.PROVIDER_NAME_EXTERNAL_MODEL;
|
return AuthProviderConstants.PROVIDER_NAME_EXTERNAL_MODEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean lazyLoad() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.keycloak.authentication.model;
|
package org.keycloak.authentication.model;
|
||||||
|
|
||||||
|
import org.keycloak.Config;
|
||||||
import org.keycloak.authentication.AuthProviderConstants;
|
import org.keycloak.authentication.AuthProviderConstants;
|
||||||
import org.keycloak.authentication.AuthenticationProvider;
|
import org.keycloak.authentication.AuthenticationProvider;
|
||||||
import org.keycloak.authentication.AuthenticationProviderFactory;
|
import org.keycloak.authentication.AuthenticationProviderFactory;
|
||||||
|
@ -16,7 +17,7 @@ public class ModelAuthenticationProviderFactory implements AuthenticationProvide
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init(Config.Scope config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -28,8 +29,4 @@ public class ModelAuthenticationProviderFactory implements AuthenticationProvide
|
||||||
return AuthProviderConstants.PROVIDER_NAME_MODEL;
|
return AuthProviderConstants.PROVIDER_NAME_MODEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean lazyLoad() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,25 @@
|
||||||
package org.keycloak.authentication.picketlink;
|
package org.keycloak.authentication.picketlink;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
|
||||||
import org.keycloak.models.RealmModel;
|
|
||||||
import org.keycloak.authentication.AuthProviderStatus;
|
|
||||||
import org.keycloak.authentication.AuthProviderConstants;
|
import org.keycloak.authentication.AuthProviderConstants;
|
||||||
|
import org.keycloak.authentication.AuthProviderStatus;
|
||||||
import org.keycloak.authentication.AuthUser;
|
import org.keycloak.authentication.AuthUser;
|
||||||
import org.keycloak.authentication.AuthenticationProvider;
|
import org.keycloak.authentication.AuthenticationProvider;
|
||||||
import org.keycloak.authentication.AuthenticationProviderException;
|
import org.keycloak.authentication.AuthenticationProviderException;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.picketlink.IdentityManagerProvider;
|
import org.keycloak.picketlink.IdentityManagerProvider;
|
||||||
import org.keycloak.util.ProviderLoader;
|
|
||||||
import org.picketlink.idm.IdentityManagementException;
|
import org.picketlink.idm.IdentityManagementException;
|
||||||
import org.picketlink.idm.IdentityManager;
|
import org.picketlink.idm.IdentityManager;
|
||||||
import org.picketlink.idm.PartitionManager;
|
|
||||||
import org.picketlink.idm.credential.Credentials;
|
import org.picketlink.idm.credential.Credentials;
|
||||||
import org.picketlink.idm.credential.Password;
|
import org.picketlink.idm.credential.Password;
|
||||||
import org.picketlink.idm.credential.UsernamePasswordCredentials;
|
import org.picketlink.idm.credential.UsernamePasswordCredentials;
|
||||||
import org.picketlink.idm.model.basic.BasicModel;
|
import org.picketlink.idm.model.basic.BasicModel;
|
||||||
import org.picketlink.idm.model.basic.User;
|
import org.picketlink.idm.model.basic.User;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AuthenticationProvider, which delegates authentication to picketlink
|
* AuthenticationProvider, which delegates authentication to picketlink
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.keycloak.authentication.picketlink;
|
package org.keycloak.authentication.picketlink;
|
||||||
|
|
||||||
|
import org.keycloak.Config;
|
||||||
import org.keycloak.authentication.AuthProviderConstants;
|
import org.keycloak.authentication.AuthProviderConstants;
|
||||||
import org.keycloak.authentication.AuthenticationProvider;
|
import org.keycloak.authentication.AuthenticationProvider;
|
||||||
import org.keycloak.authentication.AuthenticationProviderFactory;
|
import org.keycloak.authentication.AuthenticationProviderFactory;
|
||||||
|
@ -17,7 +18,7 @@ public class PicketlinkAuthenticationProviderFactory implements AuthenticationPr
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init(Config.Scope config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -29,8 +30,4 @@ public class PicketlinkAuthenticationProviderFactory implements AuthenticationPr
|
||||||
return AuthProviderConstants.PROVIDER_NAME_PICKETLINK;
|
return AuthProviderConstants.PROVIDER_NAME_PICKETLINK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean lazyLoad() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
129
core/src/main/java/org/keycloak/Config.java
Normal file
129
core/src/main/java/org/keycloak/Config.java
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
package org.keycloak;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class Config {
|
||||||
|
|
||||||
|
private static ConfigProvider configProvider = new SystemPropertiesConfigProvider();
|
||||||
|
|
||||||
|
public static void init(ConfigProvider configProvider) {
|
||||||
|
Config.configProvider = configProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getAdminRealm() {
|
||||||
|
return configProvider.scope("admin").get("realm", "keycloak-admin");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getProvider(String spi) {
|
||||||
|
return configProvider.getProvider(spi);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Scope scope(String... scope) {
|
||||||
|
return configProvider.scope(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static interface ConfigProvider {
|
||||||
|
|
||||||
|
String getProvider(String spi);
|
||||||
|
|
||||||
|
Scope scope(String... scope);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SystemPropertiesConfigProvider implements ConfigProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getProvider(String spi) {
|
||||||
|
return System.getProperties().getProperty("keycloak." + spi + ".provider");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Scope scope(String... scope) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("keycloak.");
|
||||||
|
for (String s : scope) {
|
||||||
|
sb.append(s);
|
||||||
|
sb.append(".");
|
||||||
|
}
|
||||||
|
return new SystemPropertiesScope(sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SystemPropertiesScope implements Scope {
|
||||||
|
|
||||||
|
private String prefix;
|
||||||
|
|
||||||
|
public SystemPropertiesScope(String prefix) {
|
||||||
|
this.prefix = prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String get(String key) {
|
||||||
|
return get(key, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String get(String key, String defaultValue) {
|
||||||
|
return System.getProperty(prefix + key, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getInt(String key) {
|
||||||
|
return getInt(key, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getInt(String key, Integer defaultValue) {
|
||||||
|
String v = get(key, null);
|
||||||
|
return v != null ? Integer.parseInt(v) : defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getLong(String key) {
|
||||||
|
return getLong(key, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getLong(String key, Long defaultValue) {
|
||||||
|
String v = get(key, null);
|
||||||
|
return v != null ? Long.parseLong(v) : defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean getBoolean(String key) {
|
||||||
|
return getBoolean(key, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean getBoolean(String key, Boolean defaultValue) {
|
||||||
|
String v = get(key, null);
|
||||||
|
return v != null ? Boolean.parseBoolean(v) : defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public static interface Scope {
|
||||||
|
|
||||||
|
String get(String key);
|
||||||
|
|
||||||
|
String get(String key, String defaultValue);
|
||||||
|
|
||||||
|
Integer getInt(String key);
|
||||||
|
|
||||||
|
Integer getInt(String key, Integer defaultValue);
|
||||||
|
|
||||||
|
Long getLong(String key);
|
||||||
|
|
||||||
|
Long getLong(String key, Long defaultValue);
|
||||||
|
|
||||||
|
Boolean getBoolean(String key);
|
||||||
|
|
||||||
|
Boolean getBoolean(String key, Boolean defaultValue);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
package org.keycloak.provider;
|
package org.keycloak.provider;
|
||||||
|
|
||||||
|
import org.keycloak.Config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
|
@ -7,12 +9,10 @@ public interface ProviderFactory<T extends Provider> {
|
||||||
|
|
||||||
public T create(ProviderSession providerSession);
|
public T create(ProviderSession providerSession);
|
||||||
|
|
||||||
public void init();
|
public void init(Config.Scope config);
|
||||||
|
|
||||||
public void close();
|
public void close();
|
||||||
|
|
||||||
public String getId();
|
public String getId();
|
||||||
|
|
||||||
public boolean lazyLoad();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,102 +0,0 @@
|
||||||
package org.keycloak.provider;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.ServiceLoader;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
public class ProviderFactoryLoader<T extends Provider> implements Iterable<ProviderFactory<T>> {
|
|
||||||
|
|
||||||
private final Map<String, ProviderFactory<T>> factories = new HashMap<String, ProviderFactory<T>>();
|
|
||||||
|
|
||||||
private ProviderFactoryLoader(ServiceLoader<? extends ProviderFactory> serviceLoader) {
|
|
||||||
for (ProviderFactory p : serviceLoader) {
|
|
||||||
if (!System.getProperties().containsKey(p.getClass().getName() + ".disabled")) {
|
|
||||||
if (p.lazyLoad()) {
|
|
||||||
p = new LazyProviderFactory(p);
|
|
||||||
}
|
|
||||||
factories.put(p.getId(), p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ProviderFactoryLoader create(Class<? extends ProviderFactory> service) {
|
|
||||||
return new ProviderFactoryLoader(ServiceLoader.load(service));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ProviderFactoryLoader create(Class<? extends ProviderFactory> service, ClassLoader loader) {
|
|
||||||
return new ProviderFactoryLoader(ServiceLoader.load(service, loader));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProviderFactory find(String id) {
|
|
||||||
return factories.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<ProviderFactory<T>> iterator() {
|
|
||||||
return factories.values().iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> providerIds() {
|
|
||||||
return factories.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init() {
|
|
||||||
for (ProviderFactory p : factories.values()) {
|
|
||||||
p.init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
for (ProviderFactory p : factories.values()) {
|
|
||||||
p.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class LazyProviderFactory<T extends Provider> implements ProviderFactory<T> {
|
|
||||||
|
|
||||||
private final ProviderFactory<T> factory;
|
|
||||||
|
|
||||||
private volatile boolean initialized = false;
|
|
||||||
|
|
||||||
private LazyProviderFactory(ProviderFactory<T> factory) {
|
|
||||||
this.factory = factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized T create(ProviderSession providerSession) {
|
|
||||||
if (!initialized) {
|
|
||||||
factory.init();
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
return factory.create(providerSession);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init() {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void close() {
|
|
||||||
if (initialized) {
|
|
||||||
factory.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return factory.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean lazyLoad() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,7 +1,5 @@
|
||||||
package org.keycloak.provider;
|
package org.keycloak.provider;
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
|
@ -11,12 +9,6 @@ public interface ProviderSessionFactory {
|
||||||
|
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
<T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz);
|
|
||||||
|
|
||||||
<T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz, String id);
|
|
||||||
|
|
||||||
Set<String> providerIds(Class<? extends Provider> clazz);
|
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
12
core/src/main/java/org/keycloak/provider/Spi.java
Normal file
12
core/src/main/java/org/keycloak/provider/Spi.java
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package org.keycloak.provider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public interface Spi {
|
||||||
|
|
||||||
|
public String getName();
|
||||||
|
public Class<? extends Provider> getProviderClass();
|
||||||
|
public Class<? extends ProviderFactory> getProviderFactoryClass();
|
||||||
|
|
||||||
|
}
|
263
core/src/main/java/org/keycloak/util/StringPropertyReplacer.java
Normal file
263
core/src/main/java/org/keycloak/util/StringPropertyReplacer.java
Normal file
|
@ -0,0 +1,263 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source
|
||||||
|
* Copyright 2005, JBoss Inc., and individual contributors as indicated
|
||||||
|
* by the @authors tag. See the copyright.txt in the distribution for a
|
||||||
|
* full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.keycloak.util;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility class for replacing properties in strings.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
|
||||||
|
* @author <a href="Scott.Stark@jboss.org">Scott Stark</a>
|
||||||
|
* @author <a href="claudio.vesco@previnet.it">Claudio Vesco</a>
|
||||||
|
* @author <a href="mailto:adrian@jboss.com">Adrian Brock</a>
|
||||||
|
* @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
|
||||||
|
* @version <tt>$Revision: 2898 $</tt>
|
||||||
|
*/
|
||||||
|
public final class StringPropertyReplacer
|
||||||
|
{
|
||||||
|
/** New line string constant */
|
||||||
|
public static final String NEWLINE = System.getProperty("line.separator", "\n");
|
||||||
|
|
||||||
|
/** File separator value */
|
||||||
|
private static final String FILE_SEPARATOR = File.separator;
|
||||||
|
|
||||||
|
/** Path separator value */
|
||||||
|
private static final String PATH_SEPARATOR = File.pathSeparator;
|
||||||
|
|
||||||
|
/** File separator alias */
|
||||||
|
private static final String FILE_SEPARATOR_ALIAS = "/";
|
||||||
|
|
||||||
|
/** Path separator alias */
|
||||||
|
private static final String PATH_SEPARATOR_ALIAS = ":";
|
||||||
|
|
||||||
|
// States used in property parsing
|
||||||
|
private static final int NORMAL = 0;
|
||||||
|
private static final int SEEN_DOLLAR = 1;
|
||||||
|
private static final int IN_BRACKET = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go through the input string and replace any occurance of ${p} with
|
||||||
|
* the System.getProperty(p) value. If there is no such property p defined,
|
||||||
|
* then the ${p} reference will remain unchanged.
|
||||||
|
*
|
||||||
|
* If the property reference is of the form ${p:v} and there is no such property p,
|
||||||
|
* then the default value v will be returned.
|
||||||
|
*
|
||||||
|
* If the property reference is of the form ${p1,p2} or ${p1,p2:v} then
|
||||||
|
* the primary and the secondary properties will be tried in turn, before
|
||||||
|
* returning either the unchanged input, or the default value.
|
||||||
|
*
|
||||||
|
* The property ${/} is replaced with System.getProperty("file.separator")
|
||||||
|
* value and the property ${:} is replaced with System.getProperty("path.separator").
|
||||||
|
*
|
||||||
|
* @param string - the string with possible ${} references
|
||||||
|
* @return the input string with all property references replaced if any.
|
||||||
|
* If there are no valid references the input string will be returned.
|
||||||
|
*/
|
||||||
|
public static String replaceProperties(final String string)
|
||||||
|
{
|
||||||
|
return replaceProperties(string, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go through the input string and replace any occurance of ${p} with
|
||||||
|
* the props.getProperty(p) value. If there is no such property p defined,
|
||||||
|
* then the ${p} reference will remain unchanged.
|
||||||
|
*
|
||||||
|
* If the property reference is of the form ${p:v} and there is no such property p,
|
||||||
|
* then the default value v will be returned.
|
||||||
|
*
|
||||||
|
* If the property reference is of the form ${p1,p2} or ${p1,p2:v} then
|
||||||
|
* the primary and the secondary properties will be tried in turn, before
|
||||||
|
* returning either the unchanged input, or the default value.
|
||||||
|
*
|
||||||
|
* The property ${/} is replaced with System.getProperty("file.separator")
|
||||||
|
* value and the property ${:} is replaced with System.getProperty("path.separator").
|
||||||
|
*
|
||||||
|
* @param string - the string with possible ${} references
|
||||||
|
* @param props - the source for ${x} property ref values, null means use System.getProperty()
|
||||||
|
* @return the input string with all property references replaced if any.
|
||||||
|
* If there are no valid references the input string will be returned.
|
||||||
|
*/
|
||||||
|
public static String replaceProperties(final String string, final Properties props)
|
||||||
|
{
|
||||||
|
final char[] chars = string.toCharArray();
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
boolean properties = false;
|
||||||
|
int state = NORMAL;
|
||||||
|
int start = 0;
|
||||||
|
for (int i = 0; i < chars.length; ++i)
|
||||||
|
{
|
||||||
|
char c = chars[i];
|
||||||
|
|
||||||
|
// Dollar sign outside brackets
|
||||||
|
if (c == '$' && state != IN_BRACKET)
|
||||||
|
state = SEEN_DOLLAR;
|
||||||
|
|
||||||
|
// Open bracket immediatley after dollar
|
||||||
|
else if (c == '{' && state == SEEN_DOLLAR)
|
||||||
|
{
|
||||||
|
buffer.append(string.substring(start, i - 1));
|
||||||
|
state = IN_BRACKET;
|
||||||
|
start = i - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No open bracket after dollar
|
||||||
|
else if (state == SEEN_DOLLAR)
|
||||||
|
state = NORMAL;
|
||||||
|
|
||||||
|
// Closed bracket after open bracket
|
||||||
|
else if (c == '}' && state == IN_BRACKET)
|
||||||
|
{
|
||||||
|
// No content
|
||||||
|
if (start + 2 == i)
|
||||||
|
{
|
||||||
|
buffer.append("${}"); // REVIEW: Correct?
|
||||||
|
}
|
||||||
|
else // Collect the system property
|
||||||
|
{
|
||||||
|
String value = null;
|
||||||
|
|
||||||
|
String key = string.substring(start + 2, i);
|
||||||
|
|
||||||
|
// check for alias
|
||||||
|
if (FILE_SEPARATOR_ALIAS.equals(key))
|
||||||
|
{
|
||||||
|
value = FILE_SEPARATOR;
|
||||||
|
}
|
||||||
|
else if (PATH_SEPARATOR_ALIAS.equals(key))
|
||||||
|
{
|
||||||
|
value = PATH_SEPARATOR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// check from the properties
|
||||||
|
if (props != null)
|
||||||
|
value = props.getProperty(key);
|
||||||
|
else
|
||||||
|
value = System.getProperty(key);
|
||||||
|
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
// Check for a default value ${key:default}
|
||||||
|
int colon = key.indexOf(':');
|
||||||
|
if (colon > 0)
|
||||||
|
{
|
||||||
|
String realKey = key.substring(0, colon);
|
||||||
|
if (props != null)
|
||||||
|
value = props.getProperty(realKey);
|
||||||
|
else
|
||||||
|
value = System.getProperty(realKey);
|
||||||
|
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
// Check for a composite key, "key1,key2"
|
||||||
|
value = resolveCompositeKey(realKey, props);
|
||||||
|
|
||||||
|
// Not a composite key either, use the specified default
|
||||||
|
if (value == null)
|
||||||
|
value = key.substring(colon+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No default, check for a composite key, "key1,key2"
|
||||||
|
value = resolveCompositeKey(key, props);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value != null)
|
||||||
|
{
|
||||||
|
properties = true;
|
||||||
|
buffer.append(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer.append("${");
|
||||||
|
buffer.append(key);
|
||||||
|
buffer.append('}');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
start = i + 1;
|
||||||
|
state = NORMAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No properties
|
||||||
|
if (properties == false)
|
||||||
|
return string;
|
||||||
|
|
||||||
|
// Collect the trailing characters
|
||||||
|
if (start != chars.length)
|
||||||
|
buffer.append(string.substring(start, chars.length));
|
||||||
|
|
||||||
|
// Done
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to resolve a "key" from the provided properties by
|
||||||
|
* checking if it is actually a "key1,key2", in which case
|
||||||
|
* try first "key1", then "key2". If all fails, return null.
|
||||||
|
*
|
||||||
|
* It also accepts "key1," and ",key2".
|
||||||
|
*
|
||||||
|
* @param key the key to resolve
|
||||||
|
* @param props the properties to use
|
||||||
|
* @return the resolved key or null
|
||||||
|
*/
|
||||||
|
private static String resolveCompositeKey(String key, Properties props)
|
||||||
|
{
|
||||||
|
String value = null;
|
||||||
|
|
||||||
|
// Look for the comma
|
||||||
|
int comma = key.indexOf(',');
|
||||||
|
if (comma > -1)
|
||||||
|
{
|
||||||
|
// If we have a first part, try resolve it
|
||||||
|
if (comma > 0)
|
||||||
|
{
|
||||||
|
// Check the first part
|
||||||
|
String key1 = key.substring(0, comma);
|
||||||
|
if (props != null)
|
||||||
|
value = props.getProperty(key1);
|
||||||
|
else
|
||||||
|
value = System.getProperty(key1);
|
||||||
|
}
|
||||||
|
// Check the second part, if there is one and first lookup failed
|
||||||
|
if (value == null && comma < key.length() - 1)
|
||||||
|
{
|
||||||
|
String key2 = key.substring(comma + 1);
|
||||||
|
if (props != null)
|
||||||
|
value = props.getProperty(key2);
|
||||||
|
else
|
||||||
|
value = System.getProperty(key2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Return whatever we've found or null
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
|
@ -252,12 +252,12 @@ keycloak-war-dist-all-1.0-beta-1-SNAPSHOT/
|
||||||
First you need to specify that you want to use <literal>mongo</literal> instead of default <literal>jpa</literal> model, and you may also specify
|
First you need to specify that you want to use <literal>mongo</literal> instead of default <literal>jpa</literal> model, and you may also specify
|
||||||
host, port and name of mongo database. So you can start keycloak with the command like this:
|
host, port and name of mongo database. So you can start keycloak with the command like this:
|
||||||
<programlisting><![CDATA[
|
<programlisting><![CDATA[
|
||||||
./standalone.sh -Dkeycloak.model=mongo -Dkeycloak.mongo.host=localhost
|
./standalone.sh -Dkeycloak.model=mongo -Dkeycloak.model.mongo.host=localhost
|
||||||
-Dkeycloak.mongo.port=27017 -Dkeycloak.mongo.db=keycloak
|
-Dkeycloak.model.mongoport=27017 -Dkeycloak.model.mongo.db=keycloak
|
||||||
]]></programlisting>
|
]]></programlisting>
|
||||||
Note that when you install MongoDB on your laptop, it's usually on localhost/270717 by default. That's why properties
|
Note that when you install MongoDB on your laptop, it's usually on localhost/270717 by default. That's why properties
|
||||||
<literal>keycloak.mongo.host</literal> and <literal>keycloak.mongo.port</literal> are not mandatory, but they already have
|
<literal>keycloak.model.mongo.host</literal> and <literal>keycloak.model.mongo.port</literal> are not mandatory, but they already have
|
||||||
default values <literal>localhost</literal> and <literal>27017</literal> . Similarly property <literal>keycloak.mongo.db</literal>
|
default values <literal>localhost</literal> and <literal>27017</literal> . Similarly property <literal>keycloak.model.mongo.db</literal>
|
||||||
has default value <literal>keycloak</literal> for name of underlying database. So the example above could be simplified like:
|
has default value <literal>keycloak</literal> for name of underlying database. So the example above could be simplified like:
|
||||||
<programlisting><![CDATA[
|
<programlisting><![CDATA[
|
||||||
./standalone.sh -Dkeycloak.model=mongo
|
./standalone.sh -Dkeycloak.model=mongo
|
||||||
|
|
|
@ -14,6 +14,12 @@
|
||||||
<description/>
|
<description/>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-model-api</artifactId>
|
<artifactId>keycloak-model-api</artifactId>
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package org.keycloak.exportimport;
|
package org.keycloak.exportimport;
|
||||||
|
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.provider.ProviderSessionFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
public interface ExportImportProvider {
|
public interface ExportImportProvider {
|
||||||
|
|
||||||
void checkExportImport(KeycloakSessionFactory identitySessionFactory);
|
void checkExportImport(ProviderSessionFactory identitySessionFactory);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,13 +32,6 @@
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>keycloak-audit-api</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.resteasy</groupId>
|
<groupId>org.jboss.resteasy</groupId>
|
||||||
<artifactId>jaxrs-api</artifactId>
|
<artifactId>jaxrs-api</artifactId>
|
||||||
|
@ -121,6 +114,12 @@
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-model-tests</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate.javax.persistence</groupId>
|
<groupId>org.hibernate.javax.persistence</groupId>
|
||||||
<artifactId>hibernate-jpa-2.0-api</artifactId>
|
<artifactId>hibernate-jpa-2.0-api</artifactId>
|
||||||
|
@ -149,10 +148,10 @@
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<keycloak.mongo.host>localhost</keycloak.mongo.host>
|
<keycloak.model.mongo.host>localhost</keycloak.model.mongo.host>
|
||||||
<keycloak.mongo.port>27018</keycloak.mongo.port>
|
<keycloak.model.mongo.port>27018</keycloak.model.mongo.port>
|
||||||
<keycloak.mongo.db>keycloak</keycloak.mongo.db>
|
<keycloak.model.mongo.db>keycloak</keycloak.model.mongo.db>
|
||||||
<keycloak.mongo.clearOnStartup>true</keycloak.mongo.clearOnStartup>
|
<keycloak.model.mongo.clearOnStartup>true</keycloak.model.mongo.clearOnStartup>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -179,10 +178,10 @@
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<systemPropertyVariables>
|
<systemPropertyVariables>
|
||||||
<keycloak.mongo.host>${keycloak.mongo.host}</keycloak.mongo.host>
|
<keycloak.model.mongo.host>${keycloak.model.mongo.host}</keycloak.model.mongo.host>
|
||||||
<keycloak.mongo.port>${keycloak.mongo.port}</keycloak.mongo.port>
|
<keycloak.model.mongo.port>${keycloak.model.mongo.port}</keycloak.model.mongo.port>
|
||||||
<keycloak.mongo.db>${keycloak.mongo.db}</keycloak.mongo.db>
|
<keycloak.model.mongo.db>${keycloak.model.mongo.db}</keycloak.model.mongo.db>
|
||||||
<keycloak.mongo.clearOnStartup>${keycloak.mongo.clearOnStartup}</keycloak.mongo.clearOnStartup>
|
<keycloak.model.mongo.clearOnStartup>${keycloak.model.mongo.clearOnStartup}</keycloak.model.mongo.clearOnStartup>
|
||||||
</systemPropertyVariables>
|
</systemPropertyVariables>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
|
@ -207,7 +206,7 @@
|
||||||
<goal>start</goal>
|
<goal>start</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<port>${keycloak.mongo.port}</port>
|
<port>${keycloak.model.mongo.port}</port>
|
||||||
<logging>file</logging>
|
<logging>file</logging>
|
||||||
<logFile>${project.build.directory}/mongodb.log</logFile>
|
<logFile>${project.build.directory}/mongodb.log</logFile>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,10 +4,10 @@ import org.jboss.logging.Logger;
|
||||||
import org.keycloak.exportimport.io.ExportImportIOProvider;
|
import org.keycloak.exportimport.io.ExportImportIOProvider;
|
||||||
import org.keycloak.exportimport.io.ExportWriter;
|
import org.keycloak.exportimport.io.ExportWriter;
|
||||||
import org.keycloak.exportimport.io.ImportReader;
|
import org.keycloak.exportimport.io.ImportReader;
|
||||||
import org.keycloak.models.Config;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
|
||||||
import org.keycloak.models.KeycloakTransaction;
|
import org.keycloak.models.KeycloakTransaction;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
import org.keycloak.provider.ProviderSessionFactory;
|
||||||
import org.keycloak.util.ProviderLoader;
|
import org.keycloak.util.ProviderLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,8 +21,8 @@ public class ExportImportProviderImpl implements ExportImportProvider {
|
||||||
public static final String ACTION_IMPORT = "import";
|
public static final String ACTION_IMPORT = "import";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void checkExportImport(KeycloakSessionFactory identitySessionFactory) {
|
public void checkExportImport(ProviderSessionFactory providerSessionFactory) {
|
||||||
String exportImportAction = Config.getExportImportAction();
|
String exportImportAction = ExportImportConfig.getAction();
|
||||||
|
|
||||||
boolean export = false;
|
boolean export = false;
|
||||||
boolean importt = false;
|
boolean importt = false;
|
||||||
|
@ -35,7 +35,8 @@ public class ExportImportProviderImpl implements ExportImportProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (export || importt) {
|
if (export || importt) {
|
||||||
KeycloakSession session = identitySessionFactory.createSession();
|
ProviderSession providerSession = providerSessionFactory.createSession();
|
||||||
|
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||||
KeycloakTransaction transaction = session.getTransaction();
|
KeycloakTransaction transaction = session.getTransaction();
|
||||||
try {
|
try {
|
||||||
transaction.begin();
|
transaction.begin();
|
||||||
|
@ -63,13 +64,13 @@ public class ExportImportProviderImpl implements ExportImportProvider {
|
||||||
}
|
}
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
} finally {
|
} finally {
|
||||||
session.close();
|
providerSession.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExportImportIOProvider getProvider() {
|
private ExportImportIOProvider getProvider() {
|
||||||
String providerId = Config.getExportImportProvider();
|
String providerId = ExportImportConfig.getProvider();
|
||||||
logger.infof("Requested migration provider: " + providerId);
|
logger.infof("Requested migration provider: " + providerId);
|
||||||
|
|
||||||
Iterable<ExportImportIOProvider> providers = ProviderLoader.load(ExportImportIOProvider.class);
|
Iterable<ExportImportIOProvider> providers = ProviderLoader.load(ExportImportIOProvider.class);
|
||||||
|
|
|
@ -13,7 +13,7 @@ import org.keycloak.models.ApplicationModel;
|
||||||
import org.keycloak.models.AuthenticationLinkModel;
|
import org.keycloak.models.AuthenticationLinkModel;
|
||||||
import org.keycloak.models.AuthenticationProviderModel;
|
import org.keycloak.models.AuthenticationProviderModel;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.OAuthClientModel;
|
import org.keycloak.models.OAuthClientModel;
|
||||||
import org.keycloak.models.PasswordPolicy;
|
import org.keycloak.models.PasswordPolicy;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package org.keycloak.exportimport.io.directory;
|
package org.keycloak.exportimport.io.directory;
|
||||||
|
|
||||||
import java.io.File;
|
import org.keycloak.exportimport.ExportImportConfig;
|
||||||
|
|
||||||
import org.keycloak.exportimport.io.ExportImportIOProvider;
|
import org.keycloak.exportimport.io.ExportImportIOProvider;
|
||||||
import org.keycloak.exportimport.io.ExportWriter;
|
import org.keycloak.exportimport.io.ExportWriter;
|
||||||
import org.keycloak.exportimport.io.ImportReader;
|
import org.keycloak.exportimport.io.ImportReader;
|
||||||
import org.keycloak.models.Config;
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Export/import into JSON files inside "tmp" directory. This implementation is used mainly for testing
|
* Export/import into JSON files inside "tmp" directory. This implementation is used mainly for testing
|
||||||
|
@ -19,13 +19,13 @@ public class TmpDirExportImportIOProvider implements ExportImportIOProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ExportWriter getExportWriter() {
|
public ExportWriter getExportWriter() {
|
||||||
String dir = Config.getExportImportDir();
|
String dir = ExportImportConfig.getDir();
|
||||||
return dir!=null ? new TmpDirExportWriter(new File(dir)) : new TmpDirExportWriter();
|
return dir!=null ? new TmpDirExportWriter(new File(dir)) : new TmpDirExportWriter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImportReader getImportReader() {
|
public ImportReader getImportReader() {
|
||||||
String dir = Config.getExportImportDir();
|
String dir = ExportImportConfig.getDir();
|
||||||
return dir!=null ? new TmpDirImportReader(new File(dir)) : new TmpDirImportReader();
|
return dir!=null ? new TmpDirImportReader(new File(dir)) : new TmpDirImportReader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package org.keycloak.exportimport.io.zip;
|
package org.keycloak.exportimport.io.zip;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.exportimport.ExportImportConfig;
|
||||||
import org.keycloak.exportimport.io.ExportImportIOProvider;
|
import org.keycloak.exportimport.io.ExportImportIOProvider;
|
||||||
import org.keycloak.exportimport.io.ExportWriter;
|
import org.keycloak.exportimport.io.ExportWriter;
|
||||||
import org.keycloak.exportimport.io.ImportReader;
|
import org.keycloak.exportimport.io.ImportReader;
|
||||||
import org.keycloak.models.Config;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
@ -22,8 +22,8 @@ public class EncryptedZIPIOProvider implements ExportImportIOProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ExportWriter getExportWriter() {
|
public ExportWriter getExportWriter() {
|
||||||
String zipFile = Config.getExportImportZipFile();
|
String zipFile = ExportImportConfig.getZipFile();
|
||||||
String zipPassword = Config.getExportImportZipPassword();
|
String zipPassword = ExportImportConfig.getZipPassword();
|
||||||
logger.infof("Using zip for export: " + zipFile);
|
logger.infof("Using zip for export: " + zipFile);
|
||||||
|
|
||||||
if (zipFile==null || zipPassword==null) {
|
if (zipFile==null || zipPassword==null) {
|
||||||
|
@ -35,8 +35,8 @@ public class EncryptedZIPIOProvider implements ExportImportIOProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImportReader getImportReader() {
|
public ImportReader getImportReader() {
|
||||||
String zipFile = Config.getExportImportZipFile();
|
String zipFile = ExportImportConfig.getZipFile();
|
||||||
String zipPassword = Config.getExportImportZipPassword();
|
String zipPassword = ExportImportConfig.getZipPassword();
|
||||||
logger.infof("Using zip for import: " + zipFile);
|
logger.infof("Using zip for import: " + zipFile);
|
||||||
|
|
||||||
if (zipFile==null || zipPassword==null) {
|
if (zipFile==null || zipPassword==null) {
|
||||||
|
|
|
@ -1,36 +1,43 @@
|
||||||
package org.keycloak.exportimport;
|
package org.keycloak.exportimport;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import org.junit.After;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.model.test.AbstractModelTest;
|
import org.keycloak.model.test.AbstractModelTest;
|
||||||
import org.keycloak.model.test.ImportTest;
|
import org.keycloak.model.test.ImportTest;
|
||||||
import org.keycloak.models.Config;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
import org.keycloak.provider.ProviderSessionFactory;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.services.managers.ApplianceBootstrap;
|
import org.keycloak.services.managers.ApplianceBootstrap;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.services.resources.KeycloakApplication;
|
import org.keycloak.services.resources.KeycloakApplication;
|
||||||
import org.keycloak.util.ProviderLoader;
|
import org.keycloak.util.ProviderLoader;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
public abstract class ExportImportTestBase {
|
public abstract class ExportImportTestBase {
|
||||||
|
|
||||||
protected KeycloakSessionFactory factory;
|
protected ProviderSessionFactory factory;
|
||||||
|
|
||||||
|
protected ProviderSession providerSession;
|
||||||
protected KeycloakSession identitySession;
|
protected KeycloakSession identitySession;
|
||||||
protected RealmManager realmManager;
|
protected RealmManager realmManager;
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() {
|
||||||
|
System.getProperties().remove("keycloak.model.provider");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExportImport() throws Exception {
|
public void testExportImport() throws Exception {
|
||||||
// Init JPA model
|
// Init JPA model
|
||||||
Config.setModelProvider(getExportModelProvider());
|
System.setProperty("keycloak.model.provider", getExportModelProvider());
|
||||||
factory = KeycloakApplication.createSessionFactory();
|
factory = KeycloakApplication.createProviderSessionFactory();
|
||||||
|
|
||||||
// Bootstrap admin realm
|
// Bootstrap admin realm
|
||||||
beginTransaction();
|
beginTransaction();
|
||||||
|
@ -59,8 +66,8 @@ public abstract class ExportImportTestBase {
|
||||||
factory.close();
|
factory.close();
|
||||||
|
|
||||||
// Bootstrap mongo session and factory
|
// Bootstrap mongo session and factory
|
||||||
Config.setModelProvider(getImportModelProvider());
|
System.setProperty("keycloak.model.provider", getImportModelProvider());
|
||||||
factory = KeycloakApplication.createSessionFactory();
|
factory = KeycloakApplication.createProviderSessionFactory();
|
||||||
|
|
||||||
// Full import of previous export into mongo
|
// Full import of previous export into mongo
|
||||||
importModel(factory);
|
importModel(factory);
|
||||||
|
@ -83,19 +90,20 @@ public abstract class ExportImportTestBase {
|
||||||
|
|
||||||
protected abstract String getImportModelProvider();
|
protected abstract String getImportModelProvider();
|
||||||
|
|
||||||
protected abstract void exportModel(KeycloakSessionFactory factory);
|
protected abstract void exportModel(ProviderSessionFactory factory);
|
||||||
|
|
||||||
protected abstract void importModel(KeycloakSessionFactory factory);
|
protected abstract void importModel(ProviderSessionFactory factory);
|
||||||
|
|
||||||
protected void beginTransaction() {
|
protected void beginTransaction() {
|
||||||
identitySession = factory.createSession();
|
providerSession = factory.createSession();
|
||||||
|
identitySession = providerSession.getProvider(KeycloakSession.class);
|
||||||
identitySession.getTransaction().begin();
|
identitySession.getTransaction().begin();
|
||||||
realmManager = new RealmManager(identitySession);
|
realmManager = new RealmManager(identitySession);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void commitTransaction() {
|
protected void commitTransaction() {
|
||||||
identitySession.getTransaction().commit();
|
identitySession.getTransaction().commit();
|
||||||
identitySession.close();
|
providerSession.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ExportImportProvider getExportImportProvider() {
|
protected ExportImportProvider getExportImportProvider() {
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package org.keycloak.exportimport;
|
package org.keycloak.exportimport;
|
||||||
|
|
||||||
import org.keycloak.exportimport.io.directory.TmpDirExportImportIOProvider;
|
import org.keycloak.exportimport.io.directory.TmpDirExportImportIOProvider;
|
||||||
import org.keycloak.models.Config;
|
import org.keycloak.provider.ProviderSessionFactory;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for full export of data from JPA and import them to Mongo. Using "directory" provider
|
* Test for full export of data from JPA and import them to Mongo. Using "directory" provider
|
||||||
|
@ -22,16 +21,16 @@ public class JPAToMongoExportImportTest extends ExportImportTestBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void exportModel(KeycloakSessionFactory factory) {
|
protected void exportModel(ProviderSessionFactory factory) {
|
||||||
Config.setExportImportAction(ExportImportProviderImpl.ACTION_EXPORT);
|
ExportImportConfig.setAction(ExportImportProviderImpl.ACTION_EXPORT);
|
||||||
Config.setExportImportProvider(TmpDirExportImportIOProvider.PROVIDER_ID);
|
ExportImportConfig.setProvider(TmpDirExportImportIOProvider.PROVIDER_ID);
|
||||||
getExportImportProvider().checkExportImport(factory);
|
getExportImportProvider().checkExportImport(factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void importModel(KeycloakSessionFactory factory) {
|
protected void importModel(ProviderSessionFactory factory) {
|
||||||
Config.setExportImportAction(ExportImportProviderImpl.ACTION_IMPORT);
|
ExportImportConfig.setAction(ExportImportProviderImpl.ACTION_IMPORT);
|
||||||
Config.setExportImportProvider(TmpDirExportImportIOProvider.PROVIDER_ID);
|
ExportImportConfig.setProvider(TmpDirExportImportIOProvider.PROVIDER_ID);
|
||||||
getExportImportProvider().checkExportImport(factory);
|
getExportImportProvider().checkExportImport(factory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
package org.keycloak.exportimport;
|
package org.keycloak.exportimport;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.keycloak.exportimport.io.zip.EncryptedZIPIOProvider;
|
import org.keycloak.exportimport.io.zip.EncryptedZIPIOProvider;
|
||||||
import org.keycloak.models.Config;
|
import org.keycloak.provider.ProviderSessionFactory;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for full export of data from Mongo and import them to JPA. Using export into encrypted ZIP and import from it
|
* Test for full export of data from Mongo and import them to JPA. Using export into encrypted ZIP and import from it
|
||||||
|
@ -27,12 +26,12 @@ public class MongoToJPAExportImportTest extends ExportImportTestBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void exportModel(KeycloakSessionFactory factory) {
|
protected void exportModel(ProviderSessionFactory factory) {
|
||||||
Config.setExportImportAction(ExportImportProviderImpl.ACTION_EXPORT);
|
ExportImportConfig.setAction(ExportImportProviderImpl.ACTION_EXPORT);
|
||||||
Config.setExportImportProvider(EncryptedZIPIOProvider.PROVIDER_ID);
|
ExportImportConfig.setProvider(EncryptedZIPIOProvider.PROVIDER_ID);
|
||||||
File zipFile = getZipFile();
|
File zipFile = getZipFile();
|
||||||
Config.setExportImportZipFile(zipFile.getAbsolutePath());
|
ExportImportConfig.setZipFile(zipFile.getAbsolutePath());
|
||||||
Config.setExportImportZipPassword("password123");
|
ExportImportConfig.setZipPassword("password123");
|
||||||
|
|
||||||
if (zipFile.exists()) {
|
if (zipFile.exists()) {
|
||||||
zipFile.delete();
|
zipFile.delete();
|
||||||
|
@ -42,12 +41,12 @@ public class MongoToJPAExportImportTest extends ExportImportTestBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void importModel(KeycloakSessionFactory factory) {
|
protected void importModel(ProviderSessionFactory factory) {
|
||||||
Config.setExportImportAction(ExportImportProviderImpl.ACTION_IMPORT);
|
ExportImportConfig.setAction(ExportImportProviderImpl.ACTION_IMPORT);
|
||||||
Config.setExportImportProvider(EncryptedZIPIOProvider.PROVIDER_ID);
|
ExportImportConfig.setProvider(EncryptedZIPIOProvider.PROVIDER_ID);
|
||||||
File zipFile = getZipFile();
|
File zipFile = getZipFile();
|
||||||
Config.setExportImportZipFile(zipFile.getAbsolutePath());
|
ExportImportConfig.setZipFile(zipFile.getAbsolutePath());
|
||||||
Config.setExportImportZipPassword("password-invalid");
|
ExportImportConfig.setZipPassword("password-invalid");
|
||||||
|
|
||||||
// Try invalid password
|
// Try invalid password
|
||||||
try {
|
try {
|
||||||
|
@ -55,7 +54,7 @@ public class MongoToJPAExportImportTest extends ExportImportTestBase {
|
||||||
Assert.fail("Not expected to be here. Exception should be thrown");
|
Assert.fail("Not expected to be here. Exception should be thrown");
|
||||||
} catch (Exception e) {};
|
} catch (Exception e) {};
|
||||||
|
|
||||||
Config.setExportImportZipPassword("password123");
|
ExportImportConfig.setZipPassword("password123");
|
||||||
new ExportImportProviderImpl().checkExportImport(factory);
|
new ExportImportProviderImpl().checkExportImport(factory);
|
||||||
|
|
||||||
if (zipFile.exists()) {
|
if (zipFile.exists()) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package org.keycloak.freemarker;
|
package org.keycloak.freemarker;
|
||||||
|
|
||||||
import org.keycloak.models.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.util.ProviderLoader;
|
import org.keycloak.util.ProviderLoader;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -20,7 +20,7 @@ public class ThemeLoader {
|
||||||
|
|
||||||
public static Theme createTheme(String name, Theme.Type type) throws FreeMarkerException {
|
public static Theme createTheme(String name, Theme.Type type) throws FreeMarkerException {
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
name = Config.getThemeDefault();
|
name = Config.scope("theme").get("default");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ThemeProvider> providers = new LinkedList();
|
List<ThemeProvider> providers = new LinkedList();
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
package org.keycloak.theme;
|
package org.keycloak.theme;
|
||||||
|
|
||||||
import org.keycloak.freemarker.Theme;
|
import org.keycloak.freemarker.Theme;
|
||||||
import org.keycloak.freemarker.ThemeLoader;
|
|
||||||
import org.keycloak.freemarker.ThemeProvider;
|
import org.keycloak.freemarker.ThemeProvider;
|
||||||
import org.keycloak.models.Config;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,7 +2,7 @@ package org.keycloak.theme;
|
||||||
|
|
||||||
import org.keycloak.freemarker.Theme;
|
import org.keycloak.freemarker.Theme;
|
||||||
import org.keycloak.freemarker.ThemeProvider;
|
import org.keycloak.freemarker.ThemeProvider;
|
||||||
import org.keycloak.models.Config;
|
import org.keycloak.Config;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileFilter;
|
import java.io.FileFilter;
|
||||||
|
@ -19,7 +19,7 @@ public class FolderThemeProvider implements ThemeProvider {
|
||||||
private File rootDir;
|
private File rootDir;
|
||||||
|
|
||||||
public FolderThemeProvider() {
|
public FolderThemeProvider() {
|
||||||
String d = Config.getThemeDir();
|
String d = Config.scope("theme").get("dir");
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
rootDir = new File(d);
|
rootDir = new File(d);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,183 +0,0 @@
|
||||||
package org.keycloak.models;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
public class Config {
|
|
||||||
|
|
||||||
public static final String ADMIN_REALM_KEY = "keycloak.admin.realm";
|
|
||||||
public static final String ADMIN_REALM_DEFAULT = "keycloak-admin";
|
|
||||||
|
|
||||||
public static final String MODEL_PROVIDER_KEY = "keycloak.model";
|
|
||||||
|
|
||||||
public static final String USER_EXPIRATION_SCHEDULE_KEY = "keycloak.scheduled.clearExpiredUserSessions";
|
|
||||||
public static final String USER_EXPIRATION_SCHEDULE_DEFAULT = String.valueOf(TimeUnit.MINUTES.toMillis(15));
|
|
||||||
|
|
||||||
public static final String AUDIT_PROVIDER_KEY = "keycloak.audit";
|
|
||||||
public static final String AUDIT_PROVIDER_DEFAULT = "jpa";
|
|
||||||
public static final String AUDIT_EXPIRATION_SCHEDULE_KEY = "keycloak.scheduled.clearExpiredAuditEvents";
|
|
||||||
public static final String AUDIT_EXPIRATION_SCHEDULE_DEFAULT = String.valueOf(TimeUnit.MINUTES.toMillis(15));
|
|
||||||
|
|
||||||
public static final String PICKETLINK_PROVIDER_KEY = "keycloak.picketlink";
|
|
||||||
|
|
||||||
public static final String THEME_BASE_KEY = "keycloak.theme.base";
|
|
||||||
public static final String THEME_BASE_DEFAULT = "base";
|
|
||||||
public static final String THEME_DEFAULT_KEY = "keycloak.theme.default";
|
|
||||||
public static final String THEME_DEFAULT_DEFAULT = "keycloak";
|
|
||||||
public static final String THEME_DIR_KEY = "keycloak.theme.dir";
|
|
||||||
public static final String THEME_ADMIN_KEY = "keycloak.theme.admin";
|
|
||||||
public static final String THEME_ADMIN_DEFAULT = "keycloak";
|
|
||||||
|
|
||||||
public static final String JBOSS_SERVER_CONFIG_DIR_KEY = "jboss.server.config.dir";
|
|
||||||
|
|
||||||
public static final String TIMER_PROVIDER_KEY = "keycloak.timer";
|
|
||||||
public static final String TIMER_PROVIDER_DEFAULT = "basic";
|
|
||||||
|
|
||||||
public static final String EXPORT_IMPORT_ACTION = "keycloak.migration.action";
|
|
||||||
public static final String EXPORT_IMPORT_PROVIDER = "keycloak.migration.provider";
|
|
||||||
public static final String EXPORT_IMPORT_PROVIDER_DEFAULT = "zip";
|
|
||||||
// used for "directory" provider
|
|
||||||
public static final String EXPORT_IMPORT_DIR = "keycloak.migration.dir";
|
|
||||||
// used for "zip" provider
|
|
||||||
public static final String EXPORT_IMPORT_ZIP_FILE = "keycloak.migration.zipFile";
|
|
||||||
public static final String EXPORT_IMPORT_ZIP_PASSWORD = "keycloak.migration.zipPassword";
|
|
||||||
|
|
||||||
|
|
||||||
public static String getAdminRealm() {
|
|
||||||
return System.getProperty(ADMIN_REALM_KEY, ADMIN_REALM_DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setAdminRealm(String realm) {
|
|
||||||
System.setProperty(ADMIN_REALM_KEY, realm);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getAuditProvider() {
|
|
||||||
return System.getProperty(AUDIT_PROVIDER_KEY, AUDIT_PROVIDER_DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setAuditProvider(String provider) {
|
|
||||||
System.setProperty(AUDIT_PROVIDER_KEY, provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getAuditExpirationSchedule() {
|
|
||||||
return System.getProperty(AUDIT_EXPIRATION_SCHEDULE_KEY, AUDIT_EXPIRATION_SCHEDULE_DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setAuditExpirationSchedule(String schedule) {
|
|
||||||
System.setProperty(AUDIT_EXPIRATION_SCHEDULE_KEY, schedule);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getUserExpirationSchedule() {
|
|
||||||
return System.getProperty(USER_EXPIRATION_SCHEDULE_KEY, USER_EXPIRATION_SCHEDULE_DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setUserExpirationSchedule(String schedule) {
|
|
||||||
System.setProperty(USER_EXPIRATION_SCHEDULE_KEY, schedule);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getModelProvider() {
|
|
||||||
return System.getProperty(MODEL_PROVIDER_KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setModelProvider(String provider) {
|
|
||||||
System.setProperty(MODEL_PROVIDER_KEY, provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getTimerProvider() {
|
|
||||||
return System.getProperty(TIMER_PROVIDER_KEY, TIMER_PROVIDER_DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setTimerProvider(String provider) {
|
|
||||||
System.setProperty(TIMER_PROVIDER_KEY, provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getIdentityManagerProvider() {
|
|
||||||
return System.getProperty(PICKETLINK_PROVIDER_KEY, "realm");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setIdentityManagerProvider(String provider) {
|
|
||||||
System.setProperty(PICKETLINK_PROVIDER_KEY, provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getThemeDir() {
|
|
||||||
String themeDir = System.getProperty(THEME_DIR_KEY);
|
|
||||||
if (themeDir == null && System.getProperties().containsKey(JBOSS_SERVER_CONFIG_DIR_KEY)) {
|
|
||||||
themeDir = System.getProperty(JBOSS_SERVER_CONFIG_DIR_KEY) + File.separator + "themes";
|
|
||||||
}
|
|
||||||
return themeDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setThemeDir(String dir) {
|
|
||||||
System.setProperty(THEME_DIR_KEY, dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getThemeBase() {
|
|
||||||
return System.getProperty(THEME_BASE_KEY, THEME_BASE_DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setThemeBase(String baseTheme) {
|
|
||||||
System.setProperty(THEME_BASE_KEY, baseTheme);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getThemeDefault() {
|
|
||||||
return System.getProperty(THEME_DEFAULT_KEY, THEME_DEFAULT_DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setThemeDefault(String defaultTheme) {
|
|
||||||
System.setProperty(THEME_DEFAULT_KEY, defaultTheme);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getThemeAdmin() {
|
|
||||||
return System.getProperty(THEME_ADMIN_KEY, THEME_ADMIN_DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setThemeAdmin(String adminTheme) {
|
|
||||||
System.setProperty(THEME_ADMIN_KEY, adminTheme);
|
|
||||||
}
|
|
||||||
|
|
||||||
// EXPORT + IMPORT
|
|
||||||
|
|
||||||
public static String getExportImportAction() {
|
|
||||||
return System.getProperty(EXPORT_IMPORT_ACTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setExportImportAction(String exportImportAction) {
|
|
||||||
System.setProperty(EXPORT_IMPORT_ACTION, exportImportAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getExportImportProvider() {
|
|
||||||
return System.getProperty(EXPORT_IMPORT_PROVIDER, EXPORT_IMPORT_PROVIDER_DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setExportImportProvider(String exportImportProvider) {
|
|
||||||
System.setProperty(EXPORT_IMPORT_PROVIDER, exportImportProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getExportImportDir() {
|
|
||||||
return System.getProperty(EXPORT_IMPORT_DIR);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setExportImportDir(String exportImportDir) {
|
|
||||||
System.setProperty(EXPORT_IMPORT_DIR, exportImportDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getExportImportZipFile() {
|
|
||||||
return System.getProperty(EXPORT_IMPORT_ZIP_FILE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setExportImportZipFile(String exportImportZipFile) {
|
|
||||||
System.setProperty(EXPORT_IMPORT_ZIP_FILE, exportImportZipFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getExportImportZipPassword() {
|
|
||||||
return System.getProperty(EXPORT_IMPORT_ZIP_PASSWORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setExportImportZipPassword(String exportImportZipPassword) {
|
|
||||||
System.setProperty(EXPORT_IMPORT_ZIP_PASSWORD, exportImportZipPassword);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,12 +1,14 @@
|
||||||
package org.keycloak.models;
|
package org.keycloak.models;
|
||||||
|
|
||||||
|
import org.keycloak.provider.Provider;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public interface KeycloakSession {
|
public interface KeycloakSession extends Provider {
|
||||||
KeycloakTransaction getTransaction();
|
KeycloakTransaction getTransaction();
|
||||||
|
|
||||||
RealmModel createRealm(String name);
|
RealmModel createRealm(String name);
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
package org.keycloak.models;
|
package org.keycloak.models;
|
||||||
|
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public interface KeycloakSessionFactory {
|
public interface KeycloakSessionFactory extends ProviderFactory<KeycloakSession> {
|
||||||
KeycloakSession createSession();
|
KeycloakSession create(ProviderSession providerSession);
|
||||||
void close();
|
void close();
|
||||||
}
|
}
|
||||||
|
|
27
model/api/src/main/java/org/keycloak/models/ModelSpi.java
Normal file
27
model/api/src/main/java/org/keycloak/models/ModelSpi.java
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package org.keycloak.models;
|
||||||
|
|
||||||
|
import org.keycloak.provider.Provider;
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
import org.keycloak.provider.Spi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class ModelSpi implements Spi {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "model";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Provider> getProviderClass() {
|
||||||
|
return KeycloakSession.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||||
|
return KeycloakSessionFactory.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,49 +0,0 @@
|
||||||
package org.keycloak.models.utils;
|
|
||||||
|
|
||||||
import java.util.ServiceLoader;
|
|
||||||
|
|
||||||
import org.keycloak.models.Config;
|
|
||||||
import org.keycloak.models.ModelProvider;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class ModelProviderUtils {
|
|
||||||
|
|
||||||
public static final String DEFAULT_MODEL_PROVIDER = "jpa";
|
|
||||||
|
|
||||||
public static Iterable<ModelProvider> getRegisteredProviders() {
|
|
||||||
return ServiceLoader.load(ModelProvider.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ModelProvider getConfiguredModelProvider(Iterable<ModelProvider> providers) {
|
|
||||||
String configuredProvider = Config.getModelProvider();
|
|
||||||
ModelProvider provider = null;
|
|
||||||
|
|
||||||
if (configuredProvider != null) {
|
|
||||||
for (ModelProvider p : providers) {
|
|
||||||
if (p.getId().equals(configuredProvider)) {
|
|
||||||
provider = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (ModelProvider p : providers) {
|
|
||||||
if (provider == null) {
|
|
||||||
provider = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p.getId().equals(DEFAULT_MODEL_PROVIDER)) {
|
|
||||||
provider = p;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ModelProvider getConfiguredModelProvider() {
|
|
||||||
return getConfiguredModelProvider(getRegisteredProviders());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1 @@
|
||||||
|
org.keycloak.models.ModelSpi
|
|
@ -30,24 +30,6 @@
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>keycloak-audit-api</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>keycloak-audit-jpa</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>keycloak-audit-jboss-logging</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-model-api</artifactId>
|
<artifactId>keycloak-model-api</artifactId>
|
||||||
|
|
|
@ -1,28 +1,53 @@
|
||||||
package org.keycloak.models.jpa;
|
package org.keycloak.models.jpa;
|
||||||
|
|
||||||
|
import org.keycloak.Config;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
|
||||||
import javax.persistence.EntityManagerFactory;
|
import javax.persistence.EntityManagerFactory;
|
||||||
|
import javax.persistence.Persistence;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class JpaKeycloakSessionFactory implements KeycloakSessionFactory {
|
public class JpaKeycloakSessionFactory implements KeycloakSessionFactory {
|
||||||
protected EntityManagerFactory factory;
|
|
||||||
|
|
||||||
public JpaKeycloakSessionFactory(EntityManagerFactory factory) {
|
protected EntityManagerFactory emf;
|
||||||
this.factory = factory;
|
|
||||||
|
@Override
|
||||||
|
public void init(Config.Scope config) {
|
||||||
|
emf = Persistence.createEntityManagerFactory("jpa-keycloak-identity-store", getHibernateProperties());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeycloakSession createSession() {
|
public String getId() {
|
||||||
return new JpaKeycloakSession(factory.createEntityManager());
|
return "jpa";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeycloakSession create(ProviderSession providerSession) {
|
||||||
|
return new JpaKeycloakSession(emf.createEntityManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
factory.close();
|
emf.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allows to override some properties in persistence.xml by system properties
|
||||||
|
protected Properties getHibernateProperties() {
|
||||||
|
Properties result = new Properties();
|
||||||
|
|
||||||
|
for (Object property : System.getProperties().keySet()) {
|
||||||
|
if (property.toString().startsWith("hibernate.")) {
|
||||||
|
String propValue = System.getProperty(property.toString());
|
||||||
|
result.put(property, propValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
package org.keycloak.models.jpa;
|
|
||||||
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
|
||||||
import org.keycloak.models.ModelProvider;
|
|
||||||
|
|
||||||
import javax.persistence.EntityManagerFactory;
|
|
||||||
import javax.persistence.Persistence;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public class JpaModelProvider implements ModelProvider {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return "jpa";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public KeycloakSessionFactory createFactory() {
|
|
||||||
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa-keycloak-identity-store", getHibernateProperties());
|
|
||||||
return new JpaKeycloakSessionFactory(emf);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allows to override some properties in persistence.xml by system properties
|
|
||||||
protected Properties getHibernateProperties() {
|
|
||||||
Properties result = new Properties();
|
|
||||||
|
|
||||||
for (Object property : System.getProperties().keySet()) {
|
|
||||||
if (property.toString().startsWith("hibernate.")) {
|
|
||||||
String propValue = System.getProperty(property.toString());
|
|
||||||
result.put(property, propValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1 @@
|
||||||
|
org.keycloak.models.jpa.JpaKeycloakSessionFactory
|
|
@ -1 +0,0 @@
|
||||||
org.keycloak.models.jpa.JpaModelProvider
|
|
|
@ -44,18 +44,6 @@
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>keycloak-audit-api</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>keycloak-audit-jboss-logging</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.logging</groupId>
|
<groupId>org.jboss.logging</groupId>
|
||||||
<artifactId>jboss-logging</artifactId>
|
<artifactId>jboss-logging</artifactId>
|
||||||
|
@ -103,10 +91,10 @@
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<keycloak.mongo.host>localhost</keycloak.mongo.host>
|
<keycloak.model.mongo.host>localhost</keycloak.model.mongo.host>
|
||||||
<keycloak.mongo.port>27018</keycloak.mongo.port>
|
<keycloak.model.mongo.port>27018</keycloak.model.mongo.port>
|
||||||
<keycloak.mongo.db>keycloak</keycloak.mongo.db>
|
<keycloak.model.mongo.db>keycloak</keycloak.model.mongo.db>
|
||||||
<keycloak.mongo.clearOnStartup>true</keycloak.mongo.clearOnStartup>
|
<keycloak.model.mongo.clearOnStartup>true</keycloak.model.mongo.clearOnStartup>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -133,10 +121,10 @@
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<systemPropertyVariables>
|
<systemPropertyVariables>
|
||||||
<keycloak.mongo.host>${keycloak.mongo.host}</keycloak.mongo.host>
|
<keycloak.model.mongo.host>${keycloak.model.mongo.host}</keycloak.model.mongo.host>
|
||||||
<keycloak.mongo.port>${keycloak.mongo.port}</keycloak.mongo.port>
|
<keycloak.model.mongo.port>${keycloak.model.mongo.port}</keycloak.model.mongo.port>
|
||||||
<keycloak.mongo.db>${keycloak.mongo.db}</keycloak.mongo.db>
|
<keycloak.model.mongo.db>${keycloak.model.mongo.db}</keycloak.model.mongo.db>
|
||||||
<keycloak.mongo.clearOnStartup>${keycloak.mongo.clearOnStartup}</keycloak.mongo.clearOnStartup>
|
<keycloak.model.mongo.clearOnStartup>${keycloak.model.mongo.clearOnStartup}</keycloak.model.mongo.clearOnStartup>
|
||||||
</systemPropertyVariables>
|
</systemPropertyVariables>
|
||||||
<dependenciesToScan>
|
<dependenciesToScan>
|
||||||
<dependency>org.keycloak:keycloak-model-tests</dependency>
|
<dependency>org.keycloak:keycloak-model-tests</dependency>
|
||||||
|
@ -164,7 +152,7 @@
|
||||||
<goal>start</goal>
|
<goal>start</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<port>${keycloak.mongo.port}</port>
|
<port>${keycloak.model.mongo.port}</port>
|
||||||
<logging>file</logging>
|
<logging>file</logging>
|
||||||
<logFile>${project.build.directory}/mongodb.log</logFile>
|
<logFile>${project.build.directory}/mongodb.log</logFile>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
package org.keycloak.models.mongo.keycloak;
|
|
||||||
|
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
|
||||||
import org.keycloak.models.ModelProvider;
|
|
||||||
import org.keycloak.models.mongo.keycloak.adapters.MongoKeycloakSessionFactory;
|
|
||||||
import org.keycloak.models.mongo.keycloak.config.MongoClientProvider;
|
|
||||||
import org.keycloak.models.mongo.keycloak.config.MongoClientProviderHolder;
|
|
||||||
|
|
||||||
import java.lang.Override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public class MongoModelProvider implements ModelProvider {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return "mongo";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public KeycloakSessionFactory createFactory() {
|
|
||||||
MongoClientProvider mongoClientProvider = MongoClientProviderHolder.getInstance();
|
|
||||||
return new MongoKeycloakSessionFactory(mongoClientProvider);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,11 @@
|
||||||
package org.keycloak.models.mongo.keycloak.adapters;
|
package org.keycloak.models.mongo.keycloak.adapters;
|
||||||
|
|
||||||
|
import com.mongodb.DB;
|
||||||
|
import com.mongodb.MongoClient;
|
||||||
|
import com.mongodb.MongoCredential;
|
||||||
|
import com.mongodb.ServerAddress;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.Config;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.models.entities.AuthenticationLinkEntity;
|
import org.keycloak.models.entities.AuthenticationLinkEntity;
|
||||||
|
@ -10,7 +15,6 @@ import org.keycloak.models.entities.RequiredCredentialEntity;
|
||||||
import org.keycloak.models.entities.SocialLinkEntity;
|
import org.keycloak.models.entities.SocialLinkEntity;
|
||||||
import org.keycloak.models.mongo.api.MongoStore;
|
import org.keycloak.models.mongo.api.MongoStore;
|
||||||
import org.keycloak.models.mongo.impl.MongoStoreImpl;
|
import org.keycloak.models.mongo.impl.MongoStoreImpl;
|
||||||
import org.keycloak.models.mongo.keycloak.config.MongoClientProvider;
|
|
||||||
import org.keycloak.models.mongo.keycloak.entities.MongoApplicationEntity;
|
import org.keycloak.models.mongo.keycloak.entities.MongoApplicationEntity;
|
||||||
import org.keycloak.models.mongo.keycloak.entities.MongoOAuthClientEntity;
|
import org.keycloak.models.mongo.keycloak.entities.MongoOAuthClientEntity;
|
||||||
import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
|
import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
|
||||||
|
@ -18,6 +22,10 @@ import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
|
||||||
import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity;
|
import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity;
|
||||||
import org.keycloak.models.mongo.keycloak.entities.MongoUserSessionEntity;
|
import org.keycloak.models.mongo.keycloak.entities.MongoUserSessionEntity;
|
||||||
import org.keycloak.models.mongo.keycloak.entities.MongoUsernameLoginFailureEntity;
|
import org.keycloak.models.mongo.keycloak.entities.MongoUsernameLoginFailureEntity;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* KeycloakSessionFactory implementation based on MongoDB
|
* KeycloakSessionFactory implementation based on MongoDB
|
||||||
|
@ -42,21 +50,50 @@ public class MongoKeycloakSessionFactory implements KeycloakSessionFactory {
|
||||||
MongoUserSessionEntity.class
|
MongoUserSessionEntity.class
|
||||||
};
|
};
|
||||||
|
|
||||||
private final MongoClientProvider mongoClientProvider;
|
private MongoClient client;
|
||||||
private final MongoStore mongoStore;
|
|
||||||
|
|
||||||
public MongoKeycloakSessionFactory(MongoClientProvider provider) {
|
private MongoStore mongoStore;
|
||||||
this.mongoClientProvider = provider;
|
|
||||||
this.mongoStore = new MongoStoreImpl(provider.getDB(), provider.clearCollectionsOnStartup(), MANAGED_ENTITY_TYPES);
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return "mongo";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeycloakSession createSession() {
|
public void init(Config.Scope config) {
|
||||||
|
try {
|
||||||
|
String host = config.get("host", ServerAddress.defaultHost());
|
||||||
|
int port = config.getInt("port", ServerAddress.defaultPort());
|
||||||
|
String dbName = config.get("db", "keycloak-audit");
|
||||||
|
boolean clearOnStartup = config.getBoolean("clearOnStartup", false);
|
||||||
|
|
||||||
|
String user = config.get("user");
|
||||||
|
String password = config.get("password");
|
||||||
|
if (user != null && password != null) {
|
||||||
|
MongoCredential credential = MongoCredential.createMongoCRCredential(user, dbName, password.toCharArray());
|
||||||
|
client = new MongoClient(new ServerAddress(host, port), Collections.singletonList(credential));
|
||||||
|
} else {
|
||||||
|
client = new MongoClient(host, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
DB db = client.getDB(dbName);
|
||||||
|
|
||||||
|
this.mongoStore = new MongoStoreImpl(db, clearOnStartup, MANAGED_ENTITY_TYPES);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeycloakSession create(ProviderSession providerSession) {
|
||||||
return new MongoKeycloakSession(mongoStore);
|
return new MongoKeycloakSession(mongoStore);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
this.mongoClientProvider.close();
|
this.client.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
package org.keycloak.models.mongo.keycloak.config;
|
|
||||||
|
|
||||||
import com.mongodb.DB;
|
|
||||||
import com.mongodb.MongoClient;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public interface MongoClientProvider {
|
|
||||||
|
|
||||||
MongoClient getMongoClient();
|
|
||||||
|
|
||||||
DB getDB();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if collections should be cleared on startup
|
|
||||||
*/
|
|
||||||
boolean clearCollectionsOnStartup();
|
|
||||||
|
|
||||||
void close();
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package org.keycloak.models.mongo.keycloak.config;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides {@link MongoClientProvider} instance
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class MongoClientProviderHolder {
|
|
||||||
|
|
||||||
// Just use static object for now. Default idm is SystemPropsMongoClientProvider
|
|
||||||
private static MongoClientProvider instance = new SystemPropertiesMongoClientProvider();
|
|
||||||
|
|
||||||
public static MongoClientProvider getInstance() {
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setInstance(MongoClientProvider instance) {
|
|
||||||
MongoClientProviderHolder.instance = instance;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,104 +0,0 @@
|
||||||
package org.keycloak.models.mongo.keycloak.config;
|
|
||||||
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
|
|
||||||
import com.mongodb.DB;
|
|
||||||
import com.mongodb.MongoClient;
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instance of {@link MongoClientProvider} which reads configuration of MongoDB from system properties
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class SystemPropertiesMongoClientProvider implements MongoClientProvider {
|
|
||||||
|
|
||||||
protected static final Logger logger = Logger.getLogger(SystemPropertiesMongoClientProvider.class);
|
|
||||||
|
|
||||||
public static final String MONGO_HOST = "keycloak.mongo.host";
|
|
||||||
public static final String MONGO_PORT = "keycloak.mongo.port";
|
|
||||||
public static final String MONGO_DB_NAME = "keycloak.mongo.db";
|
|
||||||
public static final String MONGO_CLEAR_ON_STARTUP = "keycloak.mongo.clearOnStartup";
|
|
||||||
|
|
||||||
// Property names from Liveoak . Those are used as fallback
|
|
||||||
private static final String MONGO_HOST_2 = "mongo.host";
|
|
||||||
private static final String MONGO_PORT_2 = "mongo.port";
|
|
||||||
private static final String MONGO_DB_NAME_2 = "mongo.db";
|
|
||||||
private static final String MONGO_CLEAR_ON_STARTUP_2 = "mongo.clearOnStartup";
|
|
||||||
|
|
||||||
// Port where MongoDB instance is normally started on linux. This port should be used if we're not starting embedded instance
|
|
||||||
private static final String MONGO_DEFAULT_PORT = "27017";
|
|
||||||
|
|
||||||
private MongoClient mongoClient;
|
|
||||||
private DB db;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized MongoClient getMongoClient() {
|
|
||||||
if (this.mongoClient == null) {
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
return this.mongoClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized DB getDB() {
|
|
||||||
if (mongoClient == null) {
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
return this.db;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean clearCollectionsOnStartup() {
|
|
||||||
return isClearCollectionsOnStartup();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void close() {
|
|
||||||
// Assume that client is dedicated just for Keycloak, so close it
|
|
||||||
logger.info("Closing MongoDB client");
|
|
||||||
mongoClient.close();
|
|
||||||
mongoClient = null;
|
|
||||||
db = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void init() {
|
|
||||||
try {
|
|
||||||
String host = getMongoHost();
|
|
||||||
int port = getMongoPort();
|
|
||||||
String dbName = getMongoDbName();
|
|
||||||
boolean clearOnStartup = isClearCollectionsOnStartup();
|
|
||||||
|
|
||||||
logger.info(String.format("Configuring MongoStore with: host=%s, port=%d, dbName=%s, clearOnStartup=%b", host, port, dbName, clearOnStartup));
|
|
||||||
|
|
||||||
this.mongoClient = new MongoClient(host, port);
|
|
||||||
this.db = mongoClient.getDB(dbName);
|
|
||||||
} catch (UnknownHostException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getMongoHost() {
|
|
||||||
return getSystemPropertyWithFallback(MONGO_HOST, MONGO_HOST_2, "localhost");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getMongoPort() {
|
|
||||||
String portProp = getSystemPropertyWithFallback(MONGO_PORT, MONGO_PORT_2, MONGO_DEFAULT_PORT);
|
|
||||||
return Integer.parseInt(portProp);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getMongoDbName() {
|
|
||||||
return getSystemPropertyWithFallback(MONGO_DB_NAME, MONGO_DB_NAME_2, "keycloak");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isClearCollectionsOnStartup() {
|
|
||||||
String property = getSystemPropertyWithFallback(MONGO_CLEAR_ON_STARTUP, MONGO_CLEAR_ON_STARTUP_2, "false");
|
|
||||||
return "true".equalsIgnoreCase(property);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if property propName1 (like "keycloak.mongo.host" is available and if not, then fallback to property "mongo.host" )
|
|
||||||
private static String getSystemPropertyWithFallback(String propName1, String propName2, String defaultValue) {
|
|
||||||
String propValue1 = System.getProperty(propName1);
|
|
||||||
return propValue1!=null ? propValue1 : System.getProperty(propName2, defaultValue);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1 @@
|
||||||
|
org.keycloak.models.mongo.keycloak.adapters.MongoKeycloakSessionFactory
|
|
@ -1 +0,0 @@
|
||||||
org.keycloak.models.mongo.keycloak.MongoModelProvider
|
|
|
@ -1,31 +0,0 @@
|
||||||
package org.keycloak.models.mongo.test;
|
|
||||||
|
|
||||||
import org.keycloak.models.mongo.api.MongoEntity;
|
|
||||||
import org.keycloak.models.mongo.api.MongoField;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class Address {
|
|
||||||
|
|
||||||
private String street;
|
|
||||||
private int number;
|
|
||||||
|
|
||||||
public String getStreet() {
|
|
||||||
return street;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStreet(String street) {
|
|
||||||
this.street = street;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumber() {
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNumber(int number) {
|
|
||||||
this.number = number;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package org.keycloak.models.mongo.test;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.keycloak.models.mongo.api.MongoField;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Just to test inheritance
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class AddressWithFlats extends Address {
|
|
||||||
|
|
||||||
private List<String> flatNumbers;
|
|
||||||
|
|
||||||
public List<String> getFlatNumbers() {
|
|
||||||
return flatNumbers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFlatNumbers(List<String> flatNumbers) {
|
|
||||||
this.flatNumbers = flatNumbers;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,140 +0,0 @@
|
||||||
package org.keycloak.models.mongo.test;
|
|
||||||
|
|
||||||
import com.mongodb.DBObject;
|
|
||||||
import com.mongodb.QueryBuilder;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.keycloak.models.mongo.api.MongoStore;
|
|
||||||
import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
|
|
||||||
import org.keycloak.models.mongo.impl.MongoStoreImpl;
|
|
||||||
import org.keycloak.models.mongo.impl.context.TransactionMongoStoreInvocationContext;
|
|
||||||
import org.keycloak.models.mongo.keycloak.config.MongoClientProvider;
|
|
||||||
import org.keycloak.models.mongo.keycloak.config.MongoClientProviderHolder;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
public class MongoStoreTest {
|
|
||||||
|
|
||||||
private static final Class<?>[] MANAGED_DATA_TYPES = (Class<?>[])new Class<?>[] {
|
|
||||||
Person.class,
|
|
||||||
Address.class,
|
|
||||||
AddressWithFlats.class
|
|
||||||
};
|
|
||||||
|
|
||||||
private MongoClientProvider mongoClientProvider;
|
|
||||||
private MongoStore mongoStore;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void before() throws Exception {
|
|
||||||
mongoClientProvider = MongoClientProviderHolder.getInstance();
|
|
||||||
mongoStore = new MongoStoreImpl(mongoClientProvider.getDB(), true, MANAGED_DATA_TYPES);
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void after() throws Exception {
|
|
||||||
mongoClientProvider.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void mongoModelTest() throws Exception {
|
|
||||||
MongoStoreInvocationContext context = new TransactionMongoStoreInvocationContext(mongoStore);
|
|
||||||
|
|
||||||
// Add some user
|
|
||||||
Person john = new Person();
|
|
||||||
john.setFirstName("john");
|
|
||||||
john.setAge(25);
|
|
||||||
john.setGender(Person.Gender.MALE);
|
|
||||||
|
|
||||||
mongoStore.insertEntity(john, context);
|
|
||||||
|
|
||||||
// Add another user
|
|
||||||
Person mary = new Person();
|
|
||||||
mary.setFirstName("mary");
|
|
||||||
mary.setKids(asList("Peter", "Paul", "Wendy"));
|
|
||||||
|
|
||||||
AddressWithFlats addr1 = new AddressWithFlats();
|
|
||||||
addr1.setStreet("Elm");
|
|
||||||
addr1.setNumber(5);
|
|
||||||
addr1.setFlatNumbers(asList("flat1", "flat2"));
|
|
||||||
AddressWithFlats addr2 = new AddressWithFlats();
|
|
||||||
List<AddressWithFlats> addresses = new ArrayList<AddressWithFlats>();
|
|
||||||
addresses.add(addr1);
|
|
||||||
addresses.add(addr2);
|
|
||||||
|
|
||||||
mary.setAddresses(addresses);
|
|
||||||
mary.setMainAddress(addr1);
|
|
||||||
mary.setGender(Person.Gender.FEMALE);
|
|
||||||
mary.setGenders(asList(Person.Gender.FEMALE));
|
|
||||||
|
|
||||||
mongoStore.insertEntity(mary, context);
|
|
||||||
|
|
||||||
Assert.assertEquals(2, mongoStore.loadEntities(Person.class, new QueryBuilder().get(), context).size());
|
|
||||||
|
|
||||||
// Commit this context
|
|
||||||
context.commit();
|
|
||||||
|
|
||||||
Assert.assertEquals(2, mongoStore.loadEntities(Person.class, new QueryBuilder().get(), context).size());
|
|
||||||
|
|
||||||
DBObject query = new QueryBuilder().and("addresses.flatNumbers").is("flat1").get();
|
|
||||||
List<Person> persons = mongoStore.loadEntities(Person.class, query, context);
|
|
||||||
Assert.assertEquals(1, persons.size());
|
|
||||||
mary = persons.get(0);
|
|
||||||
Assert.assertEquals(mary.getFirstName(), "mary");
|
|
||||||
Assert.assertTrue(mary.getKids().contains("Paul"));
|
|
||||||
Assert.assertEquals(2, mary.getAddresses().size());
|
|
||||||
Assert.assertEquals(AddressWithFlats.class, mary.getAddresses().get(0).getClass());
|
|
||||||
|
|
||||||
// Test push/pull
|
|
||||||
mongoStore.pushItemToList(mary, "kids", "Pauline", true, context);
|
|
||||||
mongoStore.pullItemFromList(mary, "kids", "Paul", context);
|
|
||||||
|
|
||||||
Address addr3 = new Address();
|
|
||||||
addr3.setNumber(6);
|
|
||||||
addr3.setStreet("Broadway");
|
|
||||||
mongoStore.pushItemToList(mary, "addresses", addr3, true, context);
|
|
||||||
|
|
||||||
mary = mongoStore.loadEntity(Person.class, mary.getId(), context);
|
|
||||||
Assert.assertEquals(3, mary.getKids().size());
|
|
||||||
Assert.assertTrue(mary.getKids().contains("Pauline"));
|
|
||||||
Assert.assertFalse(mary.getKids().contains("Paul"));
|
|
||||||
Assert.assertEquals(3, mary.getAddresses().size());
|
|
||||||
Address mainAddress = mary.getMainAddress();
|
|
||||||
Assert.assertEquals("Elm", mainAddress.getStreet());
|
|
||||||
Assert.assertEquals(5, mainAddress.getNumber());
|
|
||||||
Assert.assertEquals(Person.Gender.FEMALE, mary.getGender());
|
|
||||||
Assert.assertTrue(mary.getGenders().contains(Person.Gender.FEMALE));
|
|
||||||
|
|
||||||
|
|
||||||
// Some test of Map (attributes)
|
|
||||||
mary.addAttribute("attr1", "value1");
|
|
||||||
mary.addAttribute("attr2", "value2");
|
|
||||||
mary.addAttribute("attr.some3", "value3");
|
|
||||||
mongoStore.updateEntity(mary, context);
|
|
||||||
|
|
||||||
mary = mongoStore.loadEntity(Person.class, mary.getId(), context);
|
|
||||||
Assert.assertEquals(3, mary.getAttributes().size());
|
|
||||||
|
|
||||||
mary.removeAttribute("attr2");
|
|
||||||
mary.removeAttribute("nonExisting");
|
|
||||||
mongoStore.updateEntity(mary, context);
|
|
||||||
|
|
||||||
mary = mongoStore.loadEntity(Person.class, mary.getId(), context);
|
|
||||||
Assert.assertEquals(2, mary.getAttributes().size());
|
|
||||||
Assert.assertEquals("value1", mary.getAttributes().get("attr1"));
|
|
||||||
Assert.assertEquals("value3", mary.getAttributes().get("attr.some3"));
|
|
||||||
|
|
||||||
context.commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> List<T> asList(T... objects) {
|
|
||||||
List<T> list = new ArrayList<T>();
|
|
||||||
list.addAll(Arrays.asList(objects));
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,114 +0,0 @@
|
||||||
package org.keycloak.models.mongo.test;
|
|
||||||
|
|
||||||
import org.keycloak.models.mongo.api.MongoCollection;
|
|
||||||
import org.keycloak.models.mongo.api.MongoIdentifiableEntity;
|
|
||||||
import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
|
||||||
*/
|
|
||||||
@MongoCollection(collectionName = "persons")
|
|
||||||
public class Person implements MongoIdentifiableEntity {
|
|
||||||
|
|
||||||
private String id;
|
|
||||||
private String firstName;
|
|
||||||
private int age;
|
|
||||||
private List<String> kids;
|
|
||||||
private List<AddressWithFlats> addresses;
|
|
||||||
private Address mainAddress;
|
|
||||||
private Gender gender;
|
|
||||||
private List<Gender> genders;
|
|
||||||
private Map<String, String> attributes = new HashMap<String, String>();
|
|
||||||
|
|
||||||
public String getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(String id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFirstName() {
|
|
||||||
return firstName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFirstName(String firstName) {
|
|
||||||
this.firstName = firstName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getAge() {
|
|
||||||
return age;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAge(int age) {
|
|
||||||
this.age = age;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Gender getGender() {
|
|
||||||
return gender;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setGender(Gender gender) {
|
|
||||||
this.gender = gender;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Gender> getGenders() {
|
|
||||||
return genders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setGenders(List<Gender> genders) {
|
|
||||||
this.genders = genders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getKids() {
|
|
||||||
return kids;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setKids(List<String> kids) {
|
|
||||||
this.kids = kids;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<AddressWithFlats> getAddresses() {
|
|
||||||
return addresses;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAddresses(List<AddressWithFlats> addresses) {
|
|
||||||
this.addresses = addresses;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Address getMainAddress() {
|
|
||||||
return mainAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMainAddress(Address mainAddress) {
|
|
||||||
this.mainAddress = mainAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> getAttributes() {
|
|
||||||
return attributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAttributes(Map<String, String> attributes) {
|
|
||||||
this.attributes = attributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addAttribute(String key, String value) {
|
|
||||||
attributes.put(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeAttribute(String key) {
|
|
||||||
attributes.remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterRemove(MongoStoreInvocationContext invocationContext) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static enum Gender {
|
|
||||||
MALE, FEMALE
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,10 +11,9 @@ import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.provider.ProviderSession;
|
import org.keycloak.provider.ProviderSession;
|
||||||
import org.keycloak.provider.ProviderSessionFactory;
|
import org.keycloak.provider.ProviderSessionFactory;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
@ -28,7 +27,6 @@ import org.keycloak.util.JsonSerialization;
|
||||||
*/
|
*/
|
||||||
public class AbstractModelTest {
|
public class AbstractModelTest {
|
||||||
|
|
||||||
protected static KeycloakSessionFactory factory;
|
|
||||||
protected static ProviderSessionFactory providerSessionFactory;
|
protected static ProviderSessionFactory providerSessionFactory;
|
||||||
|
|
||||||
protected KeycloakSession identitySession;
|
protected KeycloakSession identitySession;
|
||||||
|
@ -37,41 +35,40 @@ public class AbstractModelTest {
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void beforeClass() {
|
public static void beforeClass() {
|
||||||
factory = KeycloakApplication.createSessionFactory();
|
|
||||||
providerSessionFactory = KeycloakApplication.createProviderSessionFactory();
|
providerSessionFactory = KeycloakApplication.createProviderSessionFactory();
|
||||||
|
|
||||||
KeycloakSession identitySession = factory.createSession();
|
ProviderSession providerSession = providerSessionFactory.createSession();
|
||||||
|
KeycloakSession identitySession = providerSession.getProvider(KeycloakSession.class);
|
||||||
try {
|
try {
|
||||||
identitySession.getTransaction().begin();
|
identitySession.getTransaction().begin();
|
||||||
new ApplianceBootstrap().bootstrap(identitySession, "/auth");
|
new ApplianceBootstrap().bootstrap(identitySession, "/auth");
|
||||||
identitySession.getTransaction().commit();
|
identitySession.getTransaction().commit();
|
||||||
} finally {
|
} finally {
|
||||||
identitySession.close();
|
providerSession.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void afterClass() {
|
public static void afterClass() {
|
||||||
providerSessionFactory.close();
|
providerSessionFactory.close();
|
||||||
factory.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void before() throws Exception {
|
public void before() throws Exception {
|
||||||
identitySession = factory.createSession();
|
providerSession = providerSessionFactory.createSession();
|
||||||
|
|
||||||
|
identitySession = providerSession.getProvider(KeycloakSession.class);
|
||||||
identitySession.getTransaction().begin();
|
identitySession.getTransaction().begin();
|
||||||
realmManager = new RealmManager(identitySession);
|
realmManager = new RealmManager(identitySession);
|
||||||
|
|
||||||
providerSession = providerSessionFactory.createSession();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void after() throws Exception {
|
public void after() throws Exception {
|
||||||
identitySession.getTransaction().commit();
|
identitySession.getTransaction().commit();
|
||||||
providerSession.close();
|
providerSession.close();
|
||||||
identitySession.close();
|
|
||||||
|
|
||||||
identitySession = factory.createSession();
|
providerSession = providerSessionFactory.createSession();
|
||||||
|
identitySession = providerSession.getProvider(KeycloakSession.class);
|
||||||
try {
|
try {
|
||||||
identitySession.getTransaction().begin();
|
identitySession.getTransaction().begin();
|
||||||
|
|
||||||
|
@ -84,7 +81,7 @@ public class AbstractModelTest {
|
||||||
|
|
||||||
identitySession.getTransaction().commit();
|
identitySession.getTransaction().commit();
|
||||||
} finally {
|
} finally {
|
||||||
identitySession.close();
|
providerSession.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -103,8 +100,10 @@ public class AbstractModelTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void resetSession() {
|
protected void resetSession() {
|
||||||
identitySession.close();
|
providerSession.close();
|
||||||
identitySession = factory.createSession();
|
|
||||||
|
providerSession = providerSessionFactory.createSession();
|
||||||
|
identitySession = providerSession.getProvider(KeycloakSession.class);
|
||||||
identitySession.getTransaction().begin();
|
identitySession.getTransaction().begin();
|
||||||
realmManager = new RealmManager(identitySession);
|
realmManager = new RealmManager(identitySession);
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,7 +164,7 @@ public class AuthenticationManagerTest extends AbstractModelTest {
|
||||||
realm.setAccessTokenLifespan(1000);
|
realm.setAccessTokenLifespan(1000);
|
||||||
realm.addRequiredCredential(CredentialRepresentation.PASSWORD);
|
realm.addRequiredCredential(CredentialRepresentation.PASSWORD);
|
||||||
realm.setAuthenticationProviders(Arrays.asList(AuthenticationProviderModel.DEFAULT_PROVIDER));
|
realm.setAuthenticationProviders(Arrays.asList(AuthenticationProviderModel.DEFAULT_PROVIDER));
|
||||||
protector = new BruteForceProtector(factory);
|
protector = new BruteForceProtector(providerSessionFactory);
|
||||||
protector.start();
|
protector.start();
|
||||||
am = new AuthenticationManager(providerSession, protector);
|
am = new AuthenticationManager(providerSession, protector);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package org.keycloak.picketlink;
|
||||||
|
|
||||||
|
import org.keycloak.provider.Provider;
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
import org.keycloak.provider.Spi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class IdentityManagerSpi implements Spi {
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "picketlink-identity-manager";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Provider> getProviderClass() {
|
||||||
|
return IdentityManagerProvider.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||||
|
return IdentityManagerProviderFactory.class;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
org.keycloak.picketlink.IdentityManagerSpi
|
|
@ -1,5 +1,6 @@
|
||||||
package org.keycloak.picketlink.realm;
|
package org.keycloak.picketlink.realm;
|
||||||
|
|
||||||
|
import org.keycloak.Config;
|
||||||
import org.keycloak.picketlink.IdentityManagerProvider;
|
import org.keycloak.picketlink.IdentityManagerProvider;
|
||||||
import org.keycloak.picketlink.IdentityManagerProviderFactory;
|
import org.keycloak.picketlink.IdentityManagerProviderFactory;
|
||||||
import org.keycloak.provider.ProviderSession;
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
@ -20,7 +21,7 @@ public class RealmIdentityManagerProviderFactory implements IdentityManagerProvi
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init(Config.Scope config) {
|
||||||
partitionManagerRegistry = new PartitionManagerRegistry();
|
partitionManagerRegistry = new PartitionManagerRegistry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,8 +34,4 @@ public class RealmIdentityManagerProviderFactory implements IdentityManagerProvi
|
||||||
return "realm";
|
return "realm";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean lazyLoad() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import org.jboss.resteasy.core.Dispatcher;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.services.resources.KeycloakApplication;
|
import org.keycloak.services.resources.KeycloakApplication;
|
||||||
|
|
||||||
|
@ -22,7 +23,8 @@ public class UpsSecurityApplication extends KeycloakApplication {
|
||||||
@Override
|
@Override
|
||||||
protected void setupDefaultRealm(String contextPath) {
|
protected void setupDefaultRealm(String contextPath) {
|
||||||
super.setupDefaultRealm(contextPath);
|
super.setupDefaultRealm(contextPath);
|
||||||
KeycloakSession session = factory.createSession();
|
ProviderSession providerSession = providerSessionFactory.createSession();
|
||||||
|
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||||
session.getTransaction().begin();
|
session.getTransaction().begin();
|
||||||
|
|
||||||
// disable master realm by deleting the admin user.
|
// disable master realm by deleting the admin user.
|
||||||
|
@ -33,7 +35,7 @@ public class UpsSecurityApplication extends KeycloakApplication {
|
||||||
if (admin != null) master.removeUser(admin.getLoginName());
|
if (admin != null) master.removeUser(admin.getLoginName());
|
||||||
session.getTransaction().commit();
|
session.getTransaction().commit();
|
||||||
} finally {
|
} finally {
|
||||||
session.close();
|
providerSession.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,6 +225,39 @@
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Mongo dependencies -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-model-mongo</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-audit-mongo</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mongodb</groupId>
|
||||||
|
<artifactId>mongo-java-driver</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.picketlink</groupId>
|
||||||
|
<artifactId>picketlink-common</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.picketlink</groupId>
|
||||||
|
<artifactId>picketlink-idm-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.picketlink</groupId>
|
||||||
|
<artifactId>picketlink-idm-impl</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.picketlink</groupId>
|
||||||
|
<artifactId>picketlink-idm-simple-schema</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- export/import -->
|
<!-- export/import -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
|
|
26
server/src/main/resources/META-INF/keycloak-server.json
Normal file
26
server/src/main/resources/META-INF/keycloak-server.json
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"admin": {
|
||||||
|
"realm": "keycloak-admin"
|
||||||
|
},
|
||||||
|
|
||||||
|
"audit": {
|
||||||
|
"provider": "jpa"
|
||||||
|
},
|
||||||
|
|
||||||
|
"model": {
|
||||||
|
"provider": "jpa"
|
||||||
|
},
|
||||||
|
|
||||||
|
"timer": {
|
||||||
|
"provider": "basic"
|
||||||
|
},
|
||||||
|
|
||||||
|
"theme": {
|
||||||
|
"default": "keycloak",
|
||||||
|
"dir": "${jboss.server.config.dir}/themes"
|
||||||
|
},
|
||||||
|
|
||||||
|
"scheduled": {
|
||||||
|
"interval": 900
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<property name="hibernate.hbm2ddl.auto" value="update" />
|
<property name="hibernate.hbm2ddl.auto" value="update" />
|
||||||
|
<property name="jboss.as.jpa.managed" value="false" />
|
||||||
</properties>
|
</properties>
|
||||||
</persistence-unit>
|
</persistence-unit>
|
||||||
|
|
||||||
|
@ -35,6 +36,7 @@
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<property name="hibernate.hbm2ddl.auto" value="update" />
|
<property name="hibernate.hbm2ddl.auto" value="update" />
|
||||||
|
<property name="jboss.as.jpa.managed" value="false" />
|
||||||
</properties>
|
</properties>
|
||||||
</persistence-unit>
|
</persistence-unit>
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,7 @@
|
||||||
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.logging</groupId>
|
<groupId>org.jboss.logging</groupId>
|
||||||
<artifactId>jboss-logging</artifactId>
|
<artifactId>jboss-logging</artifactId>
|
||||||
|
|
|
@ -6,6 +6,8 @@ import org.keycloak.provider.ProviderSession;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -13,6 +15,7 @@ import java.util.Set;
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class DefaultProviderSession implements ProviderSession {
|
public class DefaultProviderSession implements ProviderSession {
|
||||||
|
|
||||||
private DefaultProviderSessionFactory factory;
|
private DefaultProviderSessionFactory factory;
|
||||||
private Map<Integer, Provider> providers = new HashMap<Integer, Provider>();
|
private Map<Integer, Provider> providers = new HashMap<Integer, Provider>();
|
||||||
|
|
||||||
|
@ -21,8 +24,16 @@ public class DefaultProviderSession implements ProviderSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends Provider> T getProvider(Class<T> clazz) {
|
public <T extends Provider> T getProvider(Class<T> clazz) {
|
||||||
String id = factory.getDefaultProvider(clazz);
|
Integer hash = clazz.hashCode();
|
||||||
return id != null ? getProvider(clazz, id) : null;
|
T provider = (T) providers.get(hash);
|
||||||
|
if (provider == null) {
|
||||||
|
ProviderFactory<T> providerFactory = factory.getProviderFactory(clazz);
|
||||||
|
if (providerFactory != null) {
|
||||||
|
provider = providerFactory.create(this);
|
||||||
|
providers.put(hash, provider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends Provider> T getProvider(Class<T> clazz, String id) {
|
public <T extends Provider> T getProvider(Class<T> clazz, String id) {
|
||||||
|
@ -39,15 +50,14 @@ public class DefaultProviderSession implements ProviderSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends Provider> Set<String> listProviderIds(Class<T> clazz) {
|
public <T extends Provider> Set<String> listProviderIds(Class<T> clazz) {
|
||||||
return factory.providerIds(clazz);
|
return factory.getAllProviderIds(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends Provider> Set<T> getAllProviders(Class<T> clazz) {
|
public <T extends Provider> Set<T> getAllProviders(Class<T> clazz) {
|
||||||
Set<String> providerIds = listProviderIds(clazz);
|
|
||||||
Set<T> providers = new HashSet<T>();
|
Set<T> providers = new HashSet<T>();
|
||||||
for (String providerId : providerIds) {
|
for (String id : listProviderIds(clazz)) {
|
||||||
providers.add(getProvider(clazz, providerId));
|
providers.add(getProvider(clazz, id));
|
||||||
}
|
}
|
||||||
return providers;
|
return providers;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,71 +1,99 @@
|
||||||
package org.keycloak.services;
|
package org.keycloak.services;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.Config;
|
||||||
import org.keycloak.provider.Provider;
|
import org.keycloak.provider.Provider;
|
||||||
import org.keycloak.provider.ProviderFactory;
|
import org.keycloak.provider.ProviderFactory;
|
||||||
import org.keycloak.provider.ProviderFactoryLoader;
|
|
||||||
import org.keycloak.provider.ProviderSession;
|
import org.keycloak.provider.ProviderSession;
|
||||||
import org.keycloak.provider.ProviderSessionFactory;
|
import org.keycloak.provider.ProviderSessionFactory;
|
||||||
|
import org.keycloak.provider.Spi;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class DefaultProviderSessionFactory implements ProviderSessionFactory {
|
public class DefaultProviderSessionFactory implements ProviderSessionFactory {
|
||||||
|
|
||||||
private Map<Class<? extends Provider>, ProviderFactoryLoader> loaders = new HashMap<Class<? extends Provider>, ProviderFactoryLoader>();
|
private static final Logger log = Logger.getLogger(DefaultProviderSessionFactory.class);
|
||||||
private Map<Class<? extends Provider>, String> defaultFactories = new HashMap<Class<? extends Provider>, String>();
|
|
||||||
|
private Map<Class<? extends Provider>, String> provider = new HashMap<Class<? extends Provider>, String>();
|
||||||
|
private Map<Class<? extends Provider>, Map<String, ProviderFactory>> factoriesMap = new HashMap<Class<? extends Provider>, Map<String, ProviderFactory>>();
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
for (Spi spi : ServiceLoader.load(Spi.class)) {
|
||||||
|
Map<String, ProviderFactory> factories = new HashMap<String, ProviderFactory>();
|
||||||
|
factoriesMap.put(spi.getProviderClass(), factories);
|
||||||
|
|
||||||
|
String provider = Config.getProvider(spi.getName());
|
||||||
|
if (provider != null) {
|
||||||
|
this.provider.put(spi.getProviderClass(), provider);
|
||||||
|
|
||||||
|
ProviderFactory factory = loadProviderFactory(spi, provider);
|
||||||
|
Config.Scope scope = Config.scope(spi.getName(), provider);
|
||||||
|
factory.init(scope);
|
||||||
|
log.debug("Initialized " + factory.getClass().getName() + " (config = " + scope + ")");
|
||||||
|
|
||||||
|
factories.put(factory.getId(), factory);
|
||||||
|
|
||||||
|
log.info("Loaded SPI " + spi.getName() + " (provider = " + provider + ")");
|
||||||
|
} else {
|
||||||
|
for (ProviderFactory factory : ServiceLoader.load(spi.getProviderFactoryClass())) {
|
||||||
|
Config.Scope scope = Config.scope(spi.getName(), factory.getId());
|
||||||
|
factory.init(scope);
|
||||||
|
log.debug("Initialized " + factory.getClass().getName() + " (config = " + scope + ")");
|
||||||
|
|
||||||
|
factories.put(factory.getId(), factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (factories.size() == 1) {
|
||||||
|
provider = factories.values().iterator().next().getId();
|
||||||
|
this.provider.put(spi.getProviderClass(), provider);
|
||||||
|
|
||||||
|
log.info("Loaded SPI " + spi.getName() + " (provider = " + provider + ")");
|
||||||
|
} else {
|
||||||
|
log.info("Loaded SPI " + spi.getName() + " (providers = " + factories.keySet() + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProviderFactory loadProviderFactory(Spi spi, String id) {
|
||||||
|
for (ProviderFactory factory : ServiceLoader.load(spi.getProviderFactoryClass())) {
|
||||||
|
if (factory.getId().equals(id)){
|
||||||
|
return factory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Failed to find provider " + id + " for " + spi.getName());
|
||||||
|
}
|
||||||
|
|
||||||
public ProviderSession createSession() {
|
public ProviderSession createSession() {
|
||||||
return new DefaultProviderSession(this);
|
return new DefaultProviderSession(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz) {
|
||||||
|
return getProviderFactory(clazz, provider.get(clazz));
|
||||||
|
}
|
||||||
|
|
||||||
|
<T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz, String id) {
|
||||||
|
return factoriesMap.get(clazz).get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
<T extends Provider> Set<String> getAllProviderIds(Class<T> clazz) {
|
||||||
|
Set<String> ids = new HashSet<String>();
|
||||||
|
for (ProviderFactory f : factoriesMap.get(clazz).values()) {
|
||||||
|
ids.add(f.getId());
|
||||||
|
}
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
for (ProviderFactoryLoader loader : loaders.values()) {
|
for (Map<String, ProviderFactory> factories : factoriesMap.values()) {
|
||||||
loader.close();
|
for (ProviderFactory factory : factories.values()) {
|
||||||
|
factory.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz) {
|
|
||||||
String id = defaultFactories.get(clazz);
|
|
||||||
if (id == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return getProviderFactory(clazz, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz, String id) {
|
|
||||||
ProviderFactoryLoader loader = getLoader(clazz);
|
|
||||||
return loader != null ? loader.find(id) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> providerIds(Class<? extends Provider> clazz) {
|
|
||||||
ProviderFactoryLoader loader = getLoader(clazz);
|
|
||||||
return loader != null ? loader.providerIds() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDefaultProvider(Class<? extends Provider> clazz) {
|
|
||||||
return defaultFactories.get(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerLoader(Class<? extends Provider> clazz, ProviderFactoryLoader loader) {
|
|
||||||
loaders.put(clazz, loader);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerLoader(Class<? extends Provider> clazz, ProviderFactoryLoader loader, String defaultProvider) {
|
|
||||||
loaders.put(clazz, loader);
|
|
||||||
defaultFactories.put(clazz, defaultProvider);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init() {
|
|
||||||
for (ProviderFactoryLoader l : loaders.values()) {
|
|
||||||
l.init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T extends Provider> ProviderFactoryLoader getLoader(Class<T> clazz) {
|
|
||||||
return loaders.get(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,9 +32,7 @@ public class KeycloakSessionServletFilter implements Filter {
|
||||||
|
|
||||||
ResteasyProviderFactory.pushContext(ProviderSession.class, providerSession);
|
ResteasyProviderFactory.pushContext(ProviderSession.class, providerSession);
|
||||||
|
|
||||||
KeycloakSessionFactory factory = (KeycloakSessionFactory) servletRequest.getServletContext().getAttribute(KeycloakSessionFactory.class.getName());
|
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||||
if (factory == null) throw new ServletException("Factory was null");
|
|
||||||
KeycloakSession session = factory.createSession();
|
|
||||||
ResteasyProviderFactory.pushContext(KeycloakSession.class, session);
|
ResteasyProviderFactory.pushContext(KeycloakSession.class, session);
|
||||||
KeycloakTransaction tx = session.getTransaction();
|
KeycloakTransaction tx = session.getTransaction();
|
||||||
ResteasyProviderFactory.pushContext(KeycloakTransaction.class, tx);
|
ResteasyProviderFactory.pushContext(KeycloakTransaction.class, tx);
|
||||||
|
@ -56,7 +54,6 @@ public class KeycloakSessionServletFilter implements Filter {
|
||||||
if (tx.isActive()) tx.rollback();
|
if (tx.isActive()) tx.rollback();
|
||||||
throw ex;
|
throw ex;
|
||||||
} finally {
|
} finally {
|
||||||
session.close();
|
|
||||||
providerSession.close();
|
providerSession.close();
|
||||||
ResteasyProviderFactory.clearContextData();
|
ResteasyProviderFactory.clearContextData();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,14 +6,15 @@ import org.jboss.logging.Logger;
|
||||||
import org.keycloak.models.AdminRoles;
|
import org.keycloak.models.AdminRoles;
|
||||||
import org.keycloak.models.ApplicationModel;
|
import org.keycloak.models.ApplicationModel;
|
||||||
import org.keycloak.models.AuthenticationProviderModel;
|
import org.keycloak.models.AuthenticationProviderModel;
|
||||||
import org.keycloak.models.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserCredentialModel;
|
import org.keycloak.models.UserCredentialModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
import org.keycloak.provider.ProviderSessionFactory;
|
||||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -26,26 +27,25 @@ public class ApplianceBootstrap {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(ApplianceBootstrap.class);
|
private static final Logger logger = Logger.getLogger(ApplianceBootstrap.class);
|
||||||
|
|
||||||
public void bootstrap(KeycloakSessionFactory factory, String contextPath) {
|
public void bootstrap(ProviderSessionFactory factory, String contextPath) {
|
||||||
KeycloakSession session = factory.createSession();
|
ProviderSession providerSession = factory.createSession();
|
||||||
|
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||||
session.getTransaction().begin();
|
session.getTransaction().begin();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
bootstrap(session, contextPath);
|
bootstrap(session, contextPath);
|
||||||
session.getTransaction().commit();
|
session.getTransaction().commit();
|
||||||
} finally {
|
} finally {
|
||||||
session.close();
|
providerSession.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bootstrap(KeycloakSession session, String contextPath) {
|
public void bootstrap(KeycloakSession session, String contextPath) {
|
||||||
if (session.getRealm(Config.getAdminRealm()) != null) {
|
String adminRealmName = Config.getAdminRealm();
|
||||||
|
if (session.getRealm(adminRealmName) != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String adminRealmName = Config.getAdminRealm();
|
|
||||||
|
|
||||||
logger.info("Initializing " + adminRealmName + " realm");
|
logger.info("Initializing " + adminRealmName + " realm");
|
||||||
|
|
||||||
RealmManager manager = new RealmManager(session);
|
RealmManager manager = new RealmManager(session);
|
||||||
|
|
|
@ -6,6 +6,8 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UsernameLoginFailureModel;
|
import org.keycloak.models.UsernameLoginFailureModel;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
import org.keycloak.provider.ProviderSessionFactory;
|
||||||
import org.keycloak.services.ClientConnection;
|
import org.keycloak.services.ClientConnection;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -25,7 +27,7 @@ public class BruteForceProtector implements Runnable {
|
||||||
|
|
||||||
protected volatile boolean run = true;
|
protected volatile boolean run = true;
|
||||||
protected int maxDeltaTimeSeconds = 60 * 60 * 12; // 12 hours
|
protected int maxDeltaTimeSeconds = 60 * 60 * 12; // 12 hours
|
||||||
protected KeycloakSessionFactory factory;
|
protected ProviderSessionFactory factory;
|
||||||
protected CountDownLatch shutdownLatch = new CountDownLatch(1);
|
protected CountDownLatch shutdownLatch = new CountDownLatch(1);
|
||||||
|
|
||||||
protected volatile long failures;
|
protected volatile long failures;
|
||||||
|
@ -73,7 +75,7 @@ public class BruteForceProtector implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public BruteForceProtector(KeycloakSessionFactory factory) {
|
public BruteForceProtector(ProviderSessionFactory factory) {
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +162,8 @@ public class BruteForceProtector implements Runnable {
|
||||||
events.add(take);
|
events.add(take);
|
||||||
queue.drainTo(events, TRANSACTION_SIZE);
|
queue.drainTo(events, TRANSACTION_SIZE);
|
||||||
Collections.sort(events); // we sort to avoid deadlock due to ordered updates. Maybe I'm overthinking this.
|
Collections.sort(events); // we sort to avoid deadlock due to ordered updates. Maybe I'm overthinking this.
|
||||||
KeycloakSession session = factory.createSession();
|
ProviderSession providerSession = factory.createSession();
|
||||||
|
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||||
session.getTransaction().begin();
|
session.getTransaction().begin();
|
||||||
try {
|
try {
|
||||||
for (LoginEvent event : events) {
|
for (LoginEvent event : events) {
|
||||||
|
@ -179,7 +182,7 @@ public class BruteForceProtector implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
events.clear();
|
events.clear();
|
||||||
session.close();
|
providerSession.close();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("Failed processing event", e);
|
logger.error("Failed processing event", e);
|
||||||
|
|
|
@ -7,7 +7,7 @@ import org.keycloak.models.ApplicationModel;
|
||||||
import org.keycloak.models.AuthenticationLinkModel;
|
import org.keycloak.models.AuthenticationLinkModel;
|
||||||
import org.keycloak.models.AuthenticationProviderModel;
|
import org.keycloak.models.AuthenticationProviderModel;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.OAuthClientModel;
|
import org.keycloak.models.OAuthClientModel;
|
||||||
|
|
|
@ -1,39 +1,30 @@
|
||||||
package org.keycloak.services.resources;
|
package org.keycloak.services.resources;
|
||||||
|
|
||||||
import org.jboss.resteasy.core.Dispatcher;
|
import org.codehaus.jackson.JsonNode;
|
||||||
|
import org.codehaus.jackson.map.ObjectMapper;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
import org.jboss.resteasy.core.Dispatcher;
|
||||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||||
|
import org.keycloak.Config;
|
||||||
import org.keycloak.SkeletonKeyContextResolver;
|
import org.keycloak.SkeletonKeyContextResolver;
|
||||||
import org.keycloak.audit.AuditListener;
|
|
||||||
import org.keycloak.audit.AuditListenerFactory;
|
|
||||||
import org.keycloak.audit.AuditProvider;
|
|
||||||
import org.keycloak.audit.AuditProviderFactory;
|
|
||||||
import org.keycloak.authentication.AuthenticationProvider;
|
|
||||||
import org.keycloak.authentication.AuthenticationProviderFactory;
|
|
||||||
import org.keycloak.exportimport.ExportImportProvider;
|
import org.keycloak.exportimport.ExportImportProvider;
|
||||||
import org.keycloak.models.Config;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
|
||||||
import org.keycloak.models.ModelProvider;
|
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.provider.ProviderFactory;
|
|
||||||
import org.keycloak.provider.ProviderFactoryLoader;
|
|
||||||
import org.keycloak.provider.ProviderSession;
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
import org.keycloak.provider.ProviderSessionFactory;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.services.DefaultProviderSessionFactory;
|
import org.keycloak.services.DefaultProviderSessionFactory;
|
||||||
import org.keycloak.provider.ProviderSessionFactory;
|
|
||||||
import org.keycloak.services.managers.ApplianceBootstrap;
|
import org.keycloak.services.managers.ApplianceBootstrap;
|
||||||
import org.keycloak.services.managers.BruteForceProtector;
|
import org.keycloak.services.managers.BruteForceProtector;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.services.managers.SocialRequestManager;
|
import org.keycloak.services.managers.SocialRequestManager;
|
||||||
import org.keycloak.services.managers.TokenManager;
|
import org.keycloak.services.managers.TokenManager;
|
||||||
import org.keycloak.services.resources.admin.AdminRoot;
|
import org.keycloak.services.resources.admin.AdminRoot;
|
||||||
import org.keycloak.models.utils.ModelProviderUtils;
|
|
||||||
import org.keycloak.services.scheduled.ClearExpiredAuditEvents;
|
import org.keycloak.services.scheduled.ClearExpiredAuditEvents;
|
||||||
import org.keycloak.services.scheduled.ClearExpiredUserSessions;
|
import org.keycloak.services.scheduled.ClearExpiredUserSessions;
|
||||||
import org.keycloak.services.scheduled.ScheduledTaskRunner;
|
import org.keycloak.services.scheduled.ScheduledTaskRunner;
|
||||||
|
import org.keycloak.services.util.JsonConfigProvider;
|
||||||
import org.keycloak.timer.TimerProvider;
|
import org.keycloak.timer.TimerProvider;
|
||||||
import org.keycloak.timer.TimerProviderFactory;
|
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
import org.keycloak.util.ProviderLoader;
|
import org.keycloak.util.ProviderLoader;
|
||||||
|
|
||||||
|
@ -41,12 +32,13 @@ import javax.servlet.ServletContext;
|
||||||
import javax.ws.rs.core.Application;
|
import javax.ws.rs.core.Application;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Date;
|
import java.net.URL;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -63,22 +55,21 @@ public class KeycloakApplication extends Application {
|
||||||
protected Set<Object> singletons = new HashSet<Object>();
|
protected Set<Object> singletons = new HashSet<Object>();
|
||||||
protected Set<Class<?>> classes = new HashSet<Class<?>>();
|
protected Set<Class<?>> classes = new HashSet<Class<?>>();
|
||||||
|
|
||||||
protected KeycloakSessionFactory factory;
|
|
||||||
protected ProviderSessionFactory providerSessionFactory;
|
protected ProviderSessionFactory providerSessionFactory;
|
||||||
protected String contextPath;
|
protected String contextPath;
|
||||||
|
|
||||||
public KeycloakApplication(@Context ServletContext context, @Context Dispatcher dispatcher) {
|
public KeycloakApplication(@Context ServletContext context, @Context Dispatcher dispatcher) {
|
||||||
|
loadConfig();
|
||||||
|
|
||||||
|
this.providerSessionFactory = createProviderSessionFactory();
|
||||||
|
|
||||||
dispatcher.getDefaultContextObjects().put(KeycloakApplication.class, this);
|
dispatcher.getDefaultContextObjects().put(KeycloakApplication.class, this);
|
||||||
this.contextPath = context.getContextPath();
|
this.contextPath = context.getContextPath();
|
||||||
this.factory = createSessionFactory();
|
BruteForceProtector protector = new BruteForceProtector(providerSessionFactory);
|
||||||
BruteForceProtector protector = new BruteForceProtector(factory);
|
|
||||||
dispatcher.getDefaultContextObjects().put(BruteForceProtector.class, protector);
|
dispatcher.getDefaultContextObjects().put(BruteForceProtector.class, protector);
|
||||||
ResteasyProviderFactory.pushContext(BruteForceProtector.class, protector); // for injection
|
ResteasyProviderFactory.pushContext(BruteForceProtector.class, protector); // for injection
|
||||||
protector.start();
|
protector.start();
|
||||||
context.setAttribute(BruteForceProtector.class.getName(), protector);
|
context.setAttribute(BruteForceProtector.class.getName(), protector);
|
||||||
this.providerSessionFactory = createProviderSessionFactory();
|
|
||||||
context.setAttribute(KeycloakSessionFactory.class.getName(), factory);
|
|
||||||
|
|
||||||
context.setAttribute(ProviderSessionFactory.class.getName(), this.providerSessionFactory);
|
context.setAttribute(ProviderSessionFactory.class.getName(), this.providerSessionFactory);
|
||||||
|
|
||||||
TokenManager tokenManager = new TokenManager();
|
TokenManager tokenManager = new TokenManager();
|
||||||
|
@ -95,7 +86,7 @@ public class KeycloakApplication extends Application {
|
||||||
|
|
||||||
setupDefaultRealm(context.getContextPath());
|
setupDefaultRealm(context.getContextPath());
|
||||||
|
|
||||||
setupScheduledTasks(providerSessionFactory, factory);
|
setupScheduledTasks(providerSessionFactory);
|
||||||
importRealms(context);
|
importRealms(context);
|
||||||
|
|
||||||
checkExportImportProvider();
|
checkExportImportProvider();
|
||||||
|
@ -115,55 +106,38 @@ public class KeycloakApplication extends Application {
|
||||||
return uriInfo.getBaseUriBuilder().replacePath(getContextPath()).build();
|
return uriInfo.getBaseUriBuilder().replacePath(getContextPath()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void loadConfig() {
|
||||||
|
try {
|
||||||
|
URL config = Thread.currentThread().getContextClassLoader().getResource("META-INF/keycloak-server.json");
|
||||||
|
|
||||||
|
if (config != null) {
|
||||||
|
JsonNode node = new ObjectMapper().readTree(config);
|
||||||
|
Config.init(new JsonConfigProvider(node));
|
||||||
|
|
||||||
|
log.info("Loaded config from " + config);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Failed to load config", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void setupDefaultRealm(String contextPath) {
|
protected void setupDefaultRealm(String contextPath) {
|
||||||
new ApplianceBootstrap().bootstrap(factory, contextPath);
|
new ApplianceBootstrap().bootstrap(providerSessionFactory, contextPath);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static KeycloakSessionFactory createSessionFactory() {
|
|
||||||
ModelProvider provider = ModelProviderUtils.getConfiguredModelProvider();
|
|
||||||
|
|
||||||
if (provider != null) {
|
|
||||||
log.debug("Model provider: " + provider.getId());
|
|
||||||
return provider.createFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new RuntimeException("Model provider not found");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DefaultProviderSessionFactory createProviderSessionFactory() {
|
public static DefaultProviderSessionFactory createProviderSessionFactory() {
|
||||||
DefaultProviderSessionFactory factory = new DefaultProviderSessionFactory();
|
DefaultProviderSessionFactory factory = new DefaultProviderSessionFactory();
|
||||||
|
|
||||||
factory.registerLoader(AuditProvider.class, ProviderFactoryLoader.create(AuditProviderFactory.class), Config.getAuditProvider());
|
|
||||||
factory.registerLoader(AuditListener.class, ProviderFactoryLoader.create(AuditListenerFactory.class));
|
|
||||||
factory.registerLoader(TimerProvider.class, ProviderFactoryLoader.create(TimerProviderFactory.class), Config.getTimerProvider());
|
|
||||||
try {
|
|
||||||
Class identityManagerProvider = Class.forName("org.keycloak.picketlink.IdentityManagerProvider");
|
|
||||||
Class identityManagerProviderFactory = Class.forName("org.keycloak.picketlink.IdentityManagerProviderFactory");
|
|
||||||
factory.registerLoader(identityManagerProvider, ProviderFactoryLoader.create(identityManagerProviderFactory), Config.getIdentityManagerProvider());
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
log.warn("Picketlink libraries not installed for IdentityManagerProviderFactory");
|
|
||||||
}
|
|
||||||
|
|
||||||
factory.registerLoader(AuthenticationProvider.class, ProviderFactoryLoader.create(AuthenticationProviderFactory.class));
|
|
||||||
factory.init();
|
factory.init();
|
||||||
|
|
||||||
return factory;
|
return factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setupScheduledTasks(final ProviderSessionFactory providerSessionFactory, final KeycloakSessionFactory keycloakSessionFactory) {
|
public static void setupScheduledTasks(final ProviderSessionFactory providerSessionFactory) {
|
||||||
ProviderFactory<TimerProvider> timerFactory = providerSessionFactory.getProviderFactory(TimerProvider.class);
|
long interval = Config.scope("scheduled").getLong("interval") * 1000;
|
||||||
if (timerFactory == null) {
|
|
||||||
log.error("Can't setup schedule tasks, no timer provider found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
TimerProvider timer = timerFactory.create(null);
|
|
||||||
timer.schedule(new ScheduledTaskRunner(keycloakSessionFactory, providerSessionFactory, new ClearExpiredAuditEvents()), Config.getAuditExpirationSchedule());
|
|
||||||
timer.schedule(new ScheduledTaskRunner(keycloakSessionFactory, providerSessionFactory, new ClearExpiredUserSessions()), Config.getUserExpirationSchedule());
|
|
||||||
}
|
|
||||||
|
|
||||||
public KeycloakSessionFactory getFactory() {
|
TimerProvider timer = providerSessionFactory.createSession().getProvider(TimerProvider.class);
|
||||||
return factory;
|
timer.schedule(new ScheduledTaskRunner(providerSessionFactory, new ClearExpiredAuditEvents()), interval);
|
||||||
|
timer.schedule(new ScheduledTaskRunner(providerSessionFactory, new ClearExpiredUserSessions()), interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProviderSessionFactory getProviderSessionFactory() {
|
public ProviderSessionFactory getProviderSessionFactory() {
|
||||||
|
@ -215,7 +189,8 @@ public class KeycloakApplication extends Application {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void importRealm(RealmRepresentation rep, String from) {
|
public void importRealm(RealmRepresentation rep, String from) {
|
||||||
KeycloakSession session = factory.createSession();
|
ProviderSession providerSession = providerSessionFactory.createSession();
|
||||||
|
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||||
try {
|
try {
|
||||||
session.getTransaction().begin();
|
session.getTransaction().begin();
|
||||||
RealmManager manager = new RealmManager(session);
|
RealmManager manager = new RealmManager(session);
|
||||||
|
@ -238,7 +213,7 @@ public class KeycloakApplication extends Application {
|
||||||
|
|
||||||
session.getTransaction().commit();
|
session.getTransaction().commit();
|
||||||
} finally {
|
} finally {
|
||||||
session.close();
|
providerSession.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,7 +230,7 @@ public class KeycloakApplication extends Application {
|
||||||
|
|
||||||
if (providers.hasNext()) {
|
if (providers.hasNext()) {
|
||||||
ExportImportProvider exportImport = providers.next();
|
ExportImportProvider exportImport = providers.next();
|
||||||
exportImport.checkExportImport(factory);
|
exportImport.checkExportImport(providerSessionFactory);
|
||||||
} else {
|
} else {
|
||||||
log.warn("No ExportImportProvider found!");
|
log.warn("No ExportImportProvider found!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,14 +10,12 @@ import org.keycloak.freemarker.Theme;
|
||||||
import org.keycloak.freemarker.ThemeLoader;
|
import org.keycloak.freemarker.ThemeLoader;
|
||||||
import org.keycloak.models.AdminRoles;
|
import org.keycloak.models.AdminRoles;
|
||||||
import org.keycloak.models.ApplicationModel;
|
import org.keycloak.models.ApplicationModel;
|
||||||
import org.keycloak.models.Config;
|
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.provider.ProviderSession;
|
import org.keycloak.provider.ProviderSession;
|
||||||
import org.keycloak.services.ForbiddenException;
|
|
||||||
import org.keycloak.services.managers.AppAuthManager;
|
import org.keycloak.services.managers.AppAuthManager;
|
||||||
import org.keycloak.services.managers.ApplicationManager;
|
import org.keycloak.services.managers.ApplicationManager;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
|
@ -280,12 +278,7 @@ public class AdminConsole {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//logger.info("getting resource: " + path + " uri: " + uriInfo.getRequestUri().toString());
|
//logger.info("getting resource: " + path + " uri: " + uriInfo.getRequestUri().toString());
|
||||||
String themeName = realm.getAdminTheme();
|
Theme theme = ThemeLoader.createTheme(realm.getAdminTheme(), Theme.Type.ADMIN);
|
||||||
if (themeName == null || themeName.trim().equals("")) {
|
|
||||||
themeName = Config.getThemeAdmin();
|
|
||||||
}
|
|
||||||
|
|
||||||
Theme theme = ThemeLoader.createTheme(themeName, Theme.Type.ADMIN);
|
|
||||||
InputStream resource = theme.getResourceAsStream(path);
|
InputStream resource = theme.getResourceAsStream(path);
|
||||||
if (resource != null) {
|
if (resource != null) {
|
||||||
String contentType = mimeTypes.getContentType(path);
|
String contentType = mimeTypes.getContentType(path);
|
||||||
|
|
|
@ -13,20 +13,18 @@ public class ScheduledTaskRunner implements Runnable {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(ScheduledTaskRunner.class);
|
private static final Logger logger = Logger.getLogger(ScheduledTaskRunner.class);
|
||||||
|
|
||||||
private final KeycloakSessionFactory keycloakSessionFactory;
|
|
||||||
private final ProviderSessionFactory providerSessionFactory;
|
private final ProviderSessionFactory providerSessionFactory;
|
||||||
private final ScheduledTask task;
|
private final ScheduledTask task;
|
||||||
|
|
||||||
public ScheduledTaskRunner(KeycloakSessionFactory keycloakSessionFactory, ProviderSessionFactory providerSessionFactory, ScheduledTask task) {
|
public ScheduledTaskRunner(ProviderSessionFactory providerSessionFactory, ScheduledTask task) {
|
||||||
this.keycloakSessionFactory = keycloakSessionFactory;
|
|
||||||
this.providerSessionFactory = providerSessionFactory;
|
this.providerSessionFactory = providerSessionFactory;
|
||||||
this.task = task;
|
this.task = task;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
KeycloakSession keycloakSession = keycloakSessionFactory.createSession();
|
|
||||||
ProviderSession providerSession = providerSessionFactory.createSession();
|
ProviderSession providerSession = providerSessionFactory.createSession();
|
||||||
|
KeycloakSession keycloakSession = providerSession.getProvider(KeycloakSession.class);
|
||||||
try {
|
try {
|
||||||
keycloakSession.getTransaction().begin();
|
keycloakSession.getTransaction().begin();
|
||||||
task.run(keycloakSession, providerSession);
|
task.run(keycloakSession, providerSession);
|
||||||
|
@ -38,11 +36,6 @@ public class ScheduledTaskRunner implements Runnable {
|
||||||
|
|
||||||
keycloakSession.getTransaction().rollback();
|
keycloakSession.getTransaction().rollback();
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
|
||||||
keycloakSession.close();
|
|
||||||
} catch (Throwable t) {
|
|
||||||
logger.error("Failed to close KeycloakSession", t);
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
providerSession.close();
|
providerSession.close();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
|
|
@ -0,0 +1,129 @@
|
||||||
|
package org.keycloak.services.util;
|
||||||
|
|
||||||
|
import org.codehaus.jackson.JsonNode;
|
||||||
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.util.StringPropertyReplacer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class JsonConfigProvider implements Config.ConfigProvider {
|
||||||
|
|
||||||
|
private JsonNode config;
|
||||||
|
|
||||||
|
public JsonConfigProvider(JsonNode config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getProvider(String spi) {
|
||||||
|
JsonNode n = getNode(spi, "provider");
|
||||||
|
return n != null ? StringPropertyReplacer.replaceProperties(n.getTextValue()) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Config.Scope scope(String... path) {
|
||||||
|
return new JsonScope(getNode(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonNode getNode(String... path) {
|
||||||
|
JsonNode n = config;
|
||||||
|
for (String p : path) {
|
||||||
|
n = n.get(p);
|
||||||
|
if (n == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class JsonScope implements Config.Scope {
|
||||||
|
|
||||||
|
private JsonNode config;
|
||||||
|
|
||||||
|
public JsonScope(JsonNode config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String get(String key) {
|
||||||
|
return get(key, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String get(String key, String defaultValue) {
|
||||||
|
if (config == null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
JsonNode n = config.get(key);
|
||||||
|
if (n == null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
return StringPropertyReplacer.replaceProperties(n.getTextValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getInt(String key) {
|
||||||
|
return getInt(key, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getInt(String key, Integer defaultValue) {
|
||||||
|
if (config == null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
JsonNode n = config.get(key);
|
||||||
|
if (n == null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
if (n.isTextual()) {
|
||||||
|
return Integer.parseInt(StringPropertyReplacer.replaceProperties(n.getTextValue()));
|
||||||
|
} else {
|
||||||
|
return n.getIntValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getLong(String key) {
|
||||||
|
return getLong(key, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getLong(String key, Long defaultValue) {
|
||||||
|
if (config == null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
JsonNode n = config.get(key);
|
||||||
|
if (n == null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
if (n.isTextual()) {
|
||||||
|
return Long.parseLong(StringPropertyReplacer.replaceProperties(n.getTextValue()));
|
||||||
|
} else {
|
||||||
|
return n.getLongValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean getBoolean(String key) {
|
||||||
|
return getBoolean(key, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean getBoolean(String key, Boolean defaultValue) {
|
||||||
|
if (config == null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
JsonNode n = config.get(key);
|
||||||
|
if (n == null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
if (n.isTextual()) {
|
||||||
|
return Boolean.parseBoolean(StringPropertyReplacer.replaceProperties(n.getTextValue()));
|
||||||
|
} else {
|
||||||
|
return n.getBooleanValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,8 +2,6 @@ package org.keycloak.social;
|
||||||
|
|
||||||
import org.keycloak.util.ProviderLoader;
|
import org.keycloak.util.ProviderLoader;
|
||||||
|
|
||||||
import java.util.ServiceLoader;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -90,10 +90,9 @@ public class SimpleHttpTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetCustomHeader() throws IOException {
|
public void testGetCustomHeader() throws IOException {
|
||||||
JsonNode o = SimpleHttp.doGet("http://localhost:8081/tojson").header("Accept", "application/json").header("Authorization", "bearer dsfsadfsdf").asJson();
|
JsonNode o = SimpleHttp.doGet("http://localhost:8081/tojson").header("Authorization", "bearer dsfsadfsdf").asJson();
|
||||||
JsonNode h = o.get("headers");
|
JsonNode h = o.get("headers");
|
||||||
|
|
||||||
assertEquals("application/json", h.get("Accept"));
|
|
||||||
assertEquals("bearer dsfsadfsdf", h.get("Authorization").getTextValue());
|
assertEquals("bearer dsfsadfsdf", h.get("Authorization").getTextValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ To run the tests with Firefox add `-Dbrowser=firefox` or for Chrome add `-Dbrows
|
||||||
Mongo
|
Mongo
|
||||||
-----
|
-----
|
||||||
|
|
||||||
The testsuite is executed with JPA model implementation with data saved in H2 database by default. To run testsuite with Mongo model, just add property `-Dkeycloak.model=mongo` when executing it.
|
The testsuite is executed with JPA model implementation with data saved in H2 database by default. To run testsuite with Mongo model, just add property `-Dkeycloak.model.provider=mongo` when executing it.
|
||||||
|
|
||||||
Note that this will automatically run embedded Mongo database on localhost/27018 and it will stop it after whole testsuite is finished.
|
Note that this will automatically run embedded Mongo database on localhost/27018 and it will stop it after whole testsuite is finished.
|
||||||
So you don't need to have Mongo installed on your laptop to run mongo execution tests.
|
So you don't need to have Mongo installed on your laptop to run mongo execution tests.
|
||||||
|
@ -52,11 +52,11 @@ For example to use the example themes run the server with:
|
||||||
|
|
||||||
To start a Keycloak server with identity model data persisted in Mongo database instead of default JPA/H2 you can run:
|
To start a Keycloak server with identity model data persisted in Mongo database instead of default JPA/H2 you can run:
|
||||||
|
|
||||||
mvn exec:java -Pkeycloak-server -Dkeycloak.model=mongo
|
mvn exec:java -Pkeycloak-server -Dkeycloak.model.provider=mongo
|
||||||
|
|
||||||
By default it's using database `keycloak` on localhost/27017 and it uses already existing data from this DB (no cleanup of existing data during bootstrap). Assumption is that you already have DB running on localhost/27017 . Use system properties to configure things differently:
|
By default it's using database `keycloak` on localhost/27017 and it uses already existing data from this DB (no cleanup of existing data during bootstrap). Assumption is that you already have DB running on localhost/27017 . Use system properties to configure things differently:
|
||||||
|
|
||||||
mvn exec:java -Pkeycloak-server -Dkeycloak.model=mongo -Dkeycloak.mongo.host=localhost -Dkeycloak.mongo.port=27017 -Dkeycloak.mongo.db=keycloak -Dkeycloak.mongo.clearCollectionsOnStartup=false
|
mvn exec:java -Pkeycloak-server -Dkeycloak.model.provider=mongo -Dkeycloak.model.mongo.host=localhost -Dkeycloak.model.mongo.port=27017 -Dkeycloak.model.mongo.db=keycloak -Dkeycloak.model.mongo.clearOnStartup=false
|
||||||
|
|
||||||
TOTP codes
|
TOTP codes
|
||||||
----------
|
----------
|
||||||
|
|
|
@ -430,10 +430,10 @@
|
||||||
</activation>
|
</activation>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<keycloak.mongo.host>localhost</keycloak.mongo.host>
|
<keycloak.model.mongo.host>localhost</keycloak.model.mongo.host>
|
||||||
<keycloak.mongo.port>27018</keycloak.mongo.port>
|
<keycloak.model.mongo.port>27018</keycloak.model.mongo.port>
|
||||||
<keycloak.mongo.db>keycloak</keycloak.mongo.db>
|
<keycloak.model.mongo.db>keycloak</keycloak.model.mongo.db>
|
||||||
<keycloak.mongo.clearOnStartup>true</keycloak.mongo.clearOnStartup>
|
<keycloak.model.mongo.clearOnStartup>true</keycloak.model.mongo.clearOnStartup>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -452,16 +452,17 @@
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<systemPropertyVariables>
|
<systemPropertyVariables>
|
||||||
<keycloak.mongo.host>${keycloak.mongo.host}</keycloak.mongo.host>
|
<keycloak.model.provider>mongo</keycloak.model.provider>
|
||||||
<keycloak.mongo.port>${keycloak.mongo.port}</keycloak.mongo.port>
|
<keycloak.model.mongo.host>${keycloak.model.mongo.host}</keycloak.model.mongo.host>
|
||||||
<keycloak.mongo.db>${keycloak.mongo.db}</keycloak.mongo.db>
|
<keycloak.model.mongo.port>${keycloak.model.mongo.port}</keycloak.model.mongo.port>
|
||||||
|
<keycloak.model.mongo.db>${keycloak.model.mongo.db}</keycloak.model.mongo.db>
|
||||||
|
|
||||||
<keycloak.audit>mongo</keycloak.audit>
|
<keycloak.audit.provider>mongo</keycloak.audit.provider>
|
||||||
<keycloak.audit.mongo.host>${keycloak.mongo.host}</keycloak.audit.mongo.host>
|
<keycloak.audit.mongo.host>${keycloak.model.mongo.host}</keycloak.audit.mongo.host>
|
||||||
<keycloak.audit.mongo.port>${keycloak.mongo.port}</keycloak.audit.mongo.port>
|
<keycloak.audit.mongo.port>${keycloak.model.mongo.port}</keycloak.audit.mongo.port>
|
||||||
<keycloak.audit.mongo.db>${keycloak.mongo.db}</keycloak.audit.mongo.db>
|
<keycloak.audit.mongo.db>${keycloak.model.mongo.db}</keycloak.audit.mongo.db>
|
||||||
|
|
||||||
<keycloak.mongo.clearOnStartup>${keycloak.mongo.clearOnStartup}</keycloak.mongo.clearOnStartup>
|
<keycloak.model.mongo.clearOnStartup>${keycloak.model.mongo.clearOnStartup}</keycloak.model.mongo.clearOnStartup>
|
||||||
</systemPropertyVariables>
|
</systemPropertyVariables>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
|
@ -486,7 +487,7 @@
|
||||||
<goal>start</goal>
|
<goal>start</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<port>${keycloak.mongo.port}</port>
|
<port>${keycloak.model.mongo.port}</port>
|
||||||
<logging>file</logging>
|
<logging>file</logging>
|
||||||
<logFile>${project.build.directory}/mongodb.log</logFile>
|
<logFile>${project.build.directory}/mongodb.log</logFile>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
|
@ -30,18 +30,16 @@ import io.undertow.servlet.api.FilterInfo;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
|
import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
|
||||||
import org.jboss.resteasy.spi.ResteasyDeployment;
|
import org.jboss.resteasy.spi.ResteasyDeployment;
|
||||||
import org.keycloak.models.Config;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
import org.keycloak.provider.ProviderSessionFactory;
|
import org.keycloak.provider.ProviderSessionFactory;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.services.filters.ClientConnectionFilter;
|
import org.keycloak.services.filters.ClientConnectionFilter;
|
||||||
import org.keycloak.services.filters.KeycloakSessionServletFilter;
|
import org.keycloak.services.filters.KeycloakSessionServletFilter;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.services.resources.KeycloakApplication;
|
import org.keycloak.services.resources.KeycloakApplication;
|
||||||
import org.keycloak.theme.DefaultKeycloakThemeProvider;
|
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
import javax.servlet.DispatcherType;
|
import javax.servlet.DispatcherType;
|
||||||
|
@ -129,9 +127,8 @@ public class KeycloakServer {
|
||||||
throw new RuntimeException("Invalid resources directory");
|
throw new RuntimeException("Invalid resources directory");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.getThemeDir() == null) {
|
if (!System.getProperties().containsKey("keycloak.theme.dir")) {
|
||||||
System.setProperty(DefaultKeycloakThemeProvider.class.getName() + ".disabled", "");
|
System.setProperty("keycloak.theme.dir", file(dir.getAbsolutePath(), "forms", "common-themes", "src", "main", "resources", "theme").getAbsolutePath());
|
||||||
Config.setThemeDir(file(dir.getAbsolutePath(), "forms", "common-themes", "src", "main", "resources", "theme").getAbsolutePath());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config.setResourcesHome(dir.getAbsolutePath());
|
config.setResourcesHome(dir.getAbsolutePath());
|
||||||
|
@ -162,8 +159,6 @@ public class KeycloakServer {
|
||||||
|
|
||||||
private KeycloakServerConfig config;
|
private KeycloakServerConfig config;
|
||||||
|
|
||||||
private KeycloakSessionFactory factory;
|
|
||||||
|
|
||||||
private ProviderSessionFactory providerSessionFactory;
|
private ProviderSessionFactory providerSessionFactory;
|
||||||
|
|
||||||
private UndertowJaxrsServer server;
|
private UndertowJaxrsServer server;
|
||||||
|
@ -176,10 +171,6 @@ public class KeycloakServer {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeycloakSessionFactory getKeycloakSessionFactory() {
|
|
||||||
return factory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProviderSessionFactory getProviderSessionFactory() {
|
public ProviderSessionFactory getProviderSessionFactory() {
|
||||||
return providerSessionFactory;
|
return providerSessionFactory;
|
||||||
}
|
}
|
||||||
|
@ -194,7 +185,8 @@ public class KeycloakServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void importRealm(RealmRepresentation rep) {
|
public void importRealm(RealmRepresentation rep) {
|
||||||
KeycloakSession session = factory.createSession();
|
ProviderSession providerSession = providerSessionFactory.createSession();
|
||||||
|
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||||
session.getTransaction().begin();
|
session.getTransaction().begin();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -217,12 +209,13 @@ public class KeycloakServer {
|
||||||
|
|
||||||
session.getTransaction().commit();
|
session.getTransaction().commit();
|
||||||
} finally {
|
} finally {
|
||||||
session.close();
|
providerSession.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setupDevConfig() {
|
protected void setupDevConfig() {
|
||||||
KeycloakSession session = factory.createSession();
|
ProviderSession providerSession = providerSessionFactory.createSession();
|
||||||
|
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||||
session.getTransaction().begin();
|
session.getTransaction().begin();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -234,7 +227,7 @@ public class KeycloakServer {
|
||||||
|
|
||||||
session.getTransaction().commit();
|
session.getTransaction().commit();
|
||||||
} finally {
|
} finally {
|
||||||
session.close();
|
providerSession.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,7 +259,6 @@ public class KeycloakServer {
|
||||||
|
|
||||||
server.deploy(di);
|
server.deploy(di);
|
||||||
|
|
||||||
factory = ((KeycloakApplication) deployment.getApplication()).getFactory();
|
|
||||||
providerSessionFactory = ((KeycloakApplication) deployment.getApplication()).getProviderSessionFactory();
|
providerSessionFactory = ((KeycloakApplication) deployment.getApplication()).getProviderSessionFactory();
|
||||||
|
|
||||||
setupDevConfig();
|
setupDevConfig();
|
||||||
|
@ -289,7 +281,6 @@ public class KeycloakServer {
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
providerSessionFactory.close();
|
providerSessionFactory.close();
|
||||||
factory.close();
|
|
||||||
server.stop();
|
server.stop();
|
||||||
|
|
||||||
info("Stopped Keycloak");
|
info("Stopped Keycloak");
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"admin": {
|
||||||
|
"realm": "keycloak-admin"
|
||||||
|
},
|
||||||
|
|
||||||
|
"audit": {
|
||||||
|
"provider": "${keycloak.audit.provider:jpa}"
|
||||||
|
},
|
||||||
|
|
||||||
|
"model": {
|
||||||
|
"provider": "${keycloak.model.provider:jpa}"
|
||||||
|
},
|
||||||
|
|
||||||
|
"timer": {
|
||||||
|
"provider": "basic"
|
||||||
|
},
|
||||||
|
|
||||||
|
"theme": {
|
||||||
|
"default": "keycloak",
|
||||||
|
"dir": "${keycloak.theme.dir}"
|
||||||
|
},
|
||||||
|
|
||||||
|
"scheduled": {
|
||||||
|
"interval": 900
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,10 +4,10 @@ import org.hamcrest.CoreMatchers;
|
||||||
import org.hamcrest.Description;
|
import org.hamcrest.Description;
|
||||||
import org.hamcrest.Matcher;
|
import org.hamcrest.Matcher;
|
||||||
import org.hamcrest.TypeSafeMatcher;
|
import org.hamcrest.TypeSafeMatcher;
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.rules.TestRule;
|
import org.junit.rules.TestRule;
|
||||||
import org.junit.runners.model.Statement;
|
import org.junit.runners.model.Statement;
|
||||||
|
import org.keycloak.Config;
|
||||||
import org.keycloak.audit.AuditListener;
|
import org.keycloak.audit.AuditListener;
|
||||||
import org.keycloak.audit.AuditListenerFactory;
|
import org.keycloak.audit.AuditListenerFactory;
|
||||||
import org.keycloak.audit.Details;
|
import org.keycloak.audit.Details;
|
||||||
|
@ -58,11 +58,6 @@ public class AssertEvents implements TestRule, AuditListenerFactory {
|
||||||
return "assert-events";
|
return "assert-events";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean lazyLoad() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Statement apply(final Statement base, org.junit.runner.Description description) {
|
public Statement apply(final Statement base, org.junit.runner.Description description) {
|
||||||
return new Statement() {
|
return new Statement() {
|
||||||
|
@ -194,7 +189,7 @@ public class AssertEvents implements TestRule, AuditListenerFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init(Config.Scope config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -22,18 +22,14 @@
|
||||||
package org.keycloak.testsuite.account;
|
package org.keycloak.testsuite.account;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.AfterClass;
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.audit.Details;
|
import org.keycloak.audit.Details;
|
||||||
import org.keycloak.audit.Event;
|
import org.keycloak.audit.Event;
|
||||||
import org.keycloak.audit.jpa.JpaAuditProviderFactory;
|
|
||||||
import org.keycloak.models.ApplicationModel;
|
import org.keycloak.models.ApplicationModel;
|
||||||
import org.keycloak.models.Config;
|
|
||||||
import org.keycloak.models.PasswordPolicy;
|
import org.keycloak.models.PasswordPolicy;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserCredentialModel;
|
import org.keycloak.models.UserCredentialModel;
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.adapters.action.SessionStats;
|
import org.keycloak.representations.adapters.action.SessionStats;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
@ -171,11 +172,11 @@ public class AdapterTest {
|
||||||
System.out.println(pageSource);
|
System.out.println(pageSource);
|
||||||
Assert.assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
|
Assert.assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
|
||||||
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
ProviderSession providerSession = keycloakRule.startSession();
|
||||||
RealmModel realm = session.getRealmByName("demo");
|
RealmModel realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
|
||||||
int originalIdle = realm.getSsoSessionIdleTimeout();
|
int originalIdle = realm.getSsoSessionIdleTimeout();
|
||||||
realm.setSsoSessionIdleTimeout(1);
|
realm.setSsoSessionIdleTimeout(1);
|
||||||
keycloakRule.stopSession(session, true);
|
keycloakRule.stopSession(providerSession, true);
|
||||||
|
|
||||||
Thread.sleep(2000);
|
Thread.sleep(2000);
|
||||||
|
|
||||||
|
@ -184,10 +185,10 @@ public class AdapterTest {
|
||||||
driver.navigate().to("http://localhost:8081/product-portal");
|
driver.navigate().to("http://localhost:8081/product-portal");
|
||||||
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
|
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
providerSession = keycloakRule.startSession();
|
||||||
realm = session.getRealmByName("demo");
|
realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
|
||||||
realm.setSsoSessionIdleTimeout(originalIdle);
|
realm.setSsoSessionIdleTimeout(originalIdle);
|
||||||
keycloakRule.stopSession(session, true);
|
keycloakRule.stopSession(providerSession, true);
|
||||||
}
|
}
|
||||||
@Test
|
@Test
|
||||||
public void testLoginSSOMax() throws Exception {
|
public void testLoginSSOMax() throws Exception {
|
||||||
|
@ -202,11 +203,11 @@ public class AdapterTest {
|
||||||
System.out.println(pageSource);
|
System.out.println(pageSource);
|
||||||
Assert.assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
|
Assert.assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
|
||||||
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
ProviderSession providerSession = keycloakRule.startSession();
|
||||||
RealmModel realm = session.getRealmByName("demo");
|
RealmModel realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
|
||||||
int original = realm.getSsoSessionMaxLifespan();
|
int original = realm.getSsoSessionMaxLifespan();
|
||||||
realm.setSsoSessionMaxLifespan(1);
|
realm.setSsoSessionMaxLifespan(1);
|
||||||
keycloakRule.stopSession(session, true);
|
keycloakRule.stopSession(providerSession, true);
|
||||||
|
|
||||||
Thread.sleep(2000);
|
Thread.sleep(2000);
|
||||||
|
|
||||||
|
@ -215,9 +216,9 @@ public class AdapterTest {
|
||||||
driver.navigate().to("http://localhost:8081/product-portal");
|
driver.navigate().to("http://localhost:8081/product-portal");
|
||||||
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
|
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
providerSession = keycloakRule.startSession();
|
||||||
realm = session.getRealmByName("demo");
|
realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
|
||||||
realm.setSsoSessionMaxLifespan(original);
|
realm.setSsoSessionMaxLifespan(original);
|
||||||
keycloakRule.stopSession(session, true);
|
keycloakRule.stopSession(providerSession, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,14 +29,12 @@ import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.audit.Details;
|
import org.keycloak.audit.Details;
|
||||||
import org.keycloak.audit.Errors;
|
import org.keycloak.audit.Errors;
|
||||||
import org.keycloak.audit.Event;
|
import org.keycloak.audit.Event;
|
||||||
import org.keycloak.models.Config;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
import org.keycloak.provider.ProviderSession;
|
import org.keycloak.provider.ProviderSession;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.RefreshToken;
|
import org.keycloak.representations.RefreshToken;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
|
||||||
import org.keycloak.testsuite.AssertEvents;
|
import org.keycloak.testsuite.AssertEvents;
|
||||||
import org.keycloak.testsuite.OAuthClient;
|
import org.keycloak.testsuite.OAuthClient;
|
||||||
import org.keycloak.testsuite.OAuthClient.AccessTokenResponse;
|
import org.keycloak.testsuite.OAuthClient.AccessTokenResponse;
|
||||||
|
@ -47,7 +45,11 @@ import org.keycloak.testsuite.rule.WebRule;
|
||||||
import org.keycloak.util.Time;
|
import org.keycloak.util.Time;
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.allOf;
|
||||||
|
import static org.hamcrest.Matchers.greaterThan;
|
||||||
|
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||||
|
import static org.hamcrest.Matchers.lessThan;
|
||||||
|
import static org.hamcrest.Matchers.lessThanOrEqualTo;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
@ -181,8 +183,8 @@ public class RefreshTokenTest {
|
||||||
|
|
||||||
String refreshId = oauth.verifyRefreshToken(tokenResponse.getRefreshToken()).getId();
|
String refreshId = oauth.verifyRefreshToken(tokenResponse.getRefreshToken()).getId();
|
||||||
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
ProviderSession session = keycloakRule.startSession();
|
||||||
RealmModel realm = session.getRealmByName("test");
|
RealmModel realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
|
||||||
UserSessionModel userSession = realm.getUserSession(sessionId);
|
UserSessionModel userSession = realm.getUserSession(sessionId);
|
||||||
int last = userSession.getLastSessionRefresh();
|
int last = userSession.getLastSessionRefresh();
|
||||||
keycloakRule.stopSession(session, false);
|
keycloakRule.stopSession(session, false);
|
||||||
|
@ -197,7 +199,7 @@ public class RefreshTokenTest {
|
||||||
Assert.assertEquals(200, tokenResponse.getStatusCode());
|
Assert.assertEquals(200, tokenResponse.getStatusCode());
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
session = keycloakRule.startSession();
|
||||||
realm = session.getRealmByName("test");
|
realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
|
||||||
userSession = realm.getUserSession(sessionId);
|
userSession = realm.getUserSession(sessionId);
|
||||||
int next = userSession.getLastSessionRefresh();
|
int next = userSession.getLastSessionRefresh();
|
||||||
keycloakRule.stopSession(session, false);
|
keycloakRule.stopSession(session, false);
|
||||||
|
@ -208,7 +210,7 @@ public class RefreshTokenTest {
|
||||||
|
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
session = keycloakRule.startSession();
|
||||||
realm = session.getRealmByName("test");
|
realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
|
||||||
int lastAccessTokenLifespan = realm.getAccessTokenLifespan();
|
int lastAccessTokenLifespan = realm.getAccessTokenLifespan();
|
||||||
realm.setAccessTokenLifespan(100000);
|
realm.setAccessTokenLifespan(100000);
|
||||||
keycloakRule.stopSession(session, true);
|
keycloakRule.stopSession(session, true);
|
||||||
|
@ -217,7 +219,7 @@ public class RefreshTokenTest {
|
||||||
tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "password");
|
tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "password");
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
session = keycloakRule.startSession();
|
||||||
realm = session.getRealmByName("test");
|
realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
|
||||||
userSession = realm.getUserSession(sessionId);
|
userSession = realm.getUserSession(sessionId);
|
||||||
next = userSession.getLastSessionRefresh();
|
next = userSession.getLastSessionRefresh();
|
||||||
keycloakRule.stopSession(session, false);
|
keycloakRule.stopSession(session, false);
|
||||||
|
@ -226,7 +228,7 @@ public class RefreshTokenTest {
|
||||||
Assert.assertThat(next, allOf(greaterThan(last), lessThan(last + 6)));
|
Assert.assertThat(next, allOf(greaterThan(last), lessThan(last + 6)));
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
session = keycloakRule.startSession();
|
||||||
realm = session.getRealmByName("test");
|
realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
|
||||||
int originalIdle = realm.getSsoSessionIdleTimeout();
|
int originalIdle = realm.getSsoSessionIdleTimeout();
|
||||||
realm.setSsoSessionIdleTimeout(1);
|
realm.setSsoSessionIdleTimeout(1);
|
||||||
keycloakRule.stopSession(session, true);
|
keycloakRule.stopSession(session, true);
|
||||||
|
@ -243,7 +245,7 @@ public class RefreshTokenTest {
|
||||||
events.expectRefresh(refreshId, sessionId).error(Errors.INVALID_TOKEN);
|
events.expectRefresh(refreshId, sessionId).error(Errors.INVALID_TOKEN);
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
session = keycloakRule.startSession();
|
||||||
realm = session.getRealmByName("test");
|
realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
|
||||||
realm.setSsoSessionIdleTimeout(originalIdle);
|
realm.setSsoSessionIdleTimeout(originalIdle);
|
||||||
realm.setAccessTokenLifespan(lastAccessTokenLifespan);
|
realm.setAccessTokenLifespan(lastAccessTokenLifespan);
|
||||||
keycloakRule.stopSession(session, true);
|
keycloakRule.stopSession(session, true);
|
||||||
|
@ -266,8 +268,8 @@ public class RefreshTokenTest {
|
||||||
|
|
||||||
String refreshId = oauth.verifyRefreshToken(tokenResponse.getRefreshToken()).getId();
|
String refreshId = oauth.verifyRefreshToken(tokenResponse.getRefreshToken()).getId();
|
||||||
|
|
||||||
KeycloakSession session = keycloakRule.startSession();
|
ProviderSession session = keycloakRule.startSession();
|
||||||
RealmModel realm = session.getRealmByName("test");
|
RealmModel realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
|
||||||
int maxLifespan = realm.getSsoSessionMaxLifespan();
|
int maxLifespan = realm.getSsoSessionMaxLifespan();
|
||||||
realm.setSsoSessionMaxLifespan(1);
|
realm.setSsoSessionMaxLifespan(1);
|
||||||
keycloakRule.stopSession(session, true);
|
keycloakRule.stopSession(session, true);
|
||||||
|
@ -281,7 +283,7 @@ public class RefreshTokenTest {
|
||||||
assertNull(tokenResponse.getRefreshToken());
|
assertNull(tokenResponse.getRefreshToken());
|
||||||
|
|
||||||
session = keycloakRule.startSession();
|
session = keycloakRule.startSession();
|
||||||
realm = session.getRealmByName("test");
|
realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
|
||||||
realm.setSsoSessionMaxLifespan(maxLifespan);
|
realm.setSsoSessionMaxLifespan(maxLifespan);
|
||||||
keycloakRule.stopSession(session, true);
|
keycloakRule.stopSession(session, true);
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,11 @@ import io.undertow.servlet.api.SecurityConstraint;
|
||||||
import io.undertow.servlet.api.ServletInfo;
|
import io.undertow.servlet.api.ServletInfo;
|
||||||
import io.undertow.servlet.api.WebResourceCollection;
|
import io.undertow.servlet.api.WebResourceCollection;
|
||||||
import org.junit.rules.ExternalResource;
|
import org.junit.rules.ExternalResource;
|
||||||
import org.keycloak.models.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
import org.keycloak.services.managers.ModelToRepresentation;
|
import org.keycloak.services.managers.ModelToRepresentation;
|
||||||
|
@ -33,31 +34,33 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
|
||||||
server = new KeycloakServer();
|
server = new KeycloakServer();
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
|
|
||||||
setupKeycloak();
|
setupKeycloak();
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserRepresentation getUser(String realm, String name) {
|
public UserRepresentation getUser(String realm, String name) {
|
||||||
KeycloakSession session = server.getKeycloakSessionFactory().createSession();
|
ProviderSession providerSession = server.getProviderSessionFactory().createSession();
|
||||||
|
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||||
try {
|
try {
|
||||||
UserModel user = session.getRealmByName(realm).getUser(name);
|
UserModel user = session.getRealmByName(realm).getUser(name);
|
||||||
return user != null ? ModelToRepresentation.toRepresentation(user) : null;
|
return user != null ? ModelToRepresentation.toRepresentation(user) : null;
|
||||||
} finally {
|
} finally {
|
||||||
session.close();
|
providerSession.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserRepresentation getUserById(String realm, String id) {
|
public UserRepresentation getUserById(String realm, String id) {
|
||||||
KeycloakSession session = server.getKeycloakSessionFactory().createSession();
|
ProviderSession providerSession = server.getProviderSessionFactory().createSession();
|
||||||
|
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||||
try {
|
try {
|
||||||
return ModelToRepresentation.toRepresentation(session.getRealmByName(realm).getUserById(id));
|
return ModelToRepresentation.toRepresentation(session.getRealmByName(realm).getUserById(id));
|
||||||
} finally {
|
} finally {
|
||||||
session.close();
|
providerSession.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setupKeycloak() {
|
protected void setupKeycloak() {
|
||||||
KeycloakSession session = server.getKeycloakSessionFactory().createSession();
|
ProviderSession providerSession = server.getProviderSessionFactory().createSession();
|
||||||
|
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||||
session.getTransaction().begin();
|
session.getTransaction().begin();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -69,9 +72,8 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
|
||||||
|
|
||||||
session.getTransaction().commit();
|
session.getTransaction().commit();
|
||||||
} finally {
|
} finally {
|
||||||
session.close();
|
providerSession.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void configure(RealmManager manager, RealmModel adminRealm) {
|
protected void configure(RealmManager manager, RealmModel adminRealm) {
|
||||||
|
@ -134,15 +136,16 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
|
||||||
return JsonSerialization.readValue(bytes, RealmRepresentation.class);
|
return JsonSerialization.readValue(bytes, RealmRepresentation.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeycloakSession startSession() {
|
public ProviderSession startSession() {
|
||||||
KeycloakSession session = server.getKeycloakSessionFactory().createSession();
|
ProviderSession providerSession = server.getProviderSessionFactory().createSession();
|
||||||
|
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||||
session.getTransaction().begin();
|
session.getTransaction().begin();
|
||||||
return session;
|
return providerSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopSession(KeycloakSession session, boolean commit) {
|
public void stopSession(ProviderSession session, boolean commit) {
|
||||||
if (commit) {
|
if (commit) {
|
||||||
session.getTransaction().commit();
|
session.getProvider(KeycloakSession.class).getTransaction().commit();
|
||||||
}
|
}
|
||||||
session.close();
|
session.close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.rule;
|
package org.keycloak.testsuite.rule;
|
||||||
|
|
||||||
import org.keycloak.models.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
|
@ -61,8 +61,8 @@ public class KeycloakRule extends AbstractKeycloakRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void configure(KeycloakSetup configurer) {
|
public void configure(KeycloakSetup configurer) {
|
||||||
KeycloakSession session = server.getKeycloakSessionFactory().createSession();
|
|
||||||
ProviderSession providerSession = server.getProviderSessionFactory().createSession();
|
ProviderSession providerSession = server.getProviderSessionFactory().createSession();
|
||||||
|
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
|
||||||
session.getTransaction().begin();
|
session.getTransaction().begin();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -77,17 +77,16 @@ public class KeycloakRule extends AbstractKeycloakRule {
|
||||||
session.getTransaction().commit();
|
session.getTransaction().commit();
|
||||||
} finally {
|
} finally {
|
||||||
providerSession.close();
|
providerSession.close();
|
||||||
session.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeUserSession(String sessionId) {
|
public void removeUserSession(String sessionId) {
|
||||||
KeycloakSession keycloakSession = startSession();
|
ProviderSession providerSession = startSession();
|
||||||
RealmModel realm = keycloakSession.getRealm("test");
|
RealmModel realm = providerSession.getProvider(KeycloakSession.class).getRealm("test");
|
||||||
UserSessionModel session = realm.getUserSession(sessionId);
|
UserSessionModel session = realm.getUserSession(sessionId);
|
||||||
assertNotNull(session);
|
assertNotNull(session);
|
||||||
realm.removeUserSession(session);
|
realm.removeUserSession(session);
|
||||||
stopSession(keycloakSession, true);
|
stopSession(providerSession, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract static class KeycloakSetup {
|
public abstract static class KeycloakSetup {
|
||||||
|
|
|
@ -6,6 +6,8 @@ import org.apache.jmeter.samplers.SampleResult;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.models.KeycloakTransaction;
|
import org.keycloak.models.KeycloakTransaction;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
import org.keycloak.provider.ProviderSessionFactory;
|
||||||
import org.keycloak.services.resources.KeycloakApplication;
|
import org.keycloak.services.resources.KeycloakApplication;
|
||||||
|
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
@ -18,17 +20,17 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
public class BaseJMeterPerformanceTest extends AbstractJavaSamplerClient {
|
public class BaseJMeterPerformanceTest extends AbstractJavaSamplerClient {
|
||||||
|
|
||||||
|
|
||||||
private static FutureTask<KeycloakSessionFactory> factoryProvider = new FutureTask<KeycloakSessionFactory>(new Callable() {
|
private static FutureTask<ProviderSessionFactory> factoryProvider = new FutureTask<ProviderSessionFactory>(new Callable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeycloakSessionFactory call() throws Exception {
|
public ProviderSessionFactory call() throws Exception {
|
||||||
return KeycloakApplication.createSessionFactory();
|
return KeycloakApplication.createProviderSessionFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
private static AtomicInteger counter = new AtomicInteger();
|
private static AtomicInteger counter = new AtomicInteger();
|
||||||
|
|
||||||
private KeycloakSessionFactory factory;
|
private ProviderSessionFactory factory;
|
||||||
// private KeycloakSession identitySession;
|
// private KeycloakSession identitySession;
|
||||||
private Worker worker;
|
private Worker worker;
|
||||||
private boolean setupSuccess = false;
|
private boolean setupSuccess = false;
|
||||||
|
@ -42,7 +44,8 @@ public class BaseJMeterPerformanceTest extends AbstractJavaSamplerClient {
|
||||||
worker = getWorker();
|
worker = getWorker();
|
||||||
|
|
||||||
factory = getFactory();
|
factory = getFactory();
|
||||||
KeycloakSession identitySession = factory.createSession();
|
ProviderSession providerSession = factory.createSession();
|
||||||
|
KeycloakSession identitySession = providerSession.getProvider(KeycloakSession.class);
|
||||||
KeycloakTransaction transaction = identitySession.getTransaction();
|
KeycloakTransaction transaction = identitySession.getTransaction();
|
||||||
transaction.begin();
|
transaction.begin();
|
||||||
|
|
||||||
|
@ -56,11 +59,11 @@ public class BaseJMeterPerformanceTest extends AbstractJavaSamplerClient {
|
||||||
} else {
|
} else {
|
||||||
transaction.rollback();
|
transaction.rollback();
|
||||||
}
|
}
|
||||||
identitySession.close();
|
providerSession.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static KeycloakSessionFactory getFactory() {
|
private static ProviderSessionFactory getFactory() {
|
||||||
factoryProvider.run();
|
factoryProvider.run();
|
||||||
try {
|
try {
|
||||||
return factoryProvider.get();
|
return factoryProvider.get();
|
||||||
|
@ -98,7 +101,8 @@ public class BaseJMeterPerformanceTest extends AbstractJavaSamplerClient {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
KeycloakSession identitySession = factory.createSession();
|
ProviderSession providerSession = factory.createSession();
|
||||||
|
KeycloakSession identitySession = providerSession.getProvider(KeycloakSession.class);
|
||||||
KeycloakTransaction transaction = identitySession.getTransaction();
|
KeycloakTransaction transaction = identitySession.getTransaction();
|
||||||
try {
|
try {
|
||||||
transaction.begin();
|
transaction.begin();
|
||||||
|
@ -114,7 +118,7 @@ public class BaseJMeterPerformanceTest extends AbstractJavaSamplerClient {
|
||||||
} finally {
|
} finally {
|
||||||
result.sampleEnd();
|
result.sampleEnd();
|
||||||
result.setSuccessful(true);
|
result.setSuccessful(true);
|
||||||
identitySession.close();
|
providerSession.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -8,11 +8,11 @@ keycloak.jpa.hbm2ddl.auto=create
|
||||||
|
|
||||||
|
|
||||||
## Configure MongoDB (Useful just when keycloak.sessionFactory=mongo)
|
## Configure MongoDB (Useful just when keycloak.sessionFactory=mongo)
|
||||||
keycloak.mongodb.host=localhost
|
keycloak.model.mongo.host=localhost
|
||||||
keycloak.mongodb.port=27017
|
keycloak.model.mongo.port=27017
|
||||||
keycloak.mongodb.databaseName=keycloakPerfTest
|
keycloak.model.mongo.databaseName=keycloakPerfTest
|
||||||
# Should be DB dropped at startup of the test?
|
# Should be DB dropped at startup of the test?
|
||||||
keycloak.mongodb.dropDatabaseOnStartup=true
|
keycloak.model.mongo.dropDatabaseOnStartup=true
|
||||||
|
|
||||||
|
|
||||||
## Specify Keycloak worker class
|
## Specify Keycloak worker class
|
||||||
|
|
|
@ -7,6 +7,6 @@ import org.keycloak.provider.Provider;
|
||||||
*/
|
*/
|
||||||
public interface TimerProvider extends Provider {
|
public interface TimerProvider extends Provider {
|
||||||
|
|
||||||
public void schedule(Runnable runnable, String config);
|
public void schedule(Runnable runnable, long interval);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
25
timer/api/src/main/java/org/keycloak/timer/TimerSpi.java
Normal file
25
timer/api/src/main/java/org/keycloak/timer/TimerSpi.java
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package org.keycloak.timer;
|
||||||
|
|
||||||
|
import org.keycloak.provider.Provider;
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
import org.keycloak.provider.Spi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class TimerSpi implements Spi {
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "timer";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Provider> getProviderClass() {
|
||||||
|
return TimerProvider.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||||
|
return TimerProviderFactory.class;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
org.keycloak.timer.TimerSpi
|
|
@ -18,9 +18,7 @@ public class BasicTimerProvider implements TimerProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void schedule(final Runnable runnable, String config) {
|
public void schedule(final Runnable runnable, final long interval) {
|
||||||
long interval = Long.parseLong(config);
|
|
||||||
|
|
||||||
TimerTask task = new TimerTask() {
|
TimerTask task = new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.keycloak.timer.basic;
|
package org.keycloak.timer.basic;
|
||||||
|
|
||||||
|
import org.keycloak.Config;
|
||||||
import org.keycloak.provider.ProviderSession;
|
import org.keycloak.provider.ProviderSession;
|
||||||
import org.keycloak.timer.TimerProvider;
|
import org.keycloak.timer.TimerProvider;
|
||||||
import org.keycloak.timer.TimerProviderFactory;
|
import org.keycloak.timer.TimerProviderFactory;
|
||||||
|
@ -19,7 +20,7 @@ public class BasicTimerProviderFactory implements TimerProviderFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init(Config.Scope config) {
|
||||||
timer = new Timer();
|
timer = new Timer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,8 +35,4 @@ public class BasicTimerProviderFactory implements TimerProviderFactory {
|
||||||
return "basic";
|
return "basic";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean lazyLoad() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue