diff --git a/audit/jboss-logging/src/main/java/org/keycloak/audit/log/JBossLoggingAuditListenerFactory.java b/audit/jboss-logging/src/main/java/org/keycloak/audit/log/JBossLoggingAuditListenerFactory.java index 62322fb9b6..1f936afce4 100644 --- a/audit/jboss-logging/src/main/java/org/keycloak/audit/log/JBossLoggingAuditListenerFactory.java +++ b/audit/jboss-logging/src/main/java/org/keycloak/audit/log/JBossLoggingAuditListenerFactory.java @@ -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 Stian Thorgersen @@ -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); } diff --git a/audit/jpa/src/main/java/org/keycloak/audit/jpa/JpaAuditProviderFactory.java b/audit/jpa/src/main/java/org/keycloak/audit/jpa/JpaAuditProviderFactory.java index bce26eecc2..c7d7a1a96f 100644 --- a/audit/jpa/src/main/java/org/keycloak/audit/jpa/JpaAuditProviderFactory.java +++ b/audit/jpa/src/main/java/org/keycloak/audit/jpa/JpaAuditProviderFactory.java @@ -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()); } diff --git a/audit/mongo/src/main/java/org/keycloak/audit/mongo/MongoAuditProviderFactory.java b/audit/mongo/src/main/java/org/keycloak/audit/mongo/MongoAuditProviderFactory.java index 7d84b265a8..8f78fb4371 100644 --- a/audit/mongo/src/main/java/org/keycloak/audit/mongo/MongoAuditProviderFactory.java +++ b/audit/mongo/src/main/java/org/keycloak/audit/mongo/MongoAuditProviderFactory.java @@ -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")); } diff --git a/audit/tests/src/main/java/org/keycloak/audit/tests/AbstractAuditProviderTest.java b/audit/tests/src/main/java/org/keycloak/audit/tests/AbstractAuditProviderTest.java index 7dada9f806..7b53b75622 100644 --- a/audit/tests/src/main/java/org/keycloak/audit/tests/AbstractAuditProviderTest.java +++ b/audit/tests/src/main/java/org/keycloak/audit/tests/AbstractAuditProviderTest.java @@ -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); diff --git a/authentication/authentication-api/src/main/java/org/keycloak/authentication/AuthenticationProvider.java b/authentication/authentication-api/src/main/java/org/keycloak/authentication/AuthenticationProvider.java index dab3e8b737..542c994d10 100644 --- a/authentication/authentication-api/src/main/java/org/keycloak/authentication/AuthenticationProvider.java +++ b/authentication/authentication-api/src/main/java/org/keycloak/authentication/AuthenticationProvider.java @@ -4,11 +4,12 @@ import java.util.List; import java.util.Map; import org.keycloak.models.RealmModel; +import org.keycloak.provider.Provider; /** * @author Marek Posolda */ -public interface AuthenticationProvider { +public interface AuthenticationProvider extends Provider { String getName(); diff --git a/authentication/authentication-api/src/main/java/org/keycloak/authentication/AuthenticationProviderFactory.java b/authentication/authentication-api/src/main/java/org/keycloak/authentication/AuthenticationProviderFactory.java new file mode 100644 index 0000000000..b0d203fdea --- /dev/null +++ b/authentication/authentication-api/src/main/java/org/keycloak/authentication/AuthenticationProviderFactory.java @@ -0,0 +1,9 @@ +package org.keycloak.authentication; + +import org.keycloak.provider.ProviderFactory; + +/** + * @author Marek Posolda + */ +public interface AuthenticationProviderFactory extends ProviderFactory { +} diff --git a/authentication/authentication-api/src/main/java/org/keycloak/authentication/AuthenticationProviderManager.java b/authentication/authentication-api/src/main/java/org/keycloak/authentication/AuthenticationProviderManager.java index 036a7b8641..6b6c56bab2 100644 --- a/authentication/authentication-api/src/main/java/org/keycloak/authentication/AuthenticationProviderManager.java +++ b/authentication/authentication-api/src/main/java/org/keycloak/authentication/AuthenticationProviderManager.java @@ -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 delegates; - public static AuthenticationProviderManager getManager(RealmModel realm) { - Iterable providers = load(); + public static AuthenticationProviderManager getManager(RealmModel realm, ProviderSession providerSession) { + Iterable providers = providerSession.getAllProviders(AuthenticationProvider.class); Map providersMap = new HashMap(); for (AuthenticationProvider provider : providers) { @@ -38,10 +39,6 @@ public class AuthenticationProviderManager { return new AuthenticationProviderManager(realm, providersMap); } - public static Iterable load() { - return ProviderLoader.load(AuthenticationProvider.class); - } - public AuthenticationProviderManager(RealmModel realm, Map delegates) { this.realm = realm; this.delegates = delegates; diff --git a/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/AbstractModelAuthenticationProvider.java b/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/AbstractModelAuthenticationProvider.java index d96bbeb22a..5c6b834458 100644 --- a/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/AbstractModelAuthenticationProvider.java +++ b/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/AbstractModelAuthenticationProvider.java @@ -70,6 +70,10 @@ public abstract class AbstractModelAuthenticationProvider implements Authenticat return true; } + @Override + public void close() { + } + protected abstract RealmModel getRealm(RealmModel currentRealm, Map config) throws AuthenticationProviderException; protected AuthUser createAuthenticatedUserInstance(UserModel user) { diff --git a/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/ExternalModelAuthenticationProvider.java b/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/ExternalModelAuthenticationProvider.java index d6f74f75e2..2ff83b0bf7 100644 --- a/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/ExternalModelAuthenticationProvider.java +++ b/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/ExternalModelAuthenticationProvider.java @@ -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"); diff --git a/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/ExternalModelAuthenticationProviderFactory.java b/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/ExternalModelAuthenticationProviderFactory.java new file mode 100644 index 0000000000..3f58d4e33d --- /dev/null +++ b/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/ExternalModelAuthenticationProviderFactory.java @@ -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 Marek Posolda + */ +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; + } +} diff --git a/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/ModelAuthenticationProviderFactory.java b/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/ModelAuthenticationProviderFactory.java new file mode 100644 index 0000000000..8b9e6c1666 --- /dev/null +++ b/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/ModelAuthenticationProviderFactory.java @@ -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 Marek Posolda + */ +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; + } +} diff --git a/authentication/authentication-model/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticationProvider b/authentication/authentication-model/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticationProvider deleted file mode 100644 index beccb464a1..0000000000 --- a/authentication/authentication-model/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticationProvider +++ /dev/null @@ -1,2 +0,0 @@ -org.keycloak.authentication.model.ModelAuthenticationProvider -org.keycloak.authentication.model.ExternalModelAuthenticationProvider \ No newline at end of file diff --git a/authentication/authentication-model/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticationProviderFactory b/authentication/authentication-model/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticationProviderFactory new file mode 100644 index 0000000000..b65d4712b0 --- /dev/null +++ b/authentication/authentication-model/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticationProviderFactory @@ -0,0 +1,2 @@ +org.keycloak.authentication.model.ModelAuthenticationProviderFactory +org.keycloak.authentication.model.ExternalModelAuthenticationProviderFactory \ No newline at end of file diff --git a/authentication/authentication-picketlink/pom.xml b/authentication/authentication-picketlink/pom.xml index 4255d3d081..748c99d220 100644 --- a/authentication/authentication-picketlink/pom.xml +++ b/authentication/authentication-picketlink/pom.xml @@ -31,6 +31,12 @@ ${project.version} provided + + org.keycloak + keycloak-picketlink-api + ${project.version} + provided + org.jboss.resteasy diff --git a/authentication/authentication-picketlink/src/main/java/org/keycloak/authentication/picketlink/PicketlinkAuthenticationProvider.java b/authentication/authentication-picketlink/src/main/java/org/keycloak/authentication/picketlink/PicketlinkAuthenticationProvider.java index 7d4d561120..0027be6fdd 100755 --- a/authentication/authentication-picketlink/src/main/java/org/keycloak/authentication/picketlink/PicketlinkAuthenticationProvider.java +++ b/authentication/authentication-picketlink/src/main/java/org/keycloak/authentication/picketlink/PicketlinkAuthenticationProvider.java @@ -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 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) { diff --git a/authentication/authentication-picketlink/src/main/java/org/keycloak/authentication/picketlink/PicketlinkAuthenticationProviderFactory.java b/authentication/authentication-picketlink/src/main/java/org/keycloak/authentication/picketlink/PicketlinkAuthenticationProviderFactory.java new file mode 100644 index 0000000000..db1ece3e0f --- /dev/null +++ b/authentication/authentication-picketlink/src/main/java/org/keycloak/authentication/picketlink/PicketlinkAuthenticationProviderFactory.java @@ -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 Marek Posolda + */ +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; + } +} diff --git a/authentication/authentication-picketlink/src/main/java/org/keycloak/picketlink/PartitionManagerProvider.java b/authentication/authentication-picketlink/src/main/java/org/keycloak/picketlink/PartitionManagerProvider.java deleted file mode 100644 index a8350195f3..0000000000 --- a/authentication/authentication-picketlink/src/main/java/org/keycloak/picketlink/PartitionManagerProvider.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.keycloak.picketlink; - -import org.keycloak.models.RealmModel; -import org.picketlink.idm.PartitionManager; - -/** - * @author Marek Posolda - */ -public interface PartitionManagerProvider { - - PartitionManager getPartitionManager(RealmModel realm); -} diff --git a/authentication/authentication-picketlink/src/main/java/org/keycloak/picketlink/impl/RealmPartitionManagerProvider.java b/authentication/authentication-picketlink/src/main/java/org/keycloak/picketlink/impl/RealmPartitionManagerProvider.java deleted file mode 100644 index 99431d37b2..0000000000 --- a/authentication/authentication-picketlink/src/main/java/org/keycloak/picketlink/impl/RealmPartitionManagerProvider.java +++ /dev/null @@ -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 Marek Posolda - */ -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); - } -} diff --git a/authentication/authentication-picketlink/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticationProvider b/authentication/authentication-picketlink/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticationProviderFactory similarity index 82% rename from authentication/authentication-picketlink/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticationProvider rename to authentication/authentication-picketlink/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticationProviderFactory index f737b8a3bf..b12d76700d 100644 --- a/authentication/authentication-picketlink/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticationProvider +++ b/authentication/authentication-picketlink/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticationProviderFactory @@ -1 +1 @@ -org.keycloak.authentication.picketlink.PicketlinkAuthenticationProvider \ No newline at end of file +org.keycloak.authentication.picketlink.PicketlinkAuthenticationProviderFactory \ No newline at end of file diff --git a/authentication/authentication-picketlink/src/main/resources/META-INF/services/org.keycloak.picketlink.PartitionManagerProvider b/authentication/authentication-picketlink/src/main/resources/META-INF/services/org.keycloak.picketlink.PartitionManagerProvider deleted file mode 100644 index 7a424d0325..0000000000 --- a/authentication/authentication-picketlink/src/main/resources/META-INF/services/org.keycloak.picketlink.PartitionManagerProvider +++ /dev/null @@ -1 +0,0 @@ -org.keycloak.picketlink.impl.RealmPartitionManagerProvider \ No newline at end of file diff --git a/core/src/main/java/org/keycloak/provider/ProviderFactory.java b/core/src/main/java/org/keycloak/provider/ProviderFactory.java index ca8a19b83b..996d2c5356 100644 --- a/core/src/main/java/org/keycloak/provider/ProviderFactory.java +++ b/core/src/main/java/org/keycloak/provider/ProviderFactory.java @@ -5,7 +5,7 @@ package org.keycloak.provider; */ public interface ProviderFactory { - public T create(); + public T create(ProviderSession providerSession); public void init(); diff --git a/core/src/main/java/org/keycloak/provider/ProviderFactoryLoader.java b/core/src/main/java/org/keycloak/provider/ProviderFactoryLoader.java index fdbb171f56..798a88cc7c 100644 --- a/core/src/main/java/org/keycloak/provider/ProviderFactoryLoader.java +++ b/core/src/main/java/org/keycloak/provider/ProviderFactoryLoader.java @@ -68,12 +68,12 @@ public class ProviderFactoryLoader implements Iterable implements Iterable Set listProviderIds(Class clazz); + Set getAllProviders(Class clazz); + void close(); } diff --git a/services/src/main/java/org/keycloak/services/ProviderSessionFactory.java b/core/src/main/java/org/keycloak/provider/ProviderSessionFactory.java similarity index 65% rename from services/src/main/java/org/keycloak/services/ProviderSessionFactory.java rename to core/src/main/java/org/keycloak/provider/ProviderSessionFactory.java index a1c5707e29..2e347dfc15 100755 --- a/services/src/main/java/org/keycloak/services/ProviderSessionFactory.java +++ b/core/src/main/java/org/keycloak/provider/ProviderSessionFactory.java @@ -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; /** diff --git a/core/src/main/java/org/keycloak/util/KeycloakRegistry.java b/core/src/main/java/org/keycloak/util/KeycloakRegistry.java deleted file mode 100644 index 7a9c98230d..0000000000 --- a/core/src/main/java/org/keycloak/util/KeycloakRegistry.java +++ /dev/null @@ -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 Marek Posolda - */ -public class KeycloakRegistry { - - private final ConcurrentMap, Object> services = new ConcurrentHashMap, Object>(); - - public void putService(Class type, T object) { - services.put(type, object); - } - - public T putServiceIfAbsent(Class 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 getService(Class type) { - return (T) services.get(type); - } -} diff --git a/model/api/src/main/java/org/keycloak/models/Config.java b/model/api/src/main/java/org/keycloak/models/Config.java index 17ff238285..25f5332fc4 100644 --- a/model/api/src/main/java/org/keycloak/models/Config.java +++ b/model/api/src/main/java/org/keycloak/models/Config.java @@ -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)) { diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/MongoStoreImpl.java b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/MongoStoreImpl.java index 4d59598fba..654b7238ac 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/impl/MongoStoreImpl.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/impl/MongoStoreImpl.java @@ -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)); diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java index 57ecc660f0..14cd478b3d 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java @@ -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 Marek Posolda */ diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java index 8958e32afd..3ae2502717 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java @@ -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 Marek Posolda */ diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/MongoClientProviderHolder.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/MongoClientProviderHolder.java index 4c3eeae3f6..038e805c4d 100644 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/MongoClientProviderHolder.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/config/MongoClientProviderHolder.java @@ -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() { diff --git a/model/tests/pom.xml b/model/tests/pom.xml index 34de1ccd88..99f567e430 100755 --- a/model/tests/pom.xml +++ b/model/tests/pom.xml @@ -39,6 +39,30 @@ ${project.version} compile + + org.keycloak + keycloak-picketlink-api + ${project.version} + compile + + + org.keycloak + keycloak-picketlink-realm + ${project.version} + compile + + + org.keycloak + keycloak-timer-api + ${project.version} + compile + + + org.keycloak + keycloak-timer-basic + ${project.version} + compile + junit junit diff --git a/model/tests/src/main/java/org/keycloak/model/test/LDAPEmbeddedServer.java b/model/tests/src/main/java/org/keycloak/model/test/LDAPEmbeddedServer.java index 7356ef9441..44a172a2e5 100644 --- a/model/tests/src/main/java/org/keycloak/model/test/LDAPEmbeddedServer.java +++ b/model/tests/src/main/java/org/keycloak/model/test/LDAPEmbeddedServer.java @@ -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; /** diff --git a/model/tests/src/main/java/org/keycloak/model/test/LdapTestUtils.java b/model/tests/src/main/java/org/keycloak/model/test/LdapTestUtils.java index 55990fe73f..ac956dbe60 100644 --- a/model/tests/src/main/java/org/keycloak/model/test/LdapTestUtils.java +++ b/model/tests/src/main/java/org/keycloak/model/test/LdapTestUtils.java @@ -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) { diff --git a/model/tests/src/test/java/org/keycloak/model/test/AbstractModelTest.java b/model/tests/src/test/java/org/keycloak/model/test/AbstractModelTest.java index 072944a7f1..cdd802484d 100644 --- a/model/tests/src/test/java/org/keycloak/model/test/AbstractModelTest.java +++ b/model/tests/src/test/java/org/keycloak/model/test/AbstractModelTest.java @@ -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(); } diff --git a/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersExternalModelTest.java b/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersExternalModelTest.java index 06173686cb..1311440c10 100755 --- a/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersExternalModelTest.java +++ b/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersExternalModelTest.java @@ -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) { diff --git a/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersLDAPTest.java b/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersLDAPTest.java index 4d63a67d45..dae3862317 100755 --- a/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersLDAPTest.java +++ b/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersLDAPTest.java @@ -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 Marek Posolda @@ -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,78 +69,64 @@ public class AuthProvidersLDAPTest extends AbstractModelTest { public void testLdapAuthentication() { MultivaluedMap 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(providerSession, realm, "john", "password"); - // Set password of user in LDAP - LdapTestUtils.setLdapPassword(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)); + Assert.assertNull(realm.getUser("john")); - // 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.assertNull(realm.getUser("john")); + // Add ldap authenticationProvider + setupAuthenticationProviders(); - // Add ldap authenticationProvider - setupAuthenticationProviders(); - - // Authenticate john and verify that now he exists in realm - Assert.assertEquals(AuthenticationManager.AuthenticationStatus.SUCCESS, am.authenticateForm(null, realm, formData)); - UserModel john = realm.getUser("john"); - Assert.assertNotNull(john); - Assert.assertEquals("john", john.getLoginName()); - Assert.assertEquals("John", john.getFirstName()); - Assert.assertEquals("Doe", john.getLastName()); - Assert.assertEquals("john@email.org", john.getEmail()); - - // Verify link exists - AuthenticationLinkModel authLink = realm.getAuthenticationLink(john); - Assert.assertNotNull(authLink); - Assert.assertEquals(authLink.getAuthProvider(), AuthProviderConstants.PROVIDER_NAME_PICKETLINK); - } finally { - ResteasyProviderFactory.clearContextData(); - } + // Authenticate john and verify that now he exists in realm + Assert.assertEquals(AuthenticationManager.AuthenticationStatus.SUCCESS, am.authenticateForm(null, realm, formData)); + UserModel john = realm.getUser("john"); + Assert.assertNotNull(john); + Assert.assertEquals("john", john.getLoginName()); + Assert.assertEquals("John", john.getFirstName()); + Assert.assertEquals("Doe", john.getLastName()); + Assert.assertEquals("john@email.org", john.getEmail()); + // Verify link exists + AuthenticationLinkModel authLink = realm.getAuthenticationLink(john); + Assert.assertNotNull(authLink); + Assert.assertEquals(authLink.getAuthProvider(), AuthProviderConstants.PROVIDER_NAME_PICKETLINK); } @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); + UserCredentialModel credential = new UserCredentialModel(); + credential.setType(CredentialRepresentation.PASSWORD); + credential.setValue("pass"); + realm.updateCredential(realmUser, credential); - // Add some user and password to realm - UserModel realmUser = realm.addUser("realmUser"); - realmUser.setEnabled(true); - UserCredentialModel credential = new UserCredentialModel(); - credential.setType(CredentialRepresentation.PASSWORD); - credential.setValue("pass"); - realm.updateCredential(realmUser, credential); + // User doesn't exists + MultivaluedMap formData = AuthProvidersExternalModelTest.createFormData("invalid", "invalid"); + Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_USER, am.authenticateForm(null, realm, formData)); - // User doesn't exists - MultivaluedMap formData = AuthProvidersExternalModelTest.createFormData("invalid", "invalid"); - Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_USER, am.authenticateForm(null, realm, formData)); + // User exists in ldap + formData = AuthProvidersExternalModelTest.createFormData("john", "invalid"); + Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_CREDENTIALS, am.authenticateForm(null, realm, formData)); - // User exists in ldap - formData = AuthProvidersExternalModelTest.createFormData("john", "invalid"); - Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_CREDENTIALS, am.authenticateForm(null, realm, formData)); + // User exists in realm + formData = AuthProvidersExternalModelTest.createFormData("realmUser", "invalid"); + Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_CREDENTIALS, am.authenticateForm(null, realm, formData)); - // User exists in realm - formData = AuthProvidersExternalModelTest.createFormData("realmUser", "invalid"); - Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_CREDENTIALS, am.authenticateForm(null, realm, formData)); + // User disabled + realmUser.setEnabled(false); + formData = AuthProvidersExternalModelTest.createFormData("realmUser", "pass"); + Assert.assertEquals(AuthenticationManager.AuthenticationStatus.ACCOUNT_DISABLED, am.authenticateForm(null, realm, formData)); - // User disabled - realmUser.setEnabled(false); - formData = AuthProvidersExternalModelTest.createFormData("realmUser", "pass"); - Assert.assertEquals(AuthenticationManager.AuthenticationStatus.ACCOUNT_DISABLED, am.authenticateForm(null, realm, formData)); - - // Successful authentication - realmUser.setEnabled(true); - formData = AuthProvidersExternalModelTest.createFormData("realmUser", "pass"); - Assert.assertEquals(AuthenticationManager.AuthenticationStatus.SUCCESS, am.authenticateForm(null, realm, formData)); - } finally { - ResteasyProviderFactory.clearContextData(); - } + // Successful authentication + realmUser.setEnabled(true); + formData = AuthProvidersExternalModelTest.createFormData("realmUser", "pass"); + Assert.assertEquals(AuthenticationManager.AuthenticationStatus.SUCCESS, am.authenticateForm(null, realm, formData)); } @Test @@ -149,47 +134,40 @@ public class AuthProvidersLDAPTest extends AbstractModelTest { // Add ldap setupAuthenticationProviders(); + LdapTestUtils.setLdapPassword(providerSession, realm, "john", "password"); + + // First authenticate successfully to sync john into realm + MultivaluedMap 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, providerSession); + + UserModel john = realm.getUser("john"); try { - // 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 - MultivaluedMap 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); - - UserModel john = realm.getUser("john"); - try { - Assert.assertTrue(authProviderManager.updatePassword(john, "password-updated")); - } catch (AuthenticationProviderException ape) { - ape.printStackTrace(); - Assert.fail("Error not expected"); - } - formData = AuthProvidersExternalModelTest.createFormData("john", "password-updated"); - Assert.assertEquals(AuthenticationManager.AuthenticationStatus.SUCCESS, am.authenticateForm(null, realm, formData)); - - // Password updated just in LDAP, so validating directly in realm should fail - Assert.assertFalse(realm.validatePassword(john, "password-updated")); - - // Switch to not allow updating passwords in ldap - AuthProvidersExternalModelTest.setPasswordUpdateForProvider(false, AuthProviderConstants.PROVIDER_NAME_PICKETLINK, realm); - - // Change credential and validate that password is not updated - try { - Assert.assertFalse(authProviderManager.updatePassword(john, "password-updated2")); - } catch (AuthenticationProviderException ape) { - ape.printStackTrace(); - Assert.fail("Error not expected"); - } - formData = AuthProvidersExternalModelTest.createFormData("john", "password-updated2"); - Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_CREDENTIALS, am.authenticateForm(null, realm, formData)); - } finally { - ResteasyProviderFactory.clearContextData(); + Assert.assertTrue(authProviderManager.updatePassword(john, "password-updated")); + } catch (AuthenticationProviderException ape) { + ape.printStackTrace(); + Assert.fail("Error not expected"); } + formData = AuthProvidersExternalModelTest.createFormData("john", "password-updated"); + Assert.assertEquals(AuthenticationManager.AuthenticationStatus.SUCCESS, am.authenticateForm(null, realm, formData)); + + // Password updated just in LDAP, so validating directly in realm should fail + Assert.assertFalse(realm.validatePassword(john, "password-updated")); + + // Switch to not allow updating passwords in ldap + AuthProvidersExternalModelTest.setPasswordUpdateForProvider(false, AuthProviderConstants.PROVIDER_NAME_PICKETLINK, realm); + + // Change credential and validate that password is not updated + try { + Assert.assertFalse(authProviderManager.updatePassword(john, "password-updated2")); + } catch (AuthenticationProviderException ape) { + ape.printStackTrace(); + Assert.fail("Error not expected"); + } + formData = AuthProvidersExternalModelTest.createFormData("john", "password-updated2"); + Assert.assertEquals(AuthenticationManager.AuthenticationStatus.INVALID_CREDENTIALS, am.authenticateForm(null, realm, formData)); } /** diff --git a/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java b/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java index 6c1cece290..533837c1f1 100755 --- a/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java +++ b/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java @@ -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); diff --git a/picketlink/keycloak-picketlink-api/pom.xml b/picketlink/keycloak-picketlink-api/pom.xml new file mode 100644 index 0000000000..b23e616988 --- /dev/null +++ b/picketlink/keycloak-picketlink-api/pom.xml @@ -0,0 +1,55 @@ + + + + keycloak-picketlink + org.keycloak + 1.0-beta-1-SNAPSHOT + ../pom.xml + + 4.0.0 + + keycloak-picketlink-api + Keycloak Picketlink API + + + + + org.keycloak + keycloak-core + ${project.version} + provided + + + org.keycloak + keycloak-model-api + ${project.version} + provided + + + org.picketlink + picketlink-idm-api + provided + + + org.jboss.logging + jboss-logging + provided + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + diff --git a/picketlink/keycloak-picketlink-api/src/main/java/org/keycloak/picketlink/IdentityManagerProvider.java b/picketlink/keycloak-picketlink-api/src/main/java/org/keycloak/picketlink/IdentityManagerProvider.java new file mode 100644 index 0000000000..4b9ec6e3dd --- /dev/null +++ b/picketlink/keycloak-picketlink-api/src/main/java/org/keycloak/picketlink/IdentityManagerProvider.java @@ -0,0 +1,13 @@ +package org.keycloak.picketlink; + +import org.keycloak.models.RealmModel; +import org.keycloak.provider.Provider; +import org.picketlink.idm.IdentityManager; + +/** + * @author Marek Posolda + */ +public interface IdentityManagerProvider extends Provider { + + IdentityManager getIdentityManager(RealmModel realm); +} diff --git a/picketlink/keycloak-picketlink-api/src/main/java/org/keycloak/picketlink/IdentityManagerProviderFactory.java b/picketlink/keycloak-picketlink-api/src/main/java/org/keycloak/picketlink/IdentityManagerProviderFactory.java new file mode 100644 index 0000000000..1456e98e09 --- /dev/null +++ b/picketlink/keycloak-picketlink-api/src/main/java/org/keycloak/picketlink/IdentityManagerProviderFactory.java @@ -0,0 +1,9 @@ +package org.keycloak.picketlink; + +import org.keycloak.provider.ProviderFactory; + +/** + * @author Marek Posolda + */ +public interface IdentityManagerProviderFactory extends ProviderFactory { +} diff --git a/picketlink/keycloak-picketlink-realm/pom.xml b/picketlink/keycloak-picketlink-realm/pom.xml new file mode 100644 index 0000000000..e82acb1b6f --- /dev/null +++ b/picketlink/keycloak-picketlink-realm/pom.xml @@ -0,0 +1,66 @@ + + + + keycloak-picketlink + org.keycloak + 1.0-beta-1-SNAPSHOT + ../pom.xml + + 4.0.0 + + keycloak-picketlink-realm + Keycloak Picketlink Realm + + + + + org.keycloak + keycloak-core + ${project.version} + provided + + + org.keycloak + keycloak-model-api + ${project.version} + provided + + + org.keycloak + keycloak-picketlink-api + ${project.version} + provided + + + org.picketlink + picketlink-idm-api + provided + + + org.picketlink + picketlink-idm-impl + provided + + + org.jboss.logging + jboss-logging + provided + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + diff --git a/authentication/authentication-picketlink/src/main/java/org/keycloak/picketlink/impl/LDAPAgentIgnoreCredentialHandler.java b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/LDAPAgentIgnoreCredentialHandler.java similarity index 96% rename from authentication/authentication-picketlink/src/main/java/org/keycloak/picketlink/impl/LDAPAgentIgnoreCredentialHandler.java rename to picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/LDAPAgentIgnoreCredentialHandler.java index f89f6e804d..4bbc73b1bd 100644 --- a/authentication/authentication-picketlink/src/main/java/org/keycloak/picketlink/impl/LDAPAgentIgnoreCredentialHandler.java +++ b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/LDAPAgentIgnoreCredentialHandler.java @@ -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; diff --git a/authentication/authentication-picketlink/src/main/java/org/keycloak/picketlink/impl/LdapConstants.java b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/LdapConstants.java similarity index 91% rename from authentication/authentication-picketlink/src/main/java/org/keycloak/picketlink/impl/LdapConstants.java rename to picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/LdapConstants.java index 7c8007180e..d7fbd12d0d 100644 --- a/authentication/authentication-picketlink/src/main/java/org/keycloak/picketlink/impl/LdapConstants.java +++ b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/idm/LdapConstants.java @@ -1,4 +1,4 @@ -package org.keycloak.picketlink.impl; +package org.keycloak.picketlink.idm; /** * @author Marek Posolda diff --git a/authentication/authentication-picketlink/src/main/java/org/keycloak/picketlink/impl/PartitionManagerRegistry.java b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/realm/PartitionManagerRegistry.java similarity index 96% rename from authentication/authentication-picketlink/src/main/java/org/keycloak/picketlink/impl/PartitionManagerRegistry.java rename to picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/realm/PartitionManagerRegistry.java index 0f1c0d6585..b6a5b7bd45 100644 --- a/authentication/authentication-picketlink/src/main/java/org/keycloak/picketlink/impl/PartitionManagerRegistry.java +++ b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/realm/PartitionManagerRegistry.java @@ -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; diff --git a/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/realm/RealmIdentityManagerProvider.java b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/realm/RealmIdentityManagerProvider.java new file mode 100644 index 0000000000..3c00489c30 --- /dev/null +++ b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/realm/RealmIdentityManagerProvider.java @@ -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 Marek Posolda + */ +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() { + } +} diff --git a/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/realm/RealmIdentityManagerProviderFactory.java b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/realm/RealmIdentityManagerProviderFactory.java new file mode 100644 index 0000000000..83b5970816 --- /dev/null +++ b/picketlink/keycloak-picketlink-realm/src/main/java/org/keycloak/picketlink/realm/RealmIdentityManagerProviderFactory.java @@ -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 Marek Posolda + */ +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; + } +} diff --git a/picketlink/keycloak-picketlink-realm/src/main/resources/META-INF/services/org.keycloak.picketlink.IdentityManagerProviderFactory b/picketlink/keycloak-picketlink-realm/src/main/resources/META-INF/services/org.keycloak.picketlink.IdentityManagerProviderFactory new file mode 100644 index 0000000000..87130cbf8b --- /dev/null +++ b/picketlink/keycloak-picketlink-realm/src/main/resources/META-INF/services/org.keycloak.picketlink.IdentityManagerProviderFactory @@ -0,0 +1 @@ +org.keycloak.picketlink.realm.RealmIdentityManagerProviderFactory \ No newline at end of file diff --git a/picketlink/pom.xml b/picketlink/pom.xml new file mode 100644 index 0000000000..2917578542 --- /dev/null +++ b/picketlink/pom.xml @@ -0,0 +1,24 @@ + + + + keycloak-parent + org.keycloak + 1.0-beta-1-SNAPSHOT + ../pom.xml + + 4.0.0 + pom + + keycloak-picketlink + Keycloak Picketlink + + + + keycloak-picketlink-api + keycloak-picketlink-realm + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 47110d19a6..e0553b7aea 100755 --- a/pom.xml +++ b/pom.xml @@ -91,6 +91,7 @@ core-jaxrs model integration + picketlink services social forms diff --git a/server/pom.xml b/server/pom.xml index 972802a0c6..9cd98b6053 100755 --- a/server/pom.xml +++ b/server/pom.xml @@ -152,6 +152,16 @@ keycloak-timer-basic ${project.version} + + org.keycloak + keycloak-picketlink-api + ${project.version} + + + org.keycloak + keycloak-picketlink-realm + ${project.version} + junit junit diff --git a/services/pom.xml b/services/pom.xml index 9615528e79..03ff09f3e5 100755 --- a/services/pom.xml +++ b/services/pom.xml @@ -87,6 +87,12 @@ ${project.version} provided + + org.keycloak + keycloak-picketlink-api + ${project.version} + provided + org.jboss.logging jboss-logging diff --git a/services/src/main/java/org/keycloak/services/DefaultProviderSession.java b/services/src/main/java/org/keycloak/services/DefaultProviderSession.java index f9e2948b3e..cd6a9c92a4 100755 --- a/services/src/main/java/org/keycloak/services/DefaultProviderSession.java +++ b/services/src/main/java/org/keycloak/services/DefaultProviderSession.java @@ -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 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 Set getAllProviders(Class clazz) { + Set providerIds = listProviderIds(clazz); + Set providers = new HashSet(); + for (String providerId : providerIds) { + providers.add(getProvider(clazz, providerId)); + } + return providers; + } + public void close() { for (Provider p : providers.values()) { p.close(); diff --git a/services/src/main/java/org/keycloak/services/DefaultProviderSessionFactory.java b/services/src/main/java/org/keycloak/services/DefaultProviderSessionFactory.java index 67285593e3..fbc0993c06 100755 --- a/services/src/main/java/org/keycloak/services/DefaultProviderSessionFactory.java +++ b/services/src/main/java/org/keycloak/services/DefaultProviderSessionFactory.java @@ -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; diff --git a/services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java b/services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java index 54338ca3cf..97a5f0f9c0 100755 --- a/services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java +++ b/services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java @@ -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); diff --git a/services/src/main/java/org/keycloak/services/listeners/KeycloakSessionDestroyListener.java b/services/src/main/java/org/keycloak/services/listeners/KeycloakSessionDestroyListener.java index b5fc31dfac..7825c04027 100644 --- a/services/src/main/java/org/keycloak/services/listeners/KeycloakSessionDestroyListener.java +++ b/services/src/main/java/org/keycloak/services/listeners/KeycloakSessionDestroyListener.java @@ -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(); } } diff --git a/services/src/main/java/org/keycloak/services/managers/AppAuthManager.java b/services/src/main/java/org/keycloak/services/managers/AppAuthManager.java index e9e3a1d493..ae4f40d97b 100755 --- a/services/src/main/java/org/keycloak/services/managers/AppAuthManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AppAuthManager.java @@ -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 Stian Thorgersen */ 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; } diff --git a/services/src/main/java/org/keycloak/services/managers/AuditManager.java b/services/src/main/java/org/keycloak/services/managers/AuditManager.java index ae90e1c6d3..25ae718f55 100644 --- a/services/src/main/java/org/keycloak/services/managers/AuditManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuditManager.java @@ -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; diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java index 04b954b8de..7852781f3f 100755 --- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java @@ -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 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; diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java index 022db5cd6e..a5e12e1253 100755 --- a/services/src/main/java/org/keycloak/services/resources/AccountService.java +++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java @@ -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) { diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java index 865be1dd5b..392fd70897 100755 --- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java +++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java @@ -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> classes = new HashSet>(); 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 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> getClasses() { return classes; diff --git a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java index 1056378c75..b9447185aa 100755 --- a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java +++ b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java @@ -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 Bill Burke @@ -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; } diff --git a/services/src/main/java/org/keycloak/services/resources/RequiredActionsService.java b/services/src/main/java/org/keycloak/services/resources/RequiredActionsService.java index 5ef6cfb90f..b3a6181b4e 100755 --- a/services/src/main/java/org/keycloak/services/resources/RequiredActionsService.java +++ b/services/src/main/java/org/keycloak/services/resources/RequiredActionsService.java @@ -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()); } diff --git a/services/src/main/java/org/keycloak/services/resources/SocialResource.java b/services/src/main/java/org/keycloak/services/resources/SocialResource.java index 74d3889c9c..5bc5d4cd78 100755 --- a/services/src/main/java/org/keycloak/services/resources/SocialResource.java +++ b/services/src/main/java/org/keycloak/services/resources/SocialResource.java @@ -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()) { diff --git a/services/src/main/java/org/keycloak/services/resources/TokenService.java b/services/src/main/java/org/keycloak/services/resources/TokenService.java index 5e2334a372..6480f9ba04 100755 --- a/services/src/main/java/org/keycloak/services/resources/TokenService.java +++ b/services/src/main/java/org/keycloak/services/resources/TokenService.java @@ -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; diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminService.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminService.java index 679c9d4087..c181f25040 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/AdminService.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminService.java @@ -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) { diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java index 76fa388f22..48a926a744 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java @@ -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; diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java index 1004873b80..b617266eb1 100644 --- a/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ServerInfoAdminResource.java @@ -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>(); - Iterable authProviders = AuthenticationProviderManager.load(); + Iterable authProviders = providers.getAllProviders(AuthenticationProvider.class); for (AuthenticationProvider authProvider : authProviders) { info.authProviders.put(authProvider.getName(), authProvider.getAvailableOptions()); } diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml index 4221a3c202..f785747bf5 100755 --- a/testsuite/integration/pom.xml +++ b/testsuite/integration/pom.xml @@ -170,6 +170,16 @@ keycloak-authentication-model ${project.version} + + org.keycloak + keycloak-picketlink-api + ${project.version} + + + org.keycloak + keycloak-picketlink-realm + ${project.version} + org.jboss.logging @@ -186,7 +196,7 @@ org.picketlink - picketlink-idm-impl + picketlink-idm-idm org.picketlink diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java b/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java index 483a93db6b..167bdd6109 100755 --- a/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java +++ b/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java @@ -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(); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java index 9f45a03513..86767ad61f 100644 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/AssertEvents.java @@ -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) { diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java index d9ee2d97a9..8bd17b7070 100644 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java @@ -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"); } }); diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java index e547e13c07..4cd2b68dfc 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java @@ -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); } diff --git a/testsuite/performance/pom.xml b/testsuite/performance/pom.xml index 8480c5981e..8ecfa2dc9d 100755 --- a/testsuite/performance/pom.xml +++ b/testsuite/performance/pom.xml @@ -161,7 +161,7 @@