Refactoring of Authentication SPI and Picketlink to use ProviderSessions

Refactoring of ProviderSessionFactory to support dependencies between components
Calling lifecycle methods
Removing KeycloakRegistry
This commit is contained in:
mposolda 2014-04-08 17:13:30 +02:00
parent 0d00db281a
commit 5aefe52ccc
74 changed files with 690 additions and 315 deletions

View file

@ -3,6 +3,8 @@ package org.keycloak.audit.log;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
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.ProviderSessionFactory;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@ -14,7 +16,7 @@ public class JBossLoggingAuditListenerFactory implements AuditListenerFactory {
private static final Logger logger = Logger.getLogger("org.keycloak.audit"); private static final Logger logger = Logger.getLogger("org.keycloak.audit");
@Override @Override
public AuditListener create() { public AuditListener create(ProviderSession providerSession) {
return new JBossLoggingAuditListener(logger); return new JBossLoggingAuditListener(logger);
} }

View file

@ -2,6 +2,8 @@ package org.keycloak.audit.jpa;
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.ProviderSessionFactory;
import javax.persistence.EntityManagerFactory; import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence; import javax.persistence.Persistence;
@ -15,7 +17,7 @@ public class JpaAuditProviderFactory implements AuditProviderFactory {
private EntityManagerFactory emf; private EntityManagerFactory emf;
@Override @Override
public AuditProvider create() { public AuditProvider create(ProviderSession providerSession) {
return new JpaAuditProvider(emf.createEntityManager()); return new JpaAuditProvider(emf.createEntityManager());
} }

View file

@ -5,6 +5,8 @@ import com.mongodb.MongoClient;
import com.mongodb.WriteConcern; import com.mongodb.WriteConcern;
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.ProviderSessionFactory;
import java.net.UnknownHostException; import java.net.UnknownHostException;
@ -22,7 +24,7 @@ public class MongoAuditProviderFactory implements AuditProviderFactory {
private DB db; private DB db;
@Override @Override
public AuditProvider create() { public AuditProvider create(ProviderSession providerSession) {
return new MongoAuditProvider(db.getCollection("audit")); return new MongoAuditProvider(db.getCollection("audit"));
} }

View file

@ -27,7 +27,7 @@ public abstract class AbstractAuditProviderTest {
factory = loader.find(getProviderId()); factory = loader.find(getProviderId());
factory.init(); factory.init();
provider = factory.create(); provider = factory.create(null);
} }
protected abstract String getProviderId(); protected abstract String getProviderId();
@ -58,7 +58,7 @@ public abstract class AbstractAuditProviderTest {
provider.onEvent(create("event", "realmId", "clientId", "userId2", "127.0.0.1", "error")); provider.onEvent(create("event", "realmId", "clientId", "userId2", "127.0.0.1", "error"));
provider.close(); provider.close();
provider = factory.create(); provider = factory.create(null);
Assert.assertEquals(5, provider.createQuery().client("clientId").getResultList().size()); Assert.assertEquals(5, provider.createQuery().client("clientId").getResultList().size());
Assert.assertEquals(5, provider.createQuery().realm("realmId").getResultList().size()); Assert.assertEquals(5, provider.createQuery().realm("realmId").getResultList().size());
@ -84,7 +84,7 @@ public abstract class AbstractAuditProviderTest {
provider.onEvent(create(System.currentTimeMillis() - 30000, "event", "realmId2", "clientId", "userId", "127.0.0.1", "error")); provider.onEvent(create(System.currentTimeMillis() - 30000, "event", "realmId2", "clientId", "userId", "127.0.0.1", "error"));
provider.close(); provider.close();
provider = factory.create(); provider = factory.create(null);
provider.clear("realmId"); provider.clear("realmId");
@ -100,7 +100,7 @@ public abstract class AbstractAuditProviderTest {
provider.onEvent(create(System.currentTimeMillis() - 30000, "event", "realmId2", "clientId", "userId", "127.0.0.1", "error")); provider.onEvent(create(System.currentTimeMillis() - 30000, "event", "realmId2", "clientId", "userId", "127.0.0.1", "error"));
provider.close(); provider.close();
provider = factory.create(); provider = factory.create(null);
provider.clear("realmId", System.currentTimeMillis() - 10000); provider.clear("realmId", System.currentTimeMillis() - 10000);

View file

@ -4,11 +4,12 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.provider.Provider;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
public interface AuthenticationProvider { public interface AuthenticationProvider extends Provider {
String getName(); String getName();

View file

@ -0,0 +1,9 @@
package org.keycloak.authentication;
import org.keycloak.provider.ProviderFactory;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public interface AuthenticationProviderFactory extends ProviderFactory<AuthenticationProvider> {
}

View file

@ -10,6 +10,7 @@ import org.keycloak.models.AuthenticationLinkModel;
import org.keycloak.models.AuthenticationProviderModel; import org.keycloak.models.AuthenticationProviderModel;
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.util.ProviderLoader; import org.keycloak.util.ProviderLoader;
/** /**
@ -27,8 +28,8 @@ public class AuthenticationProviderManager {
private final RealmModel realm; private final RealmModel realm;
private final Map<String, AuthenticationProvider> delegates; private final Map<String, AuthenticationProvider> delegates;
public static AuthenticationProviderManager getManager(RealmModel realm) { public static AuthenticationProviderManager getManager(RealmModel realm, ProviderSession providerSession) {
Iterable<AuthenticationProvider> providers = load(); Iterable<AuthenticationProvider> providers = providerSession.getAllProviders(AuthenticationProvider.class);
Map<String, AuthenticationProvider> providersMap = new HashMap<String, AuthenticationProvider>(); Map<String, AuthenticationProvider> providersMap = new HashMap<String, AuthenticationProvider>();
for (AuthenticationProvider provider : providers) { for (AuthenticationProvider provider : providers) {
@ -38,10 +39,6 @@ public class AuthenticationProviderManager {
return new AuthenticationProviderManager(realm, providersMap); return new AuthenticationProviderManager(realm, providersMap);
} }
public static Iterable<AuthenticationProvider> load() {
return ProviderLoader.load(AuthenticationProvider.class);
}
public AuthenticationProviderManager(RealmModel realm, Map<String, AuthenticationProvider> delegates) { public AuthenticationProviderManager(RealmModel realm, Map<String, AuthenticationProvider> delegates) {
this.realm = realm; this.realm = realm;
this.delegates = delegates; this.delegates = delegates;

View file

@ -70,6 +70,10 @@ public abstract class AbstractModelAuthenticationProvider implements Authenticat
return true; return true;
} }
@Override
public void close() {
}
protected abstract RealmModel getRealm(RealmModel currentRealm, Map<String, String> config) throws AuthenticationProviderException; protected abstract RealmModel getRealm(RealmModel currentRealm, Map<String, String> config) throws AuthenticationProviderException;
protected AuthUser createAuthenticatedUserInstance(UserModel user) { protected AuthUser createAuthenticatedUserInstance(UserModel user) {

View file

@ -9,6 +9,7 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.authentication.AuthProviderConstants; import org.keycloak.authentication.AuthProviderConstants;
import org.keycloak.authentication.AuthenticationProviderException; import org.keycloak.authentication.AuthenticationProviderException;
import org.keycloak.provider.ProviderSession;
/** /**
* AbstractModelAuthenticationProvider, which delegates authentication operations to different (external) realm * AbstractModelAuthenticationProvider, which delegates authentication operations to different (external) realm
@ -17,6 +18,9 @@ import org.keycloak.authentication.AuthenticationProviderException;
*/ */
public class ExternalModelAuthenticationProvider extends AbstractModelAuthenticationProvider { public class ExternalModelAuthenticationProvider extends AbstractModelAuthenticationProvider {
public ExternalModelAuthenticationProvider(ProviderSession providerSession) {
}
@Override @Override
public String getName() { public String getName() {
return AuthProviderConstants.PROVIDER_NAME_EXTERNAL_MODEL; return AuthProviderConstants.PROVIDER_NAME_EXTERNAL_MODEL;
@ -34,6 +38,7 @@ public class ExternalModelAuthenticationProvider extends AbstractModelAuthentica
throw new AuthenticationProviderException("Option '" + AuthProviderConstants.EXTERNAL_REALM_ID + "' not specified in configuration"); throw new AuthenticationProviderException("Option '" + AuthProviderConstants.EXTERNAL_REALM_ID + "' not specified in configuration");
} }
// TODO: This won't be needed when KeycloakSession is available from ProviderSession
KeycloakSession session = ResteasyProviderFactory.getContextData(KeycloakSession.class); KeycloakSession session = ResteasyProviderFactory.getContextData(KeycloakSession.class);
if (session == null) { if (session == null) {
throw new AuthenticationProviderException("KeycloakSession not available"); throw new AuthenticationProviderException("KeycloakSession not available");

View file

@ -0,0 +1,36 @@
package org.keycloak.authentication.model;
import org.keycloak.authentication.AuthProviderConstants;
import org.keycloak.authentication.AuthenticationProvider;
import org.keycloak.authentication.AuthenticationProviderFactory;
import org.keycloak.provider.ProviderSession;
import org.keycloak.provider.ProviderSessionFactory;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ExternalModelAuthenticationProviderFactory implements AuthenticationProviderFactory {
@Override
public AuthenticationProvider create(ProviderSession providerSession) {
return new ExternalModelAuthenticationProvider(providerSession);
}
@Override
public void init() {
}
@Override
public void close() {
}
@Override
public String getId() {
return AuthProviderConstants.PROVIDER_NAME_EXTERNAL_MODEL;
}
@Override
public boolean lazyLoad() {
return false;
}
}

View file

@ -0,0 +1,35 @@
package org.keycloak.authentication.model;
import org.keycloak.authentication.AuthProviderConstants;
import org.keycloak.authentication.AuthenticationProvider;
import org.keycloak.authentication.AuthenticationProviderFactory;
import org.keycloak.provider.ProviderSession;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class ModelAuthenticationProviderFactory implements AuthenticationProviderFactory {
@Override
public AuthenticationProvider create(ProviderSession providerSession) {
return new ModelAuthenticationProvider();
}
@Override
public void init() {
}
@Override
public void close() {
}
@Override
public String getId() {
return AuthProviderConstants.PROVIDER_NAME_MODEL;
}
@Override
public boolean lazyLoad() {
return false;
}
}

View file

@ -1,2 +0,0 @@
org.keycloak.authentication.model.ModelAuthenticationProvider
org.keycloak.authentication.model.ExternalModelAuthenticationProvider

View file

@ -0,0 +1,2 @@
org.keycloak.authentication.model.ModelAuthenticationProviderFactory
org.keycloak.authentication.model.ExternalModelAuthenticationProviderFactory

View file

@ -31,6 +31,12 @@
<version>${project.version}</version> <version>${project.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-picketlink-api</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>org.jboss.resteasy</groupId> <groupId>org.jboss.resteasy</groupId>

View file

@ -12,7 +12,7 @@ import org.keycloak.authentication.AuthProviderConstants;
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.picketlink.PartitionManagerProvider; import org.keycloak.picketlink.IdentityManagerProvider;
import org.keycloak.util.ProviderLoader; 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;
@ -32,6 +32,12 @@ public class PicketlinkAuthenticationProvider implements AuthenticationProvider
private static final Logger logger = Logger.getLogger(PicketlinkAuthenticationProvider.class); private static final Logger logger = Logger.getLogger(PicketlinkAuthenticationProvider.class);
private final IdentityManagerProvider identityManagerProvider;
public PicketlinkAuthenticationProvider(IdentityManagerProvider identityManagerProvider) {
this.identityManagerProvider = identityManagerProvider;
}
@Override @Override
public String getName() { public String getName() {
return AuthProviderConstants.PROVIDER_NAME_PICKETLINK; return AuthProviderConstants.PROVIDER_NAME_PICKETLINK;
@ -107,28 +113,12 @@ public class PicketlinkAuthenticationProvider implements AuthenticationProvider
} }
} }
@Override
public void close() {
}
public IdentityManager getIdentityManager(RealmModel realm) throws AuthenticationProviderException { public IdentityManager getIdentityManager(RealmModel realm) throws AuthenticationProviderException {
IdentityManager identityManager = ResteasyProviderFactory.getContextData(IdentityManager.class); return identityManagerProvider.getIdentityManager(realm);
if (identityManager == null) {
Iterable<PartitionManagerProvider> providers = ProviderLoader.load(PartitionManagerProvider.class);
// TODO: Priority?
PartitionManager partitionManager = null;
for (PartitionManagerProvider provider : providers) {
partitionManager = provider.getPartitionManager(realm);
if (partitionManager != null) {
break;
}
}
if (partitionManager == null) {
throw new AuthenticationProviderException("Not able to locate PartitionManager with any PartitionManagerProvider");
}
identityManager = partitionManager.createIdentityManager();
ResteasyProviderFactory.pushContext(IdentityManager.class, identityManager);
}
return identityManager;
} }
private AuthenticationProviderException convertIDMException(IdentityManagementException ie) { private AuthenticationProviderException convertIDMException(IdentityManagementException ie) {

View file

@ -0,0 +1,36 @@
package org.keycloak.authentication.picketlink;
import org.keycloak.authentication.AuthProviderConstants;
import org.keycloak.authentication.AuthenticationProvider;
import org.keycloak.authentication.AuthenticationProviderFactory;
import org.keycloak.picketlink.IdentityManagerProvider;
import org.keycloak.provider.ProviderSession;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class PicketlinkAuthenticationProviderFactory implements AuthenticationProviderFactory {
@Override
public AuthenticationProvider create(ProviderSession providerSession) {
return new PicketlinkAuthenticationProvider(providerSession.getProvider(IdentityManagerProvider.class));
}
@Override
public void init() {
}
@Override
public void close() {
}
@Override
public String getId() {
return AuthProviderConstants.PROVIDER_NAME_PICKETLINK;
}
@Override
public boolean lazyLoad() {
return false;
}
}

View file

@ -1,12 +0,0 @@
package org.keycloak.picketlink;
import org.keycloak.models.RealmModel;
import org.picketlink.idm.PartitionManager;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public interface PartitionManagerProvider {
PartitionManager getPartitionManager(RealmModel realm);
}

View file

@ -1,36 +0,0 @@
package org.keycloak.picketlink.impl;
import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.picketlink.PartitionManagerProvider;
import org.keycloak.util.KeycloakRegistry;
import org.picketlink.idm.PartitionManager;
/**
* Obtains {@link PartitionManager} instances from shared {@link PartitionManagerRegistry} and uses realm configuration for it
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class RealmPartitionManagerProvider implements PartitionManagerProvider {
private static final Logger logger = Logger.getLogger(RealmPartitionManagerProvider.class);
@Override
public PartitionManager getPartitionManager(RealmModel realm) {
KeycloakRegistry registry = ResteasyProviderFactory.getContextData(KeycloakRegistry.class) ;
if (registry == null) {
logger.warn("KeycloakRegistry not found");
return null;
}
PartitionManagerRegistry partitionManagerRegistry = registry.getService(PartitionManagerRegistry.class);
if (partitionManagerRegistry == null) {
partitionManagerRegistry = new PartitionManagerRegistry();
partitionManagerRegistry = registry.putServiceIfAbsent(PartitionManagerRegistry.class, partitionManagerRegistry);
logger.info("Pushed PartitionManagerRegistry component");
}
return partitionManagerRegistry.getPartitionManager(realm);
}
}

View file

@ -1 +0,0 @@
org.keycloak.picketlink.impl.RealmPartitionManagerProvider

View file

@ -5,7 +5,7 @@ package org.keycloak.provider;
*/ */
public interface ProviderFactory<T extends Provider> { public interface ProviderFactory<T extends Provider> {
public T create(); public T create(ProviderSession providerSession);
public void init(); public void init();

View file

@ -68,12 +68,12 @@ public class ProviderFactoryLoader<T extends Provider> implements Iterable<Provi
} }
@Override @Override
public synchronized T create() { public synchronized T create(ProviderSession providerSession) {
if (!initialized) { if (!initialized) {
factory.init(); factory.init();
initialized = true; initialized = true;
} }
return factory.create(); return factory.create(providerSession);
} }
@Override @Override
@ -82,9 +82,11 @@ public class ProviderFactoryLoader<T extends Provider> implements Iterable<Provi
} }
@Override @Override
public void close() { public synchronized void close() {
if (initialized) {
factory.close(); factory.close();
} }
}
@Override @Override
public String getId() { public String getId() {

View file

@ -1,6 +1,4 @@
package org.keycloak.services; package org.keycloak.provider;
import org.keycloak.provider.Provider;
import java.util.Set; import java.util.Set;
@ -15,6 +13,8 @@ public interface ProviderSession {
<T extends Provider> Set<String> listProviderIds(Class<T> clazz); <T extends Provider> Set<String> listProviderIds(Class<T> clazz);
<T extends Provider> Set<T> getAllProviders(Class<T> clazz);
void close(); void close();
} }

View file

@ -1,11 +1,5 @@
package org.keycloak.services; package org.keycloak.provider;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.ProviderFactoryLoader;
import java.util.HashMap;
import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**

View file

@ -1,29 +0,0 @@
package org.keycloak.util;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* Set of services shared for whole Keycloak server
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class KeycloakRegistry {
private final ConcurrentMap<Class<?>, Object> services = new ConcurrentHashMap<Class<?>, Object>();
public <T> void putService(Class<T> type, T object) {
services.put(type, object);
}
public <T> T putServiceIfAbsent(Class<T> type, T object) {
// Put only if absent and always return the version from registry
services.putIfAbsent(type, object);
return (T) services.get(type);
}
public <T> T getService(Class<T> type) {
return (T) services.get(type);
}
}

View file

@ -18,6 +18,8 @@ public class Config {
public static final String AUDIT_EXPIRATION_SCHEDULE_KEY = "keycloak.audit.expirationSchedule"; public static final String AUDIT_EXPIRATION_SCHEDULE_KEY = "keycloak.audit.expirationSchedule";
public static final String AUDIT_EXPIRATION_SCHEDULE_DEFAULT = String.valueOf(TimeUnit.MINUTES.toMillis(15)); 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_KEY = "keycloak.theme.base";
public static final String THEME_BASE_DEFAULT = "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_KEY = "keycloak.theme.default";
@ -68,6 +70,14 @@ public class Config {
System.setProperty(TIMER_PROVIDER_KEY, 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() { public static String getThemeDir() {
String themeDir = System.getProperty(THEME_DIR_KEY); String themeDir = System.getProperty(THEME_DIR_KEY);
if (themeDir == null && System.getProperties().containsKey(JBOSS_SERVER_CONFIG_DIR_KEY)) { if (themeDir == null && System.getProperties().containsKey(JBOSS_SERVER_CONFIG_DIR_KEY)) {

View file

@ -65,7 +65,7 @@ public class MongoStoreImpl implements MongoStore {
mapperRegistry.addDBObjectMapper(converter); mapperRegistry.addDBObjectMapper(converter);
} }
// Specific converter for ArrayList is added just for performance purposes to avoid recursive converter lookup (most of list impl will be ArrayList) // Specific converter for ArrayList is added just for performance purposes to avoid recursive converter lookup (most of list idm will be ArrayList)
mapperRegistry.addAppObjectMapper(new ListMapper(mapperRegistry, ArrayList.class)); mapperRegistry.addAppObjectMapper(new ListMapper(mapperRegistry, ArrayList.class));
mapperRegistry.addAppObjectMapper(new ListMapper(mapperRegistry, List.class)); mapperRegistry.addAppObjectMapper(new ListMapper(mapperRegistry, List.class));
mapperRegistry.addDBObjectMapper(new BasicDBListMapper(mapperRegistry)); mapperRegistry.addDBObjectMapper(new BasicDBListMapper(mapperRegistry));

View file

@ -18,7 +18,7 @@ import org.keycloak.models.mongo.keycloak.entities.RoleEntity;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
/** /**
* Wrapper around RoleData object, which will persist wrapped object after each set operation (compatibility with picketlink based impl) * Wrapper around RoleData object, which will persist wrapped object after each set operation (compatibility with picketlink based idm)
* *
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */

View file

@ -11,7 +11,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**
* Wrapper around UserData object, which will persist wrapped object after each set operation (compatibility with picketlink based impl) * Wrapper around UserData object, which will persist wrapped object after each set operation (compatibility with picketlink based idm)
* *
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */

View file

@ -7,7 +7,7 @@ package org.keycloak.models.mongo.keycloak.config;
*/ */
public class MongoClientProviderHolder { public class MongoClientProviderHolder {
// Just use static object for now. Default impl is SystemPropsMongoClientProvider // Just use static object for now. Default idm is SystemPropsMongoClientProvider
private static MongoClientProvider instance = new SystemPropertiesMongoClientProvider(); private static MongoClientProvider instance = new SystemPropertiesMongoClientProvider();
public static MongoClientProvider getInstance() { public static MongoClientProvider getInstance() {

View file

@ -39,6 +39,30 @@
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-picketlink-api</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-picketlink-realm</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-timer-api</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-timer-basic</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>

View file

@ -17,7 +17,7 @@ import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext; import javax.naming.directory.InitialDirContext;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.picketlink.impl.LdapConstants; import org.keycloak.picketlink.idm.LdapConstants;
import org.picketbox.test.ldap.AbstractLDAPTest; import org.picketbox.test.ldap.AbstractLDAPTest;
/** /**

View file

@ -1,9 +1,9 @@
package org.keycloak.model.test; package org.keycloak.model.test;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.authentication.picketlink.PicketlinkAuthenticationProvider; import org.keycloak.authentication.picketlink.PicketlinkAuthenticationProvider;
import org.keycloak.util.KeycloakRegistry; import org.keycloak.picketlink.IdentityManagerProvider;
import org.keycloak.provider.ProviderSession;
import org.picketlink.idm.IdentityManager; import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.credential.Password; import org.picketlink.idm.credential.Password;
import org.picketlink.idm.model.basic.BasicModel; import org.picketlink.idm.model.basic.BasicModel;
@ -14,16 +14,10 @@ import org.picketlink.idm.model.basic.User;
*/ */
public class LdapTestUtils { public class LdapTestUtils {
public static void setLdapPassword(RealmModel realm, String username, String password) { public static void setLdapPassword(ProviderSession providerSession, RealmModel realm, String username, String password) {
// TODO: Workaround... should be improved once we have KeycloakSession with available application-scoped components
KeycloakRegistry registry = ResteasyProviderFactory.getContextData(KeycloakRegistry.class);
if (registry == null) {
ResteasyProviderFactory.pushContext(KeycloakRegistry.class, new KeycloakRegistry());
}
// Update password directly in ldap. It's workaround, but LDIF import doesn't seem to work on windows for ApacheDS // Update password directly in ldap. It's workaround, but LDIF import doesn't seem to work on windows for ApacheDS
try { try {
IdentityManager identityManager = new PicketlinkAuthenticationProvider().getIdentityManager(realm); IdentityManager identityManager = new PicketlinkAuthenticationProvider(providerSession.getProvider(IdentityManagerProvider.class)).getIdentityManager(realm);
User user = BasicModel.getUser(identityManager, username); User user = BasicModel.getUser(identityManager, username);
identityManager.updateCredential(user, new Password(password.toCharArray())); identityManager.updateCredential(user, new Password(password.toCharArray()));
} catch (Exception e) { } catch (Exception e) {

View file

@ -12,6 +12,8 @@ import org.junit.Before;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
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;
@ -26,6 +28,8 @@ public class AbstractModelTest {
protected KeycloakSessionFactory factory; protected KeycloakSessionFactory factory;
protected KeycloakSession identitySession; protected KeycloakSession identitySession;
protected RealmManager realmManager; protected RealmManager realmManager;
protected ProviderSessionFactory providerSessionFactory;
protected ProviderSession providerSession;
@Before @Before
public void before() throws Exception { public void before() throws Exception {
@ -34,13 +38,18 @@ public class AbstractModelTest {
identitySession.getTransaction().begin(); identitySession.getTransaction().begin();
realmManager = new RealmManager(identitySession); realmManager = new RealmManager(identitySession);
providerSessionFactory = KeycloakApplication.createProviderSessionFactory();
providerSession = providerSessionFactory.createSession();
new ApplianceBootstrap().bootstrap(identitySession, "/auth"); new ApplianceBootstrap().bootstrap(identitySession, "/auth");
} }
@After @After
public void after() throws Exception { public void after() throws Exception {
identitySession.getTransaction().commit(); identitySession.getTransaction().commit();
providerSession.close();
identitySession.close(); identitySession.close();
providerSessionFactory.close();
factory.close(); factory.close();
} }

View file

@ -62,7 +62,7 @@ public class AuthProvidersExternalModelTest extends AbstractModelTest {
credential.setValue("password"); credential.setValue("password");
realm1.updateCredential(john, credential); realm1.updateCredential(john, credential);
am = new AuthenticationManager(); am = new AuthenticationManager(providerSession);
} }
@ -119,7 +119,7 @@ public class AuthProvidersExternalModelTest extends AbstractModelTest {
ResteasyProviderFactory.pushContext(KeycloakSession.class, identitySession); ResteasyProviderFactory.pushContext(KeycloakSession.class, identitySession);
// Change credential via realm2 and validate that they are changed also in realm1 // Change credential via realm2 and validate that they are changed also in realm1
AuthenticationProviderManager authProviderManager = AuthenticationProviderManager.getManager(realm2); AuthenticationProviderManager authProviderManager = AuthenticationProviderManager.getManager(realm2, providerSession);
try { try {
Assert.assertTrue(authProviderManager.updatePassword(john, "password-updated")); Assert.assertTrue(authProviderManager.updatePassword(john, "password-updated"));
} catch (AuthenticationProviderException ape) { } catch (AuthenticationProviderException ape) {

View file

@ -22,7 +22,6 @@ import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.authentication.AuthProviderConstants; import org.keycloak.authentication.AuthProviderConstants;
import org.keycloak.authentication.AuthenticationProviderException; import org.keycloak.authentication.AuthenticationProviderException;
import org.keycloak.authentication.AuthenticationProviderManager; import org.keycloak.authentication.AuthenticationProviderManager;
import org.keycloak.util.KeycloakRegistry;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -52,7 +51,7 @@ public class AuthProvidersLDAPTest extends AbstractModelTest {
realm.addRequiredCredential(CredentialRepresentation.PASSWORD); realm.addRequiredCredential(CredentialRepresentation.PASSWORD);
this.embeddedServer.setupLdapInRealm(realm); this.embeddedServer.setupLdapInRealm(realm);
am = new AuthenticationManager(); am = new AuthenticationManager(providerSession);
} }
@After @After
@ -70,12 +69,8 @@ public class AuthProvidersLDAPTest extends AbstractModelTest {
public void testLdapAuthentication() { public void testLdapAuthentication() {
MultivaluedMap<String, String> formData = AuthProvidersExternalModelTest.createFormData("john", "password"); MultivaluedMap<String, String> formData = AuthProvidersExternalModelTest.createFormData("john", "password");
try {
// this is needed for Picketlink model provider
ResteasyProviderFactory.pushContext(KeycloakRegistry.class, new KeycloakRegistry());
// Set password of user in LDAP // Set password of user in LDAP
LdapTestUtils.setLdapPassword(realm, "john", "password"); LdapTestUtils.setLdapPassword(providerSession, realm, "john", "password");
// Verify that user doesn't exists in realm2 and can't authenticate here // Verify that user doesn't exists in realm2 and can't authenticate here
Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_USER, am.authenticateForm(null, realm, formData)); Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_USER, am.authenticateForm(null, realm, formData));
@ -97,19 +92,12 @@ public class AuthProvidersLDAPTest extends AbstractModelTest {
AuthenticationLinkModel authLink = realm.getAuthenticationLink(john); AuthenticationLinkModel authLink = realm.getAuthenticationLink(john);
Assert.assertNotNull(authLink); Assert.assertNotNull(authLink);
Assert.assertEquals(authLink.getAuthProvider(), AuthProviderConstants.PROVIDER_NAME_PICKETLINK); Assert.assertEquals(authLink.getAuthProvider(), AuthProviderConstants.PROVIDER_NAME_PICKETLINK);
} finally {
ResteasyProviderFactory.clearContextData();
}
} }
@Test @Test
public void testLdapInvalidAuthentication() { public void testLdapInvalidAuthentication() {
setupAuthenticationProviders(); setupAuthenticationProviders();
try {
ResteasyProviderFactory.pushContext(KeycloakRegistry.class, new KeycloakRegistry());
// Add some user and password to realm // Add some user and password to realm
UserModel realmUser = realm.addUser("realmUser"); UserModel realmUser = realm.addUser("realmUser");
realmUser.setEnabled(true); realmUser.setEnabled(true);
@ -139,9 +127,6 @@ public class AuthProvidersLDAPTest extends AbstractModelTest {
realmUser.setEnabled(true); realmUser.setEnabled(true);
formData = AuthProvidersExternalModelTest.createFormData("realmUser", "pass"); formData = AuthProvidersExternalModelTest.createFormData("realmUser", "pass");
Assert.assertEquals(AuthenticationManager.AuthenticationStatus.SUCCESS, am.authenticateForm(null, realm, formData)); Assert.assertEquals(AuthenticationManager.AuthenticationStatus.SUCCESS, am.authenticateForm(null, realm, formData));
} finally {
ResteasyProviderFactory.clearContextData();
}
} }
@Test @Test
@ -149,18 +134,14 @@ public class AuthProvidersLDAPTest extends AbstractModelTest {
// Add ldap // Add ldap
setupAuthenticationProviders(); setupAuthenticationProviders();
try { LdapTestUtils.setLdapPassword(providerSession, realm, "john", "password");
// this is needed for ldap provider
ResteasyProviderFactory.pushContext(KeycloakRegistry.class, new KeycloakRegistry());
LdapTestUtils.setLdapPassword(realm, "john", "password");
// First authenticate successfully to sync john into realm // First authenticate successfully to sync john into realm
MultivaluedMap<String, String> formData = AuthProvidersExternalModelTest.createFormData("john", "password"); MultivaluedMap<String, String> formData = AuthProvidersExternalModelTest.createFormData("john", "password");
Assert.assertEquals(AuthenticationManager.AuthenticationStatus.SUCCESS, am.authenticateForm(null, realm, formData)); Assert.assertEquals(AuthenticationManager.AuthenticationStatus.SUCCESS, am.authenticateForm(null, realm, formData));
// Change credential and validate that user can authenticate // Change credential and validate that user can authenticate
AuthenticationProviderManager authProviderManager = AuthenticationProviderManager.getManager(realm); AuthenticationProviderManager authProviderManager = AuthenticationProviderManager.getManager(realm, providerSession);
UserModel john = realm.getUser("john"); UserModel john = realm.getUser("john");
try { try {
@ -187,9 +168,6 @@ public class AuthProvidersLDAPTest extends AbstractModelTest {
} }
formData = AuthProvidersExternalModelTest.createFormData("john", "password-updated2"); formData = AuthProvidersExternalModelTest.createFormData("john", "password-updated2");
Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_CREDENTIALS, am.authenticateForm(null, realm, formData)); Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_CREDENTIALS, am.authenticateForm(null, realm, formData));
} finally {
ResteasyProviderFactory.clearContextData();
}
} }
/** /**

View file

@ -143,7 +143,7 @@ public class AuthenticationManagerTest extends AbstractModelTest {
realm.addRequiredCredential(CredentialRepresentation.PASSWORD); realm.addRequiredCredential(CredentialRepresentation.PASSWORD);
realm.setAuthenticationProviders(Arrays.asList(AuthenticationProviderModel.DEFAULT_PROVIDER)); realm.setAuthenticationProviders(Arrays.asList(AuthenticationProviderModel.DEFAULT_PROVIDER));
am = new AuthenticationManager(); am = new AuthenticationManager(providerSession);
user = realm.addUser("test"); user = realm.addUser("test");
user.setEnabled(true); user.setEnabled(true);

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>keycloak-picketlink</artifactId>
<groupId>org.keycloak</groupId>
<version>1.0-beta-1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-picketlink-api</artifactId>
<name>Keycloak Picketlink API</name>
<description />
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-model-api</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View file

@ -0,0 +1,13 @@
package org.keycloak.picketlink;
import org.keycloak.models.RealmModel;
import org.keycloak.provider.Provider;
import org.picketlink.idm.IdentityManager;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public interface IdentityManagerProvider extends Provider {
IdentityManager getIdentityManager(RealmModel realm);
}

View file

@ -0,0 +1,9 @@
package org.keycloak.picketlink;
import org.keycloak.provider.ProviderFactory;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public interface IdentityManagerProviderFactory extends ProviderFactory<IdentityManagerProvider> {
}

View file

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>keycloak-picketlink</artifactId>
<groupId>org.keycloak</groupId>
<version>1.0-beta-1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-picketlink-realm</artifactId>
<name>Keycloak Picketlink Realm</name>
<description />
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-model-api</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-picketlink-api</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-impl</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View file

@ -1,4 +1,4 @@
package org.keycloak.picketlink.impl; package org.keycloak.picketlink.idm;
import org.picketlink.idm.IdentityManager; import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.ldap.internal.LDAPPlainTextPasswordCredentialHandler; import org.picketlink.idm.ldap.internal.LDAPPlainTextPasswordCredentialHandler;

View file

@ -1,4 +1,4 @@
package org.keycloak.picketlink.impl; package org.keycloak.picketlink.idm;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>

View file

@ -1,10 +1,12 @@
package org.keycloak.picketlink.impl; package org.keycloak.picketlink.realm;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.picketlink.idm.LDAPAgentIgnoreCredentialHandler;
import org.keycloak.picketlink.idm.LdapConstants;
import org.picketlink.idm.PartitionManager; import org.picketlink.idm.PartitionManager;
import org.picketlink.idm.config.IdentityConfigurationBuilder; import org.picketlink.idm.config.IdentityConfigurationBuilder;
import org.picketlink.idm.internal.DefaultPartitionManager; import org.picketlink.idm.internal.DefaultPartitionManager;

View file

@ -0,0 +1,28 @@
package org.keycloak.picketlink.realm;
import org.keycloak.models.RealmModel;
import org.keycloak.picketlink.IdentityManagerProvider;
import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.PartitionManager;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class RealmIdentityManagerProvider implements IdentityManagerProvider {
private final PartitionManagerRegistry partitionManagerRegistry;
public RealmIdentityManagerProvider(PartitionManagerRegistry partitionManagerRegistry) {
this.partitionManagerRegistry = partitionManagerRegistry;
}
@Override
public IdentityManager getIdentityManager(RealmModel realm) {
PartitionManager partitionManager = partitionManagerRegistry.getPartitionManager(realm);
return partitionManager.createIdentityManager();
}
@Override
public void close() {
}
}

View file

@ -0,0 +1,40 @@
package org.keycloak.picketlink.realm;
import org.keycloak.picketlink.IdentityManagerProvider;
import org.keycloak.picketlink.IdentityManagerProviderFactory;
import org.keycloak.provider.ProviderSession;
import org.picketlink.idm.PartitionManager;
/**
* Obtains {@link PartitionManager} instances from shared {@link PartitionManagerRegistry} and uses realm configuration for it
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class RealmIdentityManagerProviderFactory implements IdentityManagerProviderFactory {
private PartitionManagerRegistry partitionManagerRegistry;
@Override
public IdentityManagerProvider create(ProviderSession providerSession) {
return new RealmIdentityManagerProvider(partitionManagerRegistry);
}
@Override
public void init() {
partitionManagerRegistry = new PartitionManagerRegistry();
}
@Override
public void close() {
}
@Override
public String getId() {
return "realm";
}
@Override
public boolean lazyLoad() {
return false;
}
}

View file

@ -0,0 +1 @@
org.keycloak.picketlink.realm.RealmIdentityManagerProviderFactory

24
picketlink/pom.xml Normal file
View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>keycloak-parent</artifactId>
<groupId>org.keycloak</groupId>
<version>1.0-beta-1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<artifactId>keycloak-picketlink</artifactId>
<name>Keycloak Picketlink</name>
<description />
<modules>
<module>keycloak-picketlink-api</module>
<module>keycloak-picketlink-realm</module>
</modules>
</project>

View file

@ -91,6 +91,7 @@
<module>core-jaxrs</module> <module>core-jaxrs</module>
<module>model</module> <module>model</module>
<module>integration</module> <module>integration</module>
<module>picketlink</module>
<module>services</module> <module>services</module>
<module>social</module> <module>social</module>
<module>forms</module> <module>forms</module>

View file

@ -152,6 +152,16 @@
<artifactId>keycloak-timer-basic</artifactId> <artifactId>keycloak-timer-basic</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-picketlink-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-picketlink-realm</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>

View file

@ -87,6 +87,12 @@
<version>${project.version}</version> <version>${project.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-picketlink-api</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>

View file

@ -2,8 +2,10 @@ package org.keycloak.services;
import org.keycloak.provider.Provider; import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory; import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.ProviderSession;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -29,7 +31,7 @@ public class DefaultProviderSession implements ProviderSession {
if (provider == null) { if (provider == null) {
ProviderFactory<T> providerFactory = factory.getProviderFactory(clazz, id); ProviderFactory<T> providerFactory = factory.getProviderFactory(clazz, id);
if (providerFactory != null) { if (providerFactory != null) {
provider = providerFactory.create(); provider = providerFactory.create(this);
providers.put(hash, provider); providers.put(hash, provider);
} }
} }
@ -40,6 +42,16 @@ public class DefaultProviderSession implements ProviderSession {
return factory.providerIds(clazz); return factory.providerIds(clazz);
} }
@Override
public <T extends Provider> Set<T> getAllProviders(Class<T> clazz) {
Set<String> providerIds = listProviderIds(clazz);
Set<T> providers = new HashSet<T>();
for (String providerId : providerIds) {
providers.add(getProvider(clazz, providerId));
}
return providers;
}
public void close() { public void close() {
for (Provider p : providers.values()) { for (Provider p : providers.values()) {
p.close(); p.close();

View file

@ -3,6 +3,8 @@ package org.keycloak.services;
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.ProviderFactoryLoader;
import org.keycloak.provider.ProviderSession;
import org.keycloak.provider.ProviderSessionFactory;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;

View file

@ -4,9 +4,8 @@ import org.jboss.resteasy.spi.ResteasyProviderFactory;
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.services.ProviderSession; import org.keycloak.provider.ProviderSession;
import org.keycloak.services.ProviderSessionFactory; import org.keycloak.provider.ProviderSessionFactory;
import org.keycloak.util.KeycloakRegistry;
import javax.servlet.Filter; import javax.servlet.Filter;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
@ -33,9 +32,7 @@ public class KeycloakSessionServletFilter implements Filter {
ResteasyProviderFactory.pushContext(ProviderSession.class, providerSession); ResteasyProviderFactory.pushContext(ProviderSession.class, providerSession);
KeycloakRegistry registry = (KeycloakRegistry)servletRequest.getServletContext().getAttribute(KeycloakRegistry.class.getName()); KeycloakSessionFactory factory = (KeycloakSessionFactory) servletRequest.getServletContext().getAttribute(KeycloakSessionFactory.class.getName());
ResteasyProviderFactory.pushContext(KeycloakRegistry.class, registry);
KeycloakSessionFactory factory = registry.getService(KeycloakSessionFactory.class);
if (factory == null) throw new ServletException("Factory was null"); if (factory == null) throw new ServletException("Factory was null");
KeycloakSession session = factory.createSession(); KeycloakSession session = factory.createSession();
ResteasyProviderFactory.pushContext(KeycloakSession.class, session); ResteasyProviderFactory.pushContext(KeycloakSession.class, session);

View file

@ -1,7 +1,7 @@
package org.keycloak.services.listeners; package org.keycloak.services.listeners;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.util.KeycloakRegistry; import org.keycloak.provider.ProviderSessionFactory;
import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener; import javax.servlet.ServletContextListener;
@ -17,10 +17,13 @@ public class KeycloakSessionDestroyListener implements ServletContextListener {
@Override @Override
public void contextDestroyed(ServletContextEvent sce) { public void contextDestroyed(ServletContextEvent sce) {
KeycloakRegistry registry = (KeycloakRegistry)sce.getServletContext().getAttribute(KeycloakRegistry.class.getName()); ProviderSessionFactory providerSessionFactory = (ProviderSessionFactory) sce.getServletContext().getAttribute(ProviderSessionFactory.class.getName());
KeycloakSessionFactory factory = registry.getService(KeycloakSessionFactory.class); KeycloakSessionFactory kcSessionFactory = (KeycloakSessionFactory) sce.getServletContext().getAttribute(KeycloakSessionFactory.class.getName());
if (factory != null) { if (providerSessionFactory != null) {
factory.close(); providerSessionFactory.close();
}
if (kcSessionFactory != null) {
kcSessionFactory.close();
} }
} }

View file

@ -12,6 +12,7 @@ import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel; 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.provider.ProviderSession;
import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken;
import javax.ws.rs.BadRequestException; import javax.ws.rs.BadRequestException;
@ -26,12 +27,13 @@ import java.net.URI;
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */
public class AppAuthManager extends AuthenticationManager { public class AppAuthManager extends AuthenticationManager {
protected static Logger logger = Logger.getLogger(AuthenticationManager.class); protected static Logger logger = Logger.getLogger(AppAuthManager.class);
private String cookieName; private String cookieName;
private TokenManager tokenManager; private TokenManager tokenManager;
public AppAuthManager(String cookieName, TokenManager tokenManager) { public AppAuthManager(ProviderSession providerSession, String cookieName, TokenManager tokenManager) {
super(providerSession);
this.cookieName = cookieName; this.cookieName = cookieName;
this.tokenManager = tokenManager; this.tokenManager = tokenManager;
} }

View file

@ -6,7 +6,7 @@ import org.keycloak.audit.AuditListener;
import org.keycloak.audit.AuditProvider; import org.keycloak.audit.AuditProvider;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.services.ClientConnection; import org.keycloak.services.ClientConnection;
import org.keycloak.services.ProviderSession; import org.keycloak.provider.ProviderSession;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;

View file

@ -12,6 +12,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel; import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.provider.ProviderSession;
import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken;
import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.ClientConnection; import org.keycloak.services.ClientConnection;
@ -42,9 +43,11 @@ public class AuthenticationManager {
public static final String KEYCLOAK_IDENTITY_COOKIE = "KEYCLOAK_IDENTITY"; public static final String KEYCLOAK_IDENTITY_COOKIE = "KEYCLOAK_IDENTITY";
public static final String KEYCLOAK_REMEMBER_ME = "KEYCLOAK_REMEMBER_ME"; public static final String KEYCLOAK_REMEMBER_ME = "KEYCLOAK_REMEMBER_ME";
protected ProviderSession providerSession;
protected BruteForceProtector protector; protected BruteForceProtector protector;
public AuthenticationManager() { public AuthenticationManager(ProviderSession providerSession) {
this.providerSession = providerSession;
} }
public AuthenticationManager(BruteForceProtector protector) { public AuthenticationManager(BruteForceProtector protector) {
@ -222,7 +225,7 @@ public class AuthenticationManager {
protected AuthenticationStatus authenticateInternal(RealmModel realm, MultivaluedMap<String, String> formData, String username) { protected AuthenticationStatus authenticateInternal(RealmModel realm, MultivaluedMap<String, String> formData, String username) {
UserModel user = KeycloakModelUtils.findUserByNameOrEmail(realm, username); UserModel user = KeycloakModelUtils.findUserByNameOrEmail(realm, username);
if (user == null) { if (user == null) {
AuthUser authUser = AuthenticationProviderManager.getManager(realm).getUser(username); AuthUser authUser = AuthenticationProviderManager.getManager(realm, providerSession).getUser(username);
if (authUser != null) { if (authUser != null) {
// Create new user and link him with authentication provider // Create new user and link him with authentication provider
user = realm.addUser(authUser.getUsername()); user = realm.addUser(authUser.getUsername());
@ -269,7 +272,7 @@ public class AuthenticationManager {
} else { } else {
logger.debug("validating password for user: " + username); logger.debug("validating password for user: " + username);
AuthProviderStatus authStatus = AuthenticationProviderManager.getManager(realm).validatePassword(user, password); AuthProviderStatus authStatus = AuthenticationProviderManager.getManager(realm, providerSession).validatePassword(user, password);
if (authStatus == AuthProviderStatus.INVALID_CREDENTIALS) { if (authStatus == AuthProviderStatus.INVALID_CREDENTIALS) {
logger.debug("invalid password for user: " + username); logger.debug("invalid password for user: " + username);
return AuthenticationStatus.INVALID_CREDENTIALS; return AuthenticationStatus.INVALID_CREDENTIALS;

View file

@ -45,7 +45,7 @@ import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.utils.TimeBasedOTP; import org.keycloak.models.utils.TimeBasedOTP;
import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.ProviderSession; import org.keycloak.provider.ProviderSession;
import org.keycloak.services.managers.AppAuthManager; import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.Auth; import org.keycloak.services.managers.Auth;
import org.keycloak.services.managers.ModelToRepresentation; import org.keycloak.services.managers.ModelToRepresentation;
@ -137,7 +137,7 @@ public class AccountService {
this.realm = realm; this.realm = realm;
this.application = application; this.application = application;
this.audit = audit; this.audit = audit;
this.authManager = new AppAuthManager(KEYCLOAK_ACCOUNT_IDENTITY_COOKIE, tokenManager); this.authManager = new AppAuthManager(providers, KEYCLOAK_ACCOUNT_IDENTITY_COOKIE, tokenManager);
this.socialRequestManager = socialRequestManager; this.socialRequestManager = socialRequestManager;
} }
@ -339,7 +339,7 @@ public class AccountService {
return account.setError(Messages.INVALID_PASSWORD_CONFIRM).createResponse(AccountPages.PASSWORD); return account.setError(Messages.INVALID_PASSWORD_CONFIRM).createResponse(AccountPages.PASSWORD);
} }
AuthenticationProviderManager authProviderManager = AuthenticationProviderManager.getManager(realm); AuthenticationProviderManager authProviderManager = AuthenticationProviderManager.getManager(realm, providers);
if (Validation.isEmpty(password)) { if (Validation.isEmpty(password)) {
return account.setError(Messages.MISSING_PASSWORD).createResponse(AccountPages.PASSWORD); return account.setError(Messages.MISSING_PASSWORD).createResponse(AccountPages.PASSWORD);
} else if (authProviderManager.validatePassword(user, password) != AuthProviderStatus.SUCCESS) { } else if (authProviderManager.validatePassword(user, password) != AuthProviderStatus.SUCCESS) {

View file

@ -6,6 +6,8 @@ import org.keycloak.audit.AuditListener;
import org.keycloak.audit.AuditListenerFactory; import org.keycloak.audit.AuditListenerFactory;
import org.keycloak.audit.AuditProvider; import org.keycloak.audit.AuditProvider;
import org.keycloak.audit.AuditProviderFactory; import org.keycloak.audit.AuditProviderFactory;
import org.keycloak.authentication.AuthenticationProvider;
import org.keycloak.authentication.AuthenticationProviderFactory;
import org.keycloak.models.Config; import org.keycloak.models.Config;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
@ -14,15 +16,16 @@ import org.keycloak.models.RealmModel;
import org.keycloak.provider.ProviderFactory; import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.ProviderFactoryLoader; import org.keycloak.provider.ProviderFactoryLoader;
import org.keycloak.services.DefaultProviderSessionFactory; import org.keycloak.services.DefaultProviderSessionFactory;
import org.keycloak.services.ProviderSessionFactory; import org.keycloak.picketlink.IdentityManagerProvider;
import org.keycloak.timer.TimerProvider; import org.keycloak.picketlink.IdentityManagerProviderFactory;
import org.keycloak.timer.TimerProviderFactory; import org.keycloak.provider.ProviderSessionFactory;
import org.keycloak.util.KeycloakRegistry;
import org.keycloak.services.managers.ApplianceBootstrap; import org.keycloak.services.managers.ApplianceBootstrap;
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.AdminService; import org.keycloak.services.resources.admin.AdminService;
import org.keycloak.models.utils.ModelProviderUtils; import org.keycloak.models.utils.ModelProviderUtils;
import org.keycloak.timer.TimerProvider;
import org.keycloak.timer.TimerProviderFactory;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.ws.rs.core.Application; import javax.ws.rs.core.Application;
@ -45,19 +48,17 @@ public class KeycloakApplication extends Application {
protected Set<Class<?>> classes = new HashSet<Class<?>>(); protected Set<Class<?>> classes = new HashSet<Class<?>>();
protected KeycloakSessionFactory factory; protected KeycloakSessionFactory factory;
protected ProviderSessionFactory providerSessionFactory;
protected String contextPath; protected String contextPath;
public KeycloakApplication(@Context ServletContext context) { public KeycloakApplication(@Context ServletContext context) {
this.factory = createSessionFactory(); this.factory = createSessionFactory();
this.contextPath = context.getContextPath(); this.contextPath = context.getContextPath();
KeycloakRegistry registry = new KeycloakRegistry(); this.providerSessionFactory = createProviderSessionFactory();
registry.putService(KeycloakSessionFactory.class, factory); context.setAttribute(KeycloakSessionFactory.class.getName(), factory);
context.setAttribute(KeycloakRegistry.class.getName(), registry);
//classes.add(KeycloakSessionCleanupFilter.class); //classes.add(KeycloakSessionCleanupFilter.class);
DefaultProviderSessionFactory providerSessionFactory = createProviderSessionFactory(); context.setAttribute(ProviderSessionFactory.class.getName(), this.providerSessionFactory);
context.setAttribute(ProviderSessionFactory.class.getName(), providerSessionFactory);
TokenManager tokenManager = new TokenManager(); TokenManager tokenManager = new TokenManager();
SocialRequestManager socialRequestManager = new SocialRequestManager(); SocialRequestManager socialRequestManager = new SocialRequestManager();
@ -110,6 +111,9 @@ public class KeycloakApplication extends Application {
factory.registerLoader(AuditProvider.class, ProviderFactoryLoader.create(AuditProviderFactory.class), Config.getAuditProvider()); factory.registerLoader(AuditProvider.class, ProviderFactoryLoader.create(AuditProviderFactory.class), Config.getAuditProvider());
factory.registerLoader(AuditListener.class, ProviderFactoryLoader.create(AuditListenerFactory.class)); factory.registerLoader(AuditListener.class, ProviderFactoryLoader.create(AuditListenerFactory.class));
factory.registerLoader(TimerProvider.class, ProviderFactoryLoader.create(TimerProviderFactory.class), Config.getTimerProvider()); factory.registerLoader(TimerProvider.class, ProviderFactoryLoader.create(TimerProviderFactory.class), Config.getTimerProvider());
factory.registerLoader(IdentityManagerProvider.class, ProviderFactoryLoader.create(IdentityManagerProviderFactory.class), Config.getIdentityManagerProvider());
factory.registerLoader(AuthenticationProvider.class, ProviderFactoryLoader.create(AuthenticationProviderFactory.class));
factory.init();
return factory; return factory;
} }
@ -120,7 +124,7 @@ public class KeycloakApplication extends Application {
log.error("Can't setup schedule tasks, no timer provider found"); log.error("Can't setup schedule tasks, no timer provider found");
return; return;
} }
TimerProvider timer = timerFactory.create(); TimerProvider timer = timerFactory.create(null);
final ProviderFactory<AuditProvider> auditFactory = providerSessionFactory.getProviderFactory(AuditProvider.class); final ProviderFactory<AuditProvider> auditFactory = providerSessionFactory.getProviderFactory(AuditProvider.class);
if (auditFactory != null) { if (auditFactory != null) {
@ -128,7 +132,7 @@ public class KeycloakApplication extends Application {
@Override @Override
public void run() { public void run() {
KeycloakSession keycloakSession = keycloakSessionFactory.createSession(); KeycloakSession keycloakSession = keycloakSessionFactory.createSession();
AuditProvider audit = providerSessionFactory.getProviderFactory(AuditProvider.class).create(); AuditProvider audit = providerSessionFactory.getProviderFactory(AuditProvider.class).create(null);
try { try {
for (RealmModel realm : keycloakSession.getRealms()) { for (RealmModel realm : keycloakSession.getRealms()) {
if (realm.isAuditEnabled() && realm.getAuditExpiration() > 0) { if (realm.isAuditEnabled() && realm.getAuditExpiration() > 0) {
@ -152,6 +156,10 @@ public class KeycloakApplication extends Application {
return factory; return factory;
} }
public ProviderSessionFactory getProviderSessionFactory() {
return providerSessionFactory;
}
@Override @Override
public Set<Class<?>> getClasses() { public Set<Class<?>> getClasses() {
return classes; return classes;

View file

@ -2,20 +2,18 @@ package org.keycloak.services.resources;
import org.jboss.resteasy.logging.Logger; import org.jboss.resteasy.logging.Logger;
import org.keycloak.audit.Audit; import org.keycloak.audit.Audit;
import org.keycloak.audit.AuditListener;
import org.keycloak.audit.AuditProvider;
import org.keycloak.models.ApplicationModel; import org.keycloak.models.ApplicationModel;
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.services.ClientConnection; import org.keycloak.services.ClientConnection;
import org.keycloak.services.ProviderSession; import org.keycloak.provider.ProviderSession;
import org.keycloak.services.managers.AuditManager; import org.keycloak.services.managers.AuditManager;
import org.keycloak.services.managers.AuthenticationManager;
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 javax.servlet.http.HttpServletRequest;
import javax.ws.rs.NotFoundException; import javax.ws.rs.NotFoundException;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
@ -24,8 +22,6 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import java.util.LinkedList;
import java.util.List;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -70,7 +66,8 @@ public class RealmsResource {
RealmManager realmManager = new RealmManager(session); RealmManager realmManager = new RealmManager(session);
RealmModel realm = locateRealm(name, realmManager); RealmModel realm = locateRealm(name, realmManager);
Audit audit = new AuditManager(realm, providers, clientConnection).createAudit(); Audit audit = new AuditManager(realm, providers, clientConnection).createAudit();
TokenService tokenService = new TokenService(realm, tokenManager, audit); AuthenticationManager authManager = new AuthenticationManager(providers);
TokenService tokenService = new TokenService(realm, tokenManager, audit, authManager);
resourceContext.initResource(tokenService); resourceContext.initResource(tokenService);
return tokenService; return tokenService;
} }

View file

@ -37,6 +37,7 @@ import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.UserModel.RequiredAction; import org.keycloak.models.UserModel.RequiredAction;
import org.keycloak.models.utils.TimeBasedOTP; import org.keycloak.models.utils.TimeBasedOTP;
import org.keycloak.provider.ProviderSession;
import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.email.EmailException; import org.keycloak.services.email.EmailException;
import org.keycloak.services.email.EmailSender; import org.keycloak.services.email.EmailSender;
@ -84,7 +85,8 @@ public class RequiredActionsService {
@Context @Context
protected Providers providers; protected Providers providers;
protected AuthenticationManager authManager = new AuthenticationManager(); @Context
protected ProviderSession providerSession;
private TokenManager tokenManager; private TokenManager tokenManager;
@ -200,7 +202,7 @@ public class RequiredActionsService {
} }
try { try {
boolean updateSuccessful = AuthenticationProviderManager.getManager(realm).updatePassword(user, passwordNew); boolean updateSuccessful = AuthenticationProviderManager.getManager(realm, providerSession).updatePassword(user, passwordNew);
if (!updateSuccessful) { if (!updateSuccessful) {
return loginForms.setError("Password update failed").createResponse(RequiredAction.UPDATE_PASSWORD); return loginForms.setError("Password update failed").createResponse(RequiredAction.UPDATE_PASSWORD);
} }
@ -285,6 +287,8 @@ public class RequiredActionsService {
String redirect = uriInfo.getQueryParameters().getFirst(OAuth2Constants.REDIRECT_URI); String redirect = uriInfo.getQueryParameters().getFirst(OAuth2Constants.REDIRECT_URI);
String clientId = uriInfo.getQueryParameters().getFirst(OAuth2Constants.CLIENT_ID); String clientId = uriInfo.getQueryParameters().getFirst(OAuth2Constants.CLIENT_ID);
AuthenticationManager authManager = new AuthenticationManager(providerSession);
ClientModel client = realm.findClient(clientId); ClientModel client = realm.findClient(clientId);
if (client == null) { if (client == null) {
return Flows.oauth(realm, request, uriInfo, authManager, tokenManager).forwardToSecurityFailure( return Flows.oauth(realm, request, uriInfo, authManager, tokenManager).forwardToSecurityFailure(
@ -392,6 +396,9 @@ public class RequiredActionsService {
accessCode.setExpiration(Time.currentTime() + realm.getAccessCodeLifespan()); accessCode.setExpiration(Time.currentTime() + realm.getAccessCodeLifespan());
audit.success(); audit.success();
AuthenticationManager authManager = new AuthenticationManager(providerSession);
return Flows.oauth(realm, request, uriInfo, authManager, tokenManager).redirectAccessCode(accessCode, return Flows.oauth(realm, request, uriInfo, authManager, tokenManager).redirectAccessCode(accessCode,
accessCode.getState(), accessCode.getRedirectUri()); accessCode.getState(), accessCode.getRedirectUri());
} }

View file

@ -25,8 +25,6 @@ import org.jboss.resteasy.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest; import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.OAuth2Constants; import org.keycloak.OAuth2Constants;
import org.keycloak.audit.Audit; import org.keycloak.audit.Audit;
import org.keycloak.audit.AuditListener;
import org.keycloak.audit.AuditProvider;
import org.keycloak.audit.Details; import org.keycloak.audit.Details;
import org.keycloak.audit.Errors; import org.keycloak.audit.Errors;
import org.keycloak.audit.Events; import org.keycloak.audit.Events;
@ -39,7 +37,7 @@ import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.services.ClientConnection; import org.keycloak.services.ClientConnection;
import org.keycloak.services.ProviderSession; import org.keycloak.provider.ProviderSession;
import org.keycloak.services.managers.AuditManager; import org.keycloak.services.managers.AuditManager;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
@ -57,7 +55,6 @@ import org.keycloak.social.SocialProviderConfig;
import org.keycloak.social.SocialProviderException; import org.keycloak.social.SocialProviderException;
import org.keycloak.social.SocialUser; import org.keycloak.social.SocialUser;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
@ -72,7 +69,6 @@ import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -110,8 +106,6 @@ public class SocialResource {
private TokenManager tokenManager; private TokenManager tokenManager;
private AuthenticationManager authManager = new AuthenticationManager();
public SocialResource(TokenManager tokenManager, SocialRequestManager socialRequestManager) { public SocialResource(TokenManager tokenManager, SocialRequestManager socialRequestManager) {
this.tokenManager = tokenManager; this.tokenManager = tokenManager;
this.socialRequestManager = socialRequestManager; this.socialRequestManager = socialRequestManager;
@ -135,6 +129,7 @@ public class SocialResource {
.detail(Details.RESPONSE_TYPE, "code") .detail(Details.RESPONSE_TYPE, "code")
.detail(Details.AUTH_METHOD, "social@" + provider.getId()); .detail(Details.AUTH_METHOD, "social@" + provider.getId());
AuthenticationManager authManager = new AuthenticationManager(providers);
OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager); OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
if (!realm.isEnabled()) { if (!realm.isEnabled()) {

View file

@ -21,6 +21,7 @@ import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.UserCredentialModel; import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.provider.ProviderSession;
import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken;
import org.keycloak.representations.AccessTokenResponse; import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.CredentialRepresentation;
@ -79,7 +80,7 @@ public class TokenService {
protected RealmModel realm; protected RealmModel realm;
protected TokenManager tokenManager; protected TokenManager tokenManager;
private Audit audit; private Audit audit;
protected AuthenticationManager authManager = new AuthenticationManager(); protected AuthenticationManager authManager;
@Context @Context
protected Providers providers; protected Providers providers;
@ -99,16 +100,19 @@ public class TokenService {
protected KeycloakTransaction transaction; protected KeycloakTransaction transaction;
@Context @Context
protected ClientConnection clientConnection; protected ClientConnection clientConnection;
@Context
protected ProviderSession providerSession;
@Context @Context
protected ResourceContext resourceContext; protected ResourceContext resourceContext;
private ResourceAdminManager resourceAdminManager = new ResourceAdminManager(); private ResourceAdminManager resourceAdminManager = new ResourceAdminManager();
public TokenService(RealmModel realm, TokenManager tokenManager, Audit audit) { public TokenService(RealmModel realm, TokenManager tokenManager, Audit audit, AuthenticationManager authManager) {
this.realm = realm; this.realm = realm;
this.tokenManager = tokenManager; this.tokenManager = tokenManager;
this.audit = audit; this.audit = audit;
this.authManager = authManager;
} }
public static UriBuilder tokenServiceBaseUrl(UriInfo uriInfo) { public static UriBuilder tokenServiceBaseUrl(UriInfo uriInfo) {
@ -383,7 +387,7 @@ public class TokenService {
return Flows.forms(realm, request, uriInfo).setError(error).setFormData(formData).createRegistration(); return Flows.forms(realm, request, uriInfo).setError(error).setFormData(formData).createRegistration();
} }
AuthenticationProviderManager authenticationProviderManager = AuthenticationProviderManager.getManager(realm); AuthenticationProviderManager authenticationProviderManager = AuthenticationProviderManager.getManager(realm, providerSession);
// Validate that user with this username doesn't exist in realm or any authentication provider // Validate that user with this username doesn't exist in realm or any authentication provider
if (realm.getUser(username) != null || authenticationProviderManager.getUser(username) != null) { if (realm.getUser(username) != null || authenticationProviderManager.getUser(username) != null) {
@ -406,7 +410,7 @@ public class TokenService {
boolean passwordUpdateSuccessful; boolean passwordUpdateSuccessful;
String passwordUpdateError = null; String passwordUpdateError = null;
try { try {
passwordUpdateSuccessful = AuthenticationProviderManager.getManager(realm).updatePassword(user, formData.getFirst("password")); passwordUpdateSuccessful = AuthenticationProviderManager.getManager(realm, providerSession).updatePassword(user, formData.getFirst("password"));
passwordUpdateError = "Password update failed"; passwordUpdateError = "Password update failed";
} catch (AuthenticationProviderException ape) { } catch (AuthenticationProviderException ape) {
passwordUpdateSuccessful = false; passwordUpdateSuccessful = false;

View file

@ -15,6 +15,7 @@ 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.services.managers.AppAuthManager; import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.Auth; import org.keycloak.services.managers.Auth;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
@ -69,13 +70,16 @@ public class AdminService {
@Context @Context
protected Providers providers; protected Providers providers;
@Context
protected ProviderSession providerSession;
protected String adminPath = "/admin/index.html"; protected String adminPath = "/admin/index.html";
protected AppAuthManager authManager; protected AppAuthManager authManager;
protected TokenManager tokenManager; protected TokenManager tokenManager;
public AdminService(TokenManager tokenManager) { public AdminService(TokenManager tokenManager) {
this.tokenManager = tokenManager; this.tokenManager = tokenManager;
this.authManager = new AppAuthManager("KEYCLOAK_ADMIN_CONSOLE_IDENTITY", tokenManager); this.authManager = new AppAuthManager(providerSession, "KEYCLOAK_ADMIN_CONSOLE_IDENTITY", tokenManager);
} }
public static UriBuilder adminApiUrl(UriInfo uriInfo) { public static UriBuilder adminApiUrl(UriInfo uriInfo) {

View file

@ -11,7 +11,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.representations.adapters.action.SessionStats; import org.keycloak.representations.adapters.action.SessionStats;
import org.keycloak.representations.idm.RealmAuditRepresentation; import org.keycloak.representations.idm.RealmAuditRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.ProviderSession; import org.keycloak.provider.ProviderSession;
import org.keycloak.services.managers.ModelToRepresentation; import org.keycloak.services.managers.ModelToRepresentation;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceAdminManager; import org.keycloak.services.managers.ResourceAdminManager;

View file

@ -3,7 +3,7 @@ package org.keycloak.services.resources.admin;
import org.keycloak.audit.AuditListener; import org.keycloak.audit.AuditListener;
import org.keycloak.freemarker.Theme; import org.keycloak.freemarker.Theme;
import org.keycloak.freemarker.ThemeProvider; import org.keycloak.freemarker.ThemeProvider;
import org.keycloak.services.ProviderSession; import org.keycloak.provider.ProviderSession;
import org.keycloak.social.SocialProvider; import org.keycloak.social.SocialProvider;
import org.keycloak.authentication.AuthenticationProvider; import org.keycloak.authentication.AuthenticationProvider;
import org.keycloak.authentication.AuthenticationProviderManager; import org.keycloak.authentication.AuthenticationProviderManager;
@ -59,7 +59,7 @@ public class ServerInfoAdminResource {
private void setAuthProviders(ServerInfoRepresentation info) { private void setAuthProviders(ServerInfoRepresentation info) {
info.authProviders = new HashMap<String, List<String>>(); info.authProviders = new HashMap<String, List<String>>();
Iterable<AuthenticationProvider> authProviders = AuthenticationProviderManager.load(); Iterable<AuthenticationProvider> authProviders = providers.getAllProviders(AuthenticationProvider.class);
for (AuthenticationProvider authProvider : authProviders) { for (AuthenticationProvider authProvider : authProviders) {
info.authProviders.put(authProvider.getName(), authProvider.getAvailableOptions()); info.authProviders.put(authProvider.getName(), authProvider.getAvailableOptions());
} }

View file

@ -170,6 +170,16 @@
<artifactId>keycloak-authentication-model</artifactId> <artifactId>keycloak-authentication-model</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-picketlink-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-picketlink-realm</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.jboss.logging</groupId> <groupId>org.jboss.logging</groupId>
@ -186,7 +196,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.picketlink</groupId> <groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-impl</artifactId> <artifactId>picketlink-idm-idm</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.picketlink</groupId> <groupId>org.picketlink</groupId>

View file

@ -38,6 +38,7 @@ import org.jboss.resteasy.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.Config;
import org.keycloak.provider.ProviderSessionFactory;
import org.keycloak.services.filters.ClientConnectionFilter; import org.keycloak.services.filters.ClientConnectionFilter;
import org.keycloak.theme.DefaultLoginThemeProvider; import org.keycloak.theme.DefaultLoginThemeProvider;
import org.keycloak.services.tmp.TmpAdminRedirectServlet; import org.keycloak.services.tmp.TmpAdminRedirectServlet;
@ -173,6 +174,8 @@ public class KeycloakServer {
private KeycloakSessionFactory factory; private KeycloakSessionFactory factory;
private ProviderSessionFactory providerSessionFactory;
private UndertowJaxrsServer server; private UndertowJaxrsServer server;
public KeycloakServer() { public KeycloakServer() {
@ -187,6 +190,10 @@ public class KeycloakServer {
return factory; return factory;
} }
public ProviderSessionFactory getProviderSessionFactory() {
return providerSessionFactory;
}
public UndertowJaxrsServer getServer() { public UndertowJaxrsServer getServer() {
return server; return server;
} }
@ -275,6 +282,7 @@ public class KeycloakServer {
server.deploy(di); server.deploy(di);
factory = ((KeycloakApplication) deployment.getApplication()).getFactory(); factory = ((KeycloakApplication) deployment.getApplication()).getFactory();
providerSessionFactory = ((KeycloakApplication) deployment.getApplication()).getProviderSessionFactory();
setupDevConfig(); setupDevConfig();
@ -295,6 +303,7 @@ public class KeycloakServer {
} }
public void stop() { public void stop() {
providerSessionFactory.close();
factory.close(); factory.close();
server.stop(); server.stop();

View file

@ -16,6 +16,7 @@ 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.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.provider.ProviderSession;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.rule.KeycloakRule; import org.keycloak.testsuite.rule.KeycloakRule;
@ -165,7 +166,7 @@ public class AssertEvents implements TestRule, AuditListenerFactory {
} }
@Override @Override
public AuditListener create() { public AuditListener create(ProviderSession providerSession) {
return new AuditListener() { return new AuditListener() {
@Override @Override
public void onEvent(Event event) { public void onEvent(Event event) {

View file

@ -24,6 +24,7 @@ import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
import org.keycloak.testsuite.pages.AppPage; import org.keycloak.testsuite.pages.AppPage;
import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.pages.RegisterPage; import org.keycloak.testsuite.pages.RegisterPage;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.keycloak.testsuite.rule.KeycloakRule; import org.keycloak.testsuite.rule.KeycloakRule;
import org.keycloak.testsuite.rule.LDAPRule; import org.keycloak.testsuite.rule.LDAPRule;
import org.keycloak.testsuite.rule.WebResource; import org.keycloak.testsuite.rule.WebResource;
@ -62,7 +63,7 @@ public class AuthProvidersIntegrationTest {
// Configure LDAP // Configure LDAP
ldapRule.getEmbeddedServer().setupLdapInRealm(appRealm); ldapRule.getEmbeddedServer().setupLdapInRealm(appRealm);
LdapTestUtils.setLdapPassword(appRealm, "john", "password"); LdapTestUtils.setLdapPassword(providerSession, appRealm, "john", "password");
} }
}); });

View file

@ -24,6 +24,7 @@ package org.keycloak.testsuite.rule;
import org.keycloak.models.Config; 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.provider.ProviderSession;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.ApplicationServlet; import org.keycloak.testsuite.ApplicationServlet;
@ -58,6 +59,7 @@ public class KeycloakRule extends AbstractKeycloakRule {
public void configure(KeycloakSetup configurer) { public void configure(KeycloakSetup configurer) {
KeycloakSession session = server.getKeycloakSessionFactory().createSession(); KeycloakSession session = server.getKeycloakSessionFactory().createSession();
ProviderSession providerSession = server.getProviderSessionFactory().createSession();
session.getTransaction().begin(); session.getTransaction().begin();
try { try {
@ -66,17 +68,21 @@ public class KeycloakRule extends AbstractKeycloakRule {
RealmModel adminstrationRealm = manager.getRealm(Config.getAdminRealm()); RealmModel adminstrationRealm = manager.getRealm(Config.getAdminRealm());
RealmModel appRealm = manager.getRealm("test"); RealmModel appRealm = manager.getRealm("test");
configurer.providerSession = providerSession;
configurer.config(manager, adminstrationRealm, appRealm); configurer.config(manager, adminstrationRealm, appRealm);
session.getTransaction().commit(); session.getTransaction().commit();
} finally { } finally {
providerSession.close();
session.close(); session.close();
} }
} }
public interface KeycloakSetup { public abstract static class KeycloakSetup {
void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm); protected ProviderSession providerSession;
public abstract void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm);
} }

View file

@ -161,7 +161,7 @@
<!-- <!--
<dependency> <dependency>
<groupId>org.picketlink</groupId> <groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-impl</artifactId> <artifactId>picketlink-idm-idm</artifactId>
<version>${picketlink.version}</version> <version>${picketlink.version}</version>
</dependency> </dependency>
<dependency> <dependency>

View file

@ -1,5 +1,6 @@
package org.keycloak.timer.basic; package org.keycloak.timer.basic;
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;
@ -13,7 +14,7 @@ public class BasicTimerProviderFactory implements TimerProviderFactory {
private Timer timer; private Timer timer;
@Override @Override
public TimerProvider create() { public TimerProvider create(ProviderSession providerSession) {
return new BasicTimerProvider(timer); return new BasicTimerProvider(timer);
} }