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.keycloak.audit.AuditListener;
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>
@ -14,7 +16,7 @@ public class JBossLoggingAuditListenerFactory implements AuditListenerFactory {
private static final Logger logger = Logger.getLogger("org.keycloak.audit");
@Override
public AuditListener create() {
public AuditListener create(ProviderSession providerSession) {
return new JBossLoggingAuditListener(logger);
}

View file

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

View file

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

View file

@ -27,7 +27,7 @@ public abstract class AbstractAuditProviderTest {
factory = loader.find(getProviderId());
factory.init();
provider = factory.create();
provider = factory.create(null);
}
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.close();
provider = factory.create();
provider = factory.create(null);
Assert.assertEquals(5, provider.createQuery().client("clientId").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.close();
provider = factory.create();
provider = factory.create(null);
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.close();
provider = factory.create();
provider = factory.create(null);
provider.clear("realmId", System.currentTimeMillis() - 10000);

View file

@ -4,11 +4,12 @@ import java.util.List;
import java.util.Map;
import org.keycloak.models.RealmModel;
import org.keycloak.provider.Provider;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public interface AuthenticationProvider {
public interface AuthenticationProvider extends Provider {
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.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.provider.ProviderSession;
import org.keycloak.util.ProviderLoader;
/**
@ -27,8 +28,8 @@ public class AuthenticationProviderManager {
private final RealmModel realm;
private final Map<String, AuthenticationProvider> delegates;
public static AuthenticationProviderManager getManager(RealmModel realm) {
Iterable<AuthenticationProvider> providers = load();
public static AuthenticationProviderManager getManager(RealmModel realm, ProviderSession providerSession) {
Iterable<AuthenticationProvider> providers = providerSession.getAllProviders(AuthenticationProvider.class);
Map<String, AuthenticationProvider> providersMap = new HashMap<String, AuthenticationProvider>();
for (AuthenticationProvider provider : providers) {
@ -38,10 +39,6 @@ public class AuthenticationProviderManager {
return new AuthenticationProviderManager(realm, providersMap);
}
public static Iterable<AuthenticationProvider> load() {
return ProviderLoader.load(AuthenticationProvider.class);
}
public AuthenticationProviderManager(RealmModel realm, Map<String, AuthenticationProvider> delegates) {
this.realm = realm;
this.delegates = delegates;

View file

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

View file

@ -9,6 +9,7 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.authentication.AuthProviderConstants;
import org.keycloak.authentication.AuthenticationProviderException;
import org.keycloak.provider.ProviderSession;
/**
* AbstractModelAuthenticationProvider, which delegates authentication operations to different (external) realm
@ -17,6 +18,9 @@ import org.keycloak.authentication.AuthenticationProviderException;
*/
public class ExternalModelAuthenticationProvider extends AbstractModelAuthenticationProvider {
public ExternalModelAuthenticationProvider(ProviderSession providerSession) {
}
@Override
public String getName() {
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");
}
// TODO: This won't be needed when KeycloakSession is available from ProviderSession
KeycloakSession session = ResteasyProviderFactory.getContextData(KeycloakSession.class);
if (session == null) {
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>
<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.jboss.resteasy</groupId>

View file

@ -12,7 +12,7 @@ import org.keycloak.authentication.AuthProviderConstants;
import org.keycloak.authentication.AuthUser;
import org.keycloak.authentication.AuthenticationProvider;
import org.keycloak.authentication.AuthenticationProviderException;
import org.keycloak.picketlink.PartitionManagerProvider;
import org.keycloak.picketlink.IdentityManagerProvider;
import org.keycloak.util.ProviderLoader;
import org.picketlink.idm.IdentityManagementException;
import org.picketlink.idm.IdentityManager;
@ -32,6 +32,12 @@ public class PicketlinkAuthenticationProvider implements AuthenticationProvider
private static final Logger logger = Logger.getLogger(PicketlinkAuthenticationProvider.class);
private final IdentityManagerProvider identityManagerProvider;
public PicketlinkAuthenticationProvider(IdentityManagerProvider identityManagerProvider) {
this.identityManagerProvider = identityManagerProvider;
}
@Override
public String getName() {
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 {
IdentityManager identityManager = ResteasyProviderFactory.getContextData(IdentityManager.class);
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;
return identityManagerProvider.getIdentityManager(realm);
}
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 T create();
public T create(ProviderSession providerSession);
public void init();

View file

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

View file

@ -1,6 +1,4 @@
package org.keycloak.services;
import org.keycloak.provider.Provider;
package org.keycloak.provider;
import java.util.Set;
@ -15,6 +13,8 @@ public interface ProviderSession {
<T extends Provider> Set<String> listProviderIds(Class<T> clazz);
<T extends Provider> Set<T> getAllProviders(Class<T> clazz);
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;
/**

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_DEFAULT = String.valueOf(TimeUnit.MINUTES.toMillis(15));
public static final String PICKETLINK_PROVIDER_KEY = "keycloak.picketlink";
public static final String THEME_BASE_KEY = "keycloak.theme.base";
public static final String THEME_BASE_DEFAULT = "base";
public static final String THEME_DEFAULT_KEY = "keycloak.theme.default";
@ -68,6 +70,14 @@ public class Config {
System.setProperty(TIMER_PROVIDER_KEY, provider);
}
public static String getIdentityManagerProvider() {
return System.getProperty(PICKETLINK_PROVIDER_KEY, "realm");
}
public static void setIdentityManagerProvider(String provider) {
System.setProperty(PICKETLINK_PROVIDER_KEY, provider);
}
public static String getThemeDir() {
String themeDir = System.getProperty(THEME_DIR_KEY);
if (themeDir == null && System.getProperties().containsKey(JBOSS_SERVER_CONFIG_DIR_KEY)) {

View file

@ -65,7 +65,7 @@ public class MongoStoreImpl implements MongoStore {
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, List.class));
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;
/**
* 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>
*/

View file

@ -11,7 +11,7 @@ import java.util.Map;
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>
*/

View file

@ -7,7 +7,7 @@ package org.keycloak.models.mongo.keycloak.config;
*/
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();
public static MongoClientProvider getInstance() {

View file

@ -39,6 +39,30 @@
<version>${project.version}</version>
<scope>compile</scope>
</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>
<groupId>junit</groupId>
<artifactId>junit</artifactId>

View file

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

View file

@ -1,9 +1,9 @@
package org.keycloak.model.test;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.models.RealmModel;
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.credential.Password;
import org.picketlink.idm.model.basic.BasicModel;
@ -14,16 +14,10 @@ import org.picketlink.idm.model.basic.User;
*/
public class LdapTestUtils {
public static void setLdapPassword(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());
}
public static void setLdapPassword(ProviderSession providerSession, RealmModel realm, String username, String password) {
// Update password directly in ldap. It's workaround, but LDIF import doesn't seem to work on windows for ApacheDS
try {
IdentityManager identityManager = new PicketlinkAuthenticationProvider().getIdentityManager(realm);
IdentityManager identityManager = new PicketlinkAuthenticationProvider(providerSession.getProvider(IdentityManagerProvider.class)).getIdentityManager(realm);
User user = BasicModel.getUser(identityManager, username);
identityManager.updateCredential(user, new Password(password.toCharArray()));
} catch (Exception e) {

View file

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

View file

@ -62,7 +62,7 @@ public class AuthProvidersExternalModelTest extends AbstractModelTest {
credential.setValue("password");
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);
// 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 {
Assert.assertTrue(authProviderManager.updatePassword(john, "password-updated"));
} catch (AuthenticationProviderException ape) {

View file

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

View file

@ -1,10 +1,12 @@
package org.keycloak.picketlink.impl;
package org.keycloak.picketlink.realm;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.jboss.logging.Logger;
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.config.IdentityConfigurationBuilder;
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>model</module>
<module>integration</module>
<module>picketlink</module>
<module>services</module>
<module>social</module>
<module>forms</module>

View file

@ -152,6 +152,16 @@
<artifactId>keycloak-timer-basic</artifactId>
<version>${project.version}</version>
</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>
<groupId>junit</groupId>
<artifactId>junit</artifactId>

View file

@ -87,6 +87,12 @@
<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.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>

View file

@ -2,8 +2,10 @@ package org.keycloak.services;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.ProviderSession;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@ -29,7 +31,7 @@ public class DefaultProviderSession implements ProviderSession {
if (provider == null) {
ProviderFactory<T> providerFactory = factory.getProviderFactory(clazz, id);
if (providerFactory != null) {
provider = providerFactory.create();
provider = providerFactory.create(this);
providers.put(hash, provider);
}
}
@ -40,6 +42,16 @@ public class DefaultProviderSession implements ProviderSession {
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() {
for (Provider p : providers.values()) {
p.close();

View file

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

View file

@ -1,7 +1,7 @@
package org.keycloak.services.listeners;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.util.KeycloakRegistry;
import org.keycloak.provider.ProviderSessionFactory;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
@ -17,10 +17,13 @@ public class KeycloakSessionDestroyListener implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent sce) {
KeycloakRegistry registry = (KeycloakRegistry)sce.getServletContext().getAttribute(KeycloakRegistry.class.getName());
KeycloakSessionFactory factory = registry.getService(KeycloakSessionFactory.class);
if (factory != null) {
factory.close();
ProviderSessionFactory providerSessionFactory = (ProviderSessionFactory) sce.getServletContext().getAttribute(ProviderSessionFactory.class.getName());
KeycloakSessionFactory kcSessionFactory = (KeycloakSessionFactory) sce.getServletContext().getAttribute(KeycloakSessionFactory.class.getName());
if (providerSessionFactory != null) {
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.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.provider.ProviderSession;
import org.keycloak.representations.AccessToken;
import javax.ws.rs.BadRequestException;
@ -26,12 +27,13 @@ import java.net.URI;
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
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 TokenManager tokenManager;
public AppAuthManager(String cookieName, TokenManager tokenManager) {
public AppAuthManager(ProviderSession providerSession, String cookieName, TokenManager tokenManager) {
super(providerSession);
this.cookieName = cookieName;
this.tokenManager = tokenManager;
}

View file

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

View file

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

View file

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

View file

@ -2,20 +2,18 @@ package org.keycloak.services.resources;
import org.jboss.resteasy.logging.Logger;
import org.keycloak.audit.Audit;
import org.keycloak.audit.AuditListener;
import org.keycloak.audit.AuditProvider;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
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.AuthenticationManager;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.SocialRequestManager;
import org.keycloak.services.managers.TokenManager;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.Path;
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.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.util.LinkedList;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -70,7 +66,8 @@ public class RealmsResource {
RealmManager realmManager = new RealmManager(session);
RealmModel realm = locateRealm(name, realmManager);
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);
return tokenService;
}

View file

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

View file

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

View file

@ -21,6 +21,7 @@ import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.provider.ProviderSession;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.idm.CredentialRepresentation;
@ -79,7 +80,7 @@ public class TokenService {
protected RealmModel realm;
protected TokenManager tokenManager;
private Audit audit;
protected AuthenticationManager authManager = new AuthenticationManager();
protected AuthenticationManager authManager;
@Context
protected Providers providers;
@ -99,16 +100,19 @@ public class TokenService {
protected KeycloakTransaction transaction;
@Context
protected ClientConnection clientConnection;
@Context
protected ProviderSession providerSession;
@Context
protected ResourceContext resourceContext;
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.tokenManager = tokenManager;
this.audit = audit;
this.authManager = authManager;
}
public static UriBuilder tokenServiceBaseUrl(UriInfo uriInfo) {
@ -383,7 +387,7 @@ public class TokenService {
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
if (realm.getUser(username) != null || authenticationProviderManager.getUser(username) != null) {
@ -406,7 +410,7 @@ public class TokenService {
boolean passwordUpdateSuccessful;
String passwordUpdateError = null;
try {
passwordUpdateSuccessful = AuthenticationProviderManager.getManager(realm).updatePassword(user, formData.getFirst("password"));
passwordUpdateSuccessful = AuthenticationProviderManager.getManager(realm, providerSession).updatePassword(user, formData.getFirst("password"));
passwordUpdateError = "Password update failed";
} catch (AuthenticationProviderException ape) {
passwordUpdateSuccessful = false;

View file

@ -15,6 +15,7 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.provider.ProviderSession;
import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.Auth;
import org.keycloak.services.managers.RealmManager;
@ -69,13 +70,16 @@ public class AdminService {
@Context
protected Providers providers;
@Context
protected ProviderSession providerSession;
protected String adminPath = "/admin/index.html";
protected AppAuthManager authManager;
protected TokenManager tokenManager;
public AdminService(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) {

View file

@ -11,7 +11,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.representations.adapters.action.SessionStats;
import org.keycloak.representations.idm.RealmAuditRepresentation;
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.RealmManager;
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.freemarker.Theme;
import org.keycloak.freemarker.ThemeProvider;
import org.keycloak.services.ProviderSession;
import org.keycloak.provider.ProviderSession;
import org.keycloak.social.SocialProvider;
import org.keycloak.authentication.AuthenticationProvider;
import org.keycloak.authentication.AuthenticationProviderManager;
@ -59,7 +59,7 @@ public class ServerInfoAdminResource {
private void setAuthProviders(ServerInfoRepresentation info) {
info.authProviders = new HashMap<String, List<String>>();
Iterable<AuthenticationProvider> authProviders = AuthenticationProviderManager.load();
Iterable<AuthenticationProvider> authProviders = providers.getAllProviders(AuthenticationProvider.class);
for (AuthenticationProvider authProvider : authProviders) {
info.authProviders.put(authProvider.getName(), authProvider.getAvailableOptions());
}

View file

@ -170,6 +170,16 @@
<artifactId>keycloak-authentication-model</artifactId>
<version>${project.version}</version>
</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>
<groupId>org.jboss.logging</groupId>
@ -186,7 +196,7 @@
</dependency>
<dependency>
<groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-impl</artifactId>
<artifactId>picketlink-idm-idm</artifactId>
</dependency>
<dependency>
<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.spi.ResteasyDeployment;
import org.keycloak.models.Config;
import org.keycloak.provider.ProviderSessionFactory;
import org.keycloak.services.filters.ClientConnectionFilter;
import org.keycloak.theme.DefaultLoginThemeProvider;
import org.keycloak.services.tmp.TmpAdminRedirectServlet;
@ -173,6 +174,8 @@ public class KeycloakServer {
private KeycloakSessionFactory factory;
private ProviderSessionFactory providerSessionFactory;
private UndertowJaxrsServer server;
public KeycloakServer() {
@ -187,6 +190,10 @@ public class KeycloakServer {
return factory;
}
public ProviderSessionFactory getProviderSessionFactory() {
return providerSessionFactory;
}
public UndertowJaxrsServer getServer() {
return server;
}
@ -275,6 +282,7 @@ public class KeycloakServer {
server.deploy(di);
factory = ((KeycloakApplication) deployment.getApplication()).getFactory();
providerSessionFactory = ((KeycloakApplication) deployment.getApplication()).getProviderSessionFactory();
setupDevConfig();
@ -295,6 +303,7 @@ public class KeycloakServer {
}
public void stop() {
providerSessionFactory.close();
factory.close();
server.stop();

View file

@ -16,6 +16,7 @@ import org.keycloak.models.ClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.provider.ProviderSession;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.rule.KeycloakRule;
@ -165,7 +166,7 @@ public class AssertEvents implements TestRule, AuditListenerFactory {
}
@Override
public AuditListener create() {
public AuditListener create(ProviderSession providerSession) {
return new AuditListener() {
@Override
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.LoginPage;
import org.keycloak.testsuite.pages.RegisterPage;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
import org.keycloak.testsuite.rule.KeycloakRule;
import org.keycloak.testsuite.rule.LDAPRule;
import org.keycloak.testsuite.rule.WebResource;
@ -62,7 +63,7 @@ public class AuthProvidersIntegrationTest {
// Configure LDAP
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.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.provider.ProviderSession;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.ApplicationServlet;
@ -58,6 +59,7 @@ public class KeycloakRule extends AbstractKeycloakRule {
public void configure(KeycloakSetup configurer) {
KeycloakSession session = server.getKeycloakSessionFactory().createSession();
ProviderSession providerSession = server.getProviderSessionFactory().createSession();
session.getTransaction().begin();
try {
@ -66,17 +68,21 @@ public class KeycloakRule extends AbstractKeycloakRule {
RealmModel adminstrationRealm = manager.getRealm(Config.getAdminRealm());
RealmModel appRealm = manager.getRealm("test");
configurer.providerSession = providerSession;
configurer.config(manager, adminstrationRealm, appRealm);
session.getTransaction().commit();
} finally {
providerSession.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>
<groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-impl</artifactId>
<artifactId>picketlink-idm-idm</artifactId>
<version>${picketlink.version}</version>
</dependency>
<dependency>

View file

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