diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java index 9c932142b1..b5621ef3e4 100755 --- a/model/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java +++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java @@ -20,25 +20,17 @@ package org.keycloak.connections.jpa; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.DriverManager; -import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashMap; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import javax.naming.InitialContext; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; -import javax.persistence.Persistence; -import javax.persistence.spi.PersistenceUnitTransactionType; import javax.sql.DataSource; -import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl; import org.hibernate.ejb.AvailableSettings; -import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor; -import org.hibernate.jpa.boot.internal.PersistenceXmlParser; -import org.hibernate.jpa.boot.spi.Bootstrap; import org.jboss.logging.Logger; import org.keycloak.Config; import org.keycloak.connections.jpa.updater.JpaUpdaterProvider; @@ -182,7 +174,7 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide } logger.trace("Creating EntityManagerFactory"); - emf = JpaUtils.createEntityManagerFactory(unitName, properties, getClass().getClassLoader()); + emf = JpaUtils.createEntityManagerFactory(session, unitName, properties, getClass().getClassLoader()); logger.trace("EntityManagerFactory created"); if (globalStatsInterval != -1) { diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/JpaEntityProvider.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/JpaEntityProvider.java new file mode 100644 index 0000000000..c64c96520d --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/JpaEntityProvider.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.keycloak.connections.jpa.entityprovider; + +import java.util.List; + +import org.keycloak.provider.Provider; + +/** + * @author Erik Mulder + * + * A JPA Entity Provider can supply extra JPA entities that the Keycloak system should include in it's entity manager. The + * entities should be provided as a list of Class objects. + */ +public interface JpaEntityProvider extends Provider { + + /** + * Return the entities that should be added to the entity manager. + * + * @return list of class objects + */ + List> getEntities(); + + /** + * Return the location of the Liquibase changelog that facilitates the extra JPA entities. + * This should be a location that can be found on the same classpath as the entity classes. + * + * @return a changelog location or null if not needed + */ + String getChangelogLocation(); + +} diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/JpaEntityProviderFactory.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/JpaEntityProviderFactory.java new file mode 100644 index 0000000000..8c08bf93e1 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/JpaEntityProviderFactory.java @@ -0,0 +1,29 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.keycloak.connections.jpa.entityprovider; + +import org.keycloak.provider.ProviderFactory; + +/** + * @author Erik Mulder + * + * Extended interface for a provider factory for JpaEntityProvider's. + */ +public interface JpaEntityProviderFactory extends ProviderFactory { + +} diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/JpaEntitySpi.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/JpaEntitySpi.java new file mode 100644 index 0000000000..d89389fc48 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/JpaEntitySpi.java @@ -0,0 +1,51 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.keycloak.connections.jpa.entityprovider; + +import org.keycloak.provider.Provider; +import org.keycloak.provider.ProviderFactory; +import org.keycloak.provider.Spi; + +/** + * @author Erik Mulder + * + * Spi that allows for adding extra JPA entity's to the Keycloak entity manager. + */ +public class JpaEntitySpi implements Spi { + + @Override + public boolean isInternal() { + return false; + } + + @Override + public String getName() { + return "jpa-entity-provider"; + } + + @Override + public Class getProviderClass() { + return JpaEntityProvider.class; + } + + @Override + public Class getProviderFactoryClass() { + return JpaEntityProviderFactory.class; + } + +} diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/ProxyClassLoader.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/ProxyClassLoader.java new file mode 100644 index 0000000000..e9b82a3d5f --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/ProxyClassLoader.java @@ -0,0 +1,87 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.keycloak.connections.jpa.entityprovider; + +import java.net.URL; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +/** + * @author Erik Mulder + * + * Classloader implementation to facilitate loading classes and resources from a collection of other classloaders. + * Effectively it forms a proxy to one or more other classloaders. + * + * The way it works: + * - Get all (unique) classloaders from all provided classes + * - For each class or resource that is 'requested': + * - First try all provided classloaders and if we have a match, return that + * - If no match was found: proceed with 'normal' classloading in 'current classpath' scope + * + * In this particular context: only loadClass and getResource overrides are needed, since those + * are the methods that a classloading and resource loading process will need. + */ +public class ProxyClassLoader extends ClassLoader { + + private Set classloaders; + + public ProxyClassLoader(Collection> classes, ClassLoader parentClassLoader) { + super(parentClassLoader); + init(classes); + } + + public ProxyClassLoader(Collection> classes) { + init(classes); + } + + private void init(Collection> classes) { + classloaders = new HashSet<>(); + for (Class clazz : classes) { + classloaders.add(clazz.getClassLoader()); + } + } + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + for (ClassLoader classloader : classloaders) { + try { + return classloader.loadClass(name); + } catch (ClassNotFoundException e) { + // This particular class loader did not find the class. It's expected behavior that + // this can happen, so we'll just ignore the exception and let the next one try. + } + } + // We did not find the class in the proxy class loaders, so proceed with 'normal' behavior. + return super.loadClass(name); + } + + @Override + public URL getResource(String name) { + for (ClassLoader classloader : classloaders) { + URL resource = classloader.getResource(name); + if (resource != null) { + return resource; + } + // Resource == null means not found, so let the next one try. + } + // We could not get the resource from the proxy class loaders, so proceed with 'normal' behavior. + return super.getResource(name); + } + +} diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/conn/DefaultLiquibaseConnectionProvider.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/conn/DefaultLiquibaseConnectionProvider.java index b9018f8991..ca6d722ebd 100644 --- a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/conn/DefaultLiquibaseConnectionProvider.java +++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/conn/DefaultLiquibaseConnectionProvider.java @@ -18,8 +18,25 @@ package org.keycloak.connections.jpa.updater.liquibase.conn; import java.sql.Connection; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.jboss.logging.Logger; +import org.keycloak.Config; +import org.keycloak.connections.jpa.entityprovider.JpaEntityProvider; +import org.keycloak.connections.jpa.entityprovider.ProxyClassLoader; +import org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProvider; +import org.keycloak.connections.jpa.updater.liquibase.PostgresPlusDatabase; +import org.keycloak.connections.jpa.updater.liquibase.lock.CustomInsertLockRecordGenerator; +import org.keycloak.connections.jpa.updater.liquibase.lock.CustomLockDatabaseChangeLogGenerator; +import org.keycloak.connections.jpa.updater.liquibase.lock.DummyLockService; +import org.keycloak.connections.jpa.util.JpaUtils; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; import liquibase.Liquibase; +import liquibase.changelog.ChangeLogParameters; import liquibase.changelog.ChangeSet; import liquibase.changelog.DatabaseChangeLog; import liquibase.database.Database; @@ -27,23 +44,14 @@ import liquibase.database.DatabaseFactory; import liquibase.database.core.DB2Database; import liquibase.database.jvm.JdbcConnection; import liquibase.exception.LiquibaseException; -import liquibase.lockservice.LockService; -import liquibase.lockservice.LockServiceFactory; import liquibase.logging.LogFactory; import liquibase.logging.LogLevel; +import liquibase.parser.ChangeLogParser; +import liquibase.parser.ChangeLogParserFactory; import liquibase.resource.ClassLoaderResourceAccessor; +import liquibase.resource.ResourceAccessor; import liquibase.servicelocator.ServiceLocator; import liquibase.sqlgenerator.SqlGeneratorFactory; -import org.jboss.logging.Logger; -import org.keycloak.Config; -import org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProvider; -import org.keycloak.connections.jpa.updater.liquibase.PostgresPlusDatabase; -import org.keycloak.connections.jpa.updater.liquibase.lock.CustomInsertLockRecordGenerator; -import org.keycloak.connections.jpa.updater.liquibase.lock.CustomLockDatabaseChangeLogGenerator; -import org.keycloak.connections.jpa.updater.liquibase.lock.CustomLockService; -import org.keycloak.connections.jpa.updater.liquibase.lock.DummyLockService; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.KeycloakSessionFactory; /** * @author Marek Posolda @@ -54,8 +62,11 @@ public class DefaultLiquibaseConnectionProvider implements LiquibaseConnectionPr private volatile boolean initialized = false; + private KeycloakSession keycloakSession; + @Override public LiquibaseConnectionProvider create(KeycloakSession session) { + this.keycloakSession = session; if (!initialized) { synchronized (this) { if (!initialized) { @@ -134,7 +145,61 @@ public class DefaultLiquibaseConnectionProvider implements LiquibaseConnectionPr String changelog = (database instanceof DB2Database) ? LiquibaseJpaUpdaterProvider.DB2_CHANGELOG : LiquibaseJpaUpdaterProvider.CHANGELOG; logger.debugf("Using changelog file: %s", changelog); - return new Liquibase(changelog, new ClassLoaderResourceAccessor(getClass().getClassLoader()), database); + ResourceAccessor resourceAccessor = new ClassLoaderResourceAccessor(getClass().getClassLoader()); + DatabaseChangeLog databaseChangeLog = generateDynamicChangeLog(changelog, resourceAccessor, database); + + return new Liquibase(databaseChangeLog, resourceAccessor, database); + } + + /** + * We want to be able to provide extra changesets as an extension to the Keycloak data model. + * But we do not want users to be able to not execute certain parts of the Keycloak internal data model. + * Therefore, we generate a dynamic changelog here that always contains the keycloak changelog file + * and optionally include the user extension changelog files. + * + * @param changelog the changelog file location + * @param resourceAccessor the resource accessor + * @param database the database + * @return + */ + private DatabaseChangeLog generateDynamicChangeLog(String changelog, ResourceAccessor resourceAccessor, Database database) throws LiquibaseException { + ChangeLogParameters changeLogParameters = new ChangeLogParameters(database); + ChangeLogParser parser = ChangeLogParserFactory.getInstance().getParser(changelog, resourceAccessor); + DatabaseChangeLog keycloakDatabaseChangeLog = parser.parse(changelog, changeLogParameters, resourceAccessor); + + List locations = new ArrayList<>(); + Set entityProviders = keycloakSession.getAllProviders(JpaEntityProvider.class); + for (JpaEntityProvider entityProvider : entityProviders) { + String location = entityProvider.getChangelogLocation(); + if (location != null) { + locations.add(location); + } + } + + final DatabaseChangeLog dynamicMasterChangeLog; + if (locations.isEmpty()) { + // If there are no extra changelog locations, we'll just use the keycloak one. + dynamicMasterChangeLog = keycloakDatabaseChangeLog; + } else { + // A change log is essentially not much more than a (big) collection of changesets. + // The original (file) destination is not important. So we can just make one big dynamic change log that include all changesets. + dynamicMasterChangeLog = new DatabaseChangeLog(); + dynamicMasterChangeLog.setChangeLogParameters(changeLogParameters); + for (ChangeSet changeSet : keycloakDatabaseChangeLog.getChangeSets()) { + dynamicMasterChangeLog.addChangeSet(changeSet); + } + ProxyClassLoader proxyClassLoader = new ProxyClassLoader(JpaUtils.getProvidedEntities(keycloakSession)); + for (String location : locations) { + ResourceAccessor proxyResourceAccessor = new ClassLoaderResourceAccessor(proxyClassLoader); + ChangeLogParser locationParser = ChangeLogParserFactory.getInstance().getParser(location, proxyResourceAccessor); + DatabaseChangeLog locationDatabaseChangeLog = locationParser.parse(location, changeLogParameters, proxyResourceAccessor); + for (ChangeSet changeSet : locationDatabaseChangeLog.getChangeSets()) { + dynamicMasterChangeLog.addChangeSet(changeSet); + } + } + } + + return dynamicMasterChangeLog; } private static class LogWrapper extends LogFactory { diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/util/JpaUtils.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/util/JpaUtils.java index de07fd5abd..d93c02ba8b 100644 --- a/model/jpa/src/main/java/org/keycloak/connections/jpa/util/JpaUtils.java +++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/util/JpaUtils.java @@ -21,12 +21,18 @@ import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl; import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor; import org.hibernate.jpa.boot.internal.PersistenceXmlParser; import org.hibernate.jpa.boot.spi.Bootstrap; +import org.keycloak.connections.jpa.entityprovider.JpaEntityProvider; +import org.keycloak.connections.jpa.entityprovider.ProxyClassLoader; +import org.keycloak.models.KeycloakSession; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.spi.PersistenceUnitTransactionType; + +import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; /** * @author Marek Posolda @@ -40,14 +46,40 @@ public class JpaUtils { return (schema==null) ? tableName : schema + "." + tableName; } - public static EntityManagerFactory createEntityManagerFactory(String unitName, Map properties, ClassLoader classLoader) { + public static EntityManagerFactory createEntityManagerFactory(KeycloakSession session, String unitName, Map properties, ClassLoader classLoader) { PersistenceXmlParser parser = new PersistenceXmlParser(new ClassLoaderServiceImpl(classLoader), PersistenceUnitTransactionType.RESOURCE_LOCAL); List persistenceUnits = parser.doResolve(properties); for (ParsedPersistenceXmlDescriptor persistenceUnit : persistenceUnits) { if (persistenceUnit.getName().equals(unitName)) { - return Bootstrap.getEntityManagerFactoryBuilder(persistenceUnit, properties, classLoader).build(); + List> providedEntities = getProvidedEntities(session); + for (Class entityClass : providedEntities) { + // Add all extra entity classes to the persistence unit. + persistenceUnit.addClasses(entityClass.getName()); + } + // Now build the entity manager factory, supplying a proxy classloader, so Hibernate will be able + // to find and load the extra provided entities. Set the provided classloader as parent classloader. + return Bootstrap.getEntityManagerFactoryBuilder(persistenceUnit, properties, + new ProxyClassLoader(providedEntities, classLoader)).build(); } } throw new RuntimeException("Persistence unit '" + unitName + "' not found"); } + + /** + * Get a list of all provided entities by looping over all configured entity providers. + * + * @param session the keycloak session + * @return a list of all provided entities (can be an empty list) + */ + public static List> getProvidedEntities(KeycloakSession session) { + List> providedEntityClasses = new ArrayList<>(); + // Get all configured entity providers. + Set entityProviders = session.getAllProviders(JpaEntityProvider.class); + // For every provider, add all entity classes to the list. + for (JpaEntityProvider entityProvider : entityProviders) { + providedEntityClasses.addAll(entityProvider.getEntities()); + } + return providedEntityClasses; + } + } diff --git a/model/jpa/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/model/jpa/src/main/resources/META-INF/services/org.keycloak.provider.Spi index 94c651287a..5aba7baadf 100644 --- a/model/jpa/src/main/resources/META-INF/services/org.keycloak.provider.Spi +++ b/model/jpa/src/main/resources/META-INF/services/org.keycloak.provider.Spi @@ -17,4 +17,5 @@ org.keycloak.connections.jpa.JpaConnectionSpi org.keycloak.connections.jpa.updater.JpaUpdaterSpi -org.keycloak.connections.jpa.updater.liquibase.conn.LiquibaseConnectionSpi \ No newline at end of file +org.keycloak.connections.jpa.updater.liquibase.conn.LiquibaseConnectionSpi +org.keycloak.connections.jpa.entityprovider.JpaEntitySpi diff --git a/server-spi/src/main/java/org/keycloak/provider/ProviderLoader.java b/server-spi/src/main/java/org/keycloak/provider/ProviderLoader.java index 76c2950f10..2d7a07a6d4 100644 --- a/server-spi/src/main/java/org/keycloak/provider/ProviderLoader.java +++ b/server-spi/src/main/java/org/keycloak/provider/ProviderLoader.java @@ -24,6 +24,19 @@ import java.util.List; */ public interface ProviderLoader { + /** + * Load the SPI definitions themselves. + * + * @return a list of Spi definition objects + */ + List loadSpis(); + + /** + * Load all provider factories of a specific SPI. + * + * @param spi the Spi definition + * @return a list of provider factories + */ List load(Spi spi); } diff --git a/services/src/main/java/org/keycloak/provider/DefaultProviderLoader.java b/services/src/main/java/org/keycloak/provider/DefaultProviderLoader.java index 26aa19d4b5..5f4b19db6b 100644 --- a/services/src/main/java/org/keycloak/provider/DefaultProviderLoader.java +++ b/services/src/main/java/org/keycloak/provider/DefaultProviderLoader.java @@ -32,6 +32,15 @@ public class DefaultProviderLoader implements ProviderLoader { this.classLoader = classLoader; } + @Override + public List loadSpis() { + LinkedList list = new LinkedList<>(); + for (Spi spi : ServiceLoader.load(Spi.class, classLoader)) { + list.add(spi); + } + return list; + } + @Override public List load(Spi spi) { LinkedList list = new LinkedList(); diff --git a/services/src/main/java/org/keycloak/provider/ProviderManager.java b/services/src/main/java/org/keycloak/provider/ProviderManager.java index 997c68aee9..e906df9f41 100644 --- a/services/src/main/java/org/keycloak/provider/ProviderManager.java +++ b/services/src/main/java/org/keycloak/provider/ProviderManager.java @@ -65,6 +65,20 @@ public class ProviderManager { } } + public synchronized List loadSpis() { + // Use a map to prevent duplicates, since the loaders may have overlapping classpaths. + Map spiMap = new HashMap<>(); + for (ProviderLoader loader : loaders) { + List spis = loader.loadSpis(); + if (spis != null) { + for (Spi spi : spis) { + spiMap.put(spi.getName(), spi); + } + } + } + return new LinkedList<>(spiMap.values()); + } + public synchronized List load(Spi spi) { List factories = cache.get(spi.getName()); if (factories == null) { diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java index 90b495cc71..172de6ee48 100755 --- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java +++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java @@ -70,8 +70,9 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory { ProviderManager pm = new ProviderManager(getClass().getClassLoader(), Config.scope().getArray("providers")); - ServiceLoader load = ServiceLoader.load(Spi.class, getClass().getClassLoader()); - loadSPIs(pm, load); + // Load the SPI classes through the provider manager, so both Keycloak internal SPI's and + // the ones defined in deployed modules will be found. + loadSPIs(pm, pm.loadSpis()); for ( Map factories : factoriesMap.values()) { for (ProviderFactory factory : factories.values()) { factory.postInit(this); @@ -79,8 +80,8 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory { } } - protected void loadSPIs(ProviderManager pm, ServiceLoader load) { - for (Spi spi : load) { + protected void loadSPIs(ProviderManager pm, List spiList) { + for (Spi spi : spiList) { spis.add(spi); Map factories = new HashMap(); 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 4161763ef1..53c9aaf14a 100755 --- a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java +++ b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java @@ -101,7 +101,7 @@ public class RealmsResource { @Path("{realm}/protocol/{protocol}") public Object getProtocol(final @PathParam("realm") String name, - final @PathParam("protocol") String protocol) { + final @PathParam("protocol") String protocol) { RealmModel realm = init(name); LoginProtocolFactory factory = (LoginProtocolFactory)session.getKeycloakSessionFactory().getProviderFactory(LoginProtocol.class, protocol); @@ -239,7 +239,7 @@ public class RealmsResource { @Path("{realm}/.well-known/{provider}") @Produces(MediaType.APPLICATION_JSON) public Response getWellKnown(final @PathParam("realm") String name, - final @PathParam("provider") String providerName) { + final @PathParam("provider") String providerName) { init(name); WellKnownProvider wellKnown = session.getProvider(WellKnownProvider.class, providerName); 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 b26d95ac4d..1eee46bc00 100644 --- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java @@ -496,9 +496,9 @@ public class RealmAdminResource { @NoCache @Produces(MediaType.APPLICATION_JSON) public List getEvents(@QueryParam("type") List types, @QueryParam("client") String client, - @QueryParam("user") String user, @QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo, - @QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult, - @QueryParam("max") Integer maxResults) { + @QueryParam("user") String user, @QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo, + @QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult, + @QueryParam("max") Integer maxResults) { auth.init(RealmAuth.Resource.EVENTS).requireView(); EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class); @@ -585,10 +585,10 @@ public class RealmAdminResource { @NoCache @Produces(MediaType.APPLICATION_JSON) public List getEvents(@QueryParam("operationTypes") List operationTypes, @QueryParam("authRealm") String authRealm, @QueryParam("authClient") String authClient, - @QueryParam("authUser") String authUser, @QueryParam("authIpAddress") String authIpAddress, - @QueryParam("resourcePath") String resourcePath, @QueryParam("dateFrom") String dateFrom, - @QueryParam("dateTo") String dateTo, @QueryParam("first") Integer firstResult, - @QueryParam("max") Integer maxResults) { + @QueryParam("authUser") String authUser, @QueryParam("authIpAddress") String authIpAddress, + @QueryParam("resourcePath") String resourcePath, @QueryParam("dateFrom") String dateFrom, + @QueryParam("dateTo") String dateTo, @QueryParam("first") Integer firstResult, + @QueryParam("max") Integer maxResults) { auth.init(RealmAuth.Resource.EVENTS).requireView(); EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class); diff --git a/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi index 50bb346ff5..55b31a09f9 100755 --- a/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi +++ b/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi @@ -18,3 +18,4 @@ org.keycloak.exportimport.ClientDescriptionConverterSpi org.keycloak.wellknown.WellKnownSpi org.keycloak.services.clientregistration.ClientRegistrationSpi +