You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by bd...@apache.org on 2016/10/14 19:36:22 UTC
[19/20] shiro git commit: SHIRO-493 - Adding new methods and
deprecating old to ShiroWebModule to support Guice 4
http://git-wip-us.apache.org/repos/asf/shiro/blob/a63e1d85/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 53c8946..d85823e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -110,6 +110,17 @@
</properties>
+ <modules>
+ <module>core</module>
+ <module>web</module>
+ <module>support</module>
+ <module>samples</module>
+ <module>tools</module>
+ <module>all</module>
+ <module>integration-tests</module>
+ <module>test-coverage</module>
+ </modules>
+
<mailingLists>
<mailingList>
<name>Apache Shiro Users Mailing List</name>
@@ -197,16 +208,6 @@
</developer>
</developers>
- <modules>
- <module>core</module>
- <module>web</module>
- <module>support</module>
- <module>samples</module>
- <module>tools</module>
- <module>all</module>
- <module>test-coverage</module>
- </modules>
-
<build>
<pluginManagement>
<plugins>
@@ -384,6 +385,25 @@
</excludes>
</configuration>
</plugin>
+ <plugin>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-maven-plugin</artifactId>
+ <version>${jetty.version}</version>
+ <configuration>
+ <contextPath>/</contextPath>
+ <httpConnector>
+ <port>9080</port>
+ <idleTimeout>60000</idleTimeout>
+ </httpConnector>
+ <requestLog implementation="org.eclipse.jetty.server.NCSARequestLog">
+ <filename>./target/yyyy_mm_dd.request.log</filename>
+ <retainDays>90</retainDays>
+ <append>true</append>
+ <extended>false</extended>
+ <logTimeZone>GMT</logTimeZone>
+ </requestLog>
+ </configuration>
+ </plugin>
</plugins>
</pluginManagement>
<plugins>
@@ -445,6 +465,13 @@
<goal>prepare-agent</goal>
</goals>
</execution>
+ <execution>
+ <id>prepare-agent-integration</id>
+ <phase>pre-integration-test</phase>
+ <goals>
+ <goal>prepare-agent-integration</goal>
+ </goals>
+ </execution>
</executions>
</plugin>
<!-- Allow Groovy tests to run: -->
@@ -485,7 +512,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
- <version>2.3.1</version>
+ <version>3.0.2</version>
<configuration>
<archive>
<manifest>
@@ -1000,6 +1027,12 @@
<version>1.1.2</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>com.github.mjeanroy</groupId>
+ <artifactId>junit-servers-jetty</artifactId>
+ <version>0.4.2</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</dependencyManagement>
@@ -1093,7 +1126,7 @@
</plugin>
<plugin>
<artifactId>maven-surefire-report-plugin</artifactId>
- <version>2.5</version>
+ <version>2.19.1</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
@@ -1143,8 +1176,9 @@
<artifactId>jacoco-maven-plugin</artifactId>
<reportSets>
<reportSet>
- <id>javadoc-aggregate</id>
+ <id>jacoco-aggregate</id>
<reports>
+ <report>report-integration</report>
<report>report</report>
</reports>
</reportSet>
http://git-wip-us.apache.org/repos/asf/shiro/blob/a63e1d85/samples/guice/pom.xml
----------------------------------------------------------------------
diff --git a/samples/guice/pom.xml b/samples/guice/pom.xml
index ce9d56c..e51c0e0 100644
--- a/samples/guice/pom.xml
+++ b/samples/guice/pom.xml
@@ -32,30 +32,9 @@
<build>
<plugins>
- <plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <forkMode>never</forkMode>
- </configuration>
- </plugin>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
- <version>${jetty.version}</version>
- <configuration>
- <contextPath>/</contextPath>
- <httpConnector>
- <port>9080</port>
- <idleTimeout>60000</idleTimeout>
- </httpConnector>
- <requestLog implementation="org.eclipse.jetty.server.NCSARequestLog">
- <filename>./target/yyyy_mm_dd.request.log</filename>
- <retainDays>90</retainDays>
- <append>true</append>
- <extended>false</extended>
- <logTimeZone>GMT</logTimeZone>
- </requestLog>
- </configuration>
</plugin>
</plugins>
</build>
http://git-wip-us.apache.org/repos/asf/shiro/blob/a63e1d85/samples/guice/src/main/java/org/apache/shiro/samples/guice/SampleShiroServletModule.java
----------------------------------------------------------------------
diff --git a/samples/guice/src/main/java/org/apache/shiro/samples/guice/SampleShiroServletModule.java b/samples/guice/src/main/java/org/apache/shiro/samples/guice/SampleShiroServletModule.java
index 01a0113..945ae70 100644
--- a/samples/guice/src/main/java/org/apache/shiro/samples/guice/SampleShiroServletModule.java
+++ b/samples/guice/src/main/java/org/apache/shiro/samples/guice/SampleShiroServletModule.java
@@ -31,6 +31,7 @@ import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.mgt.WebSecurityManager;
import javax.inject.Singleton;
+import javax.servlet.Filter;
import javax.servlet.ServletContext;
import java.net.MalformedURLException;
import java.net.URL;
@@ -56,7 +57,8 @@ public class SampleShiroServletModule extends ShiroWebModule {
this.addFilterChain("/login.jsp", AUTHC);
this.addFilterChain("/logout", LOGOUT);
this.addFilterChain("/account/**", AUTHC);
- this.addFilterChain("/remoting/**", AUTHC, config(ROLES, "b2bClient"), config(PERMS, "remote:invoke:lan,wan"));
+
+ this.addFilterChain("/remoting/**", filterConfig(AUTHC), filterConfig(ROLES, "b2bClient"), filterConfig(PERMS, "remote:invoke:lan,wan"));
}
@Provides
http://git-wip-us.apache.org/repos/asf/shiro/blob/a63e1d85/samples/jaxrs/pom.xml
----------------------------------------------------------------------
diff --git a/samples/jaxrs/pom.xml b/samples/jaxrs/pom.xml
index c2ef72f..ad3716e 100644
--- a/samples/jaxrs/pom.xml
+++ b/samples/jaxrs/pom.xml
@@ -62,12 +62,6 @@
</pluginManagement>
<plugins>
<plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <forkMode>never</forkMode>
- </configuration>
- </plugin>
- <plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
</plugin>
http://git-wip-us.apache.org/repos/asf/shiro/blob/a63e1d85/samples/servlet-plugin/pom.xml
----------------------------------------------------------------------
diff --git a/samples/servlet-plugin/pom.xml b/samples/servlet-plugin/pom.xml
index 75c7cb6..c03d4f1 100644
--- a/samples/servlet-plugin/pom.xml
+++ b/samples/servlet-plugin/pom.xml
@@ -34,12 +34,6 @@
<build>
<plugins>
<plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <forkMode>never</forkMode>
- </configuration>
- </plugin>
- <plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jetty.version}</version>
http://git-wip-us.apache.org/repos/asf/shiro/blob/a63e1d85/samples/web/pom.xml
----------------------------------------------------------------------
diff --git a/samples/web/pom.xml b/samples/web/pom.xml
index 8b045fd..8d93a9a 100644
--- a/samples/web/pom.xml
+++ b/samples/web/pom.xml
@@ -40,12 +40,6 @@
<build>
<plugins>
<plugin>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <forkMode>never</forkMode>
- </configuration>
- </plugin>
- <plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jetty.version}</version>
http://git-wip-us.apache.org/repos/asf/shiro/blob/a63e1d85/support/guice/pom.xml
----------------------------------------------------------------------
diff --git a/support/guice/pom.xml b/support/guice/pom.xml
index 78a97f8..f91cb4e 100644
--- a/support/guice/pom.xml
+++ b/support/guice/pom.xml
@@ -31,10 +31,6 @@
<name>Apache Shiro :: Support :: Guice</name>
<packaging>bundle</packaging>
- <properties>
- <guice.version>3.0</guice.version>
- </properties>
-
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
@@ -68,6 +64,16 @@
<artifactId>jcl-over-slf4j</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
@@ -89,7 +95,18 @@
</instructions>
</configuration>
</plugin>
+ <plugin>
+ <!-- Package tests so we can re-run them with guice4 -->
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
-
</project>
http://git-wip-us.apache.org/repos/asf/shiro/blob/a63e1d85/support/guice/src/main/java/org/apache/shiro/guice/ShiroModule.java
----------------------------------------------------------------------
diff --git a/support/guice/src/main/java/org/apache/shiro/guice/ShiroModule.java b/support/guice/src/main/java/org/apache/shiro/guice/ShiroModule.java
index 00c40a4..2eac73d 100644
--- a/support/guice/src/main/java/org/apache/shiro/guice/ShiroModule.java
+++ b/support/guice/src/main/java/org/apache/shiro/guice/ShiroModule.java
@@ -18,20 +18,33 @@
*/
package org.apache.shiro.guice;
+import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
+import java.util.List;
import java.util.Set;
import java.util.WeakHashMap;
import javax.annotation.PreDestroy;
+import com.google.inject.Provider;
+import com.google.inject.matcher.Matchers;
+import com.google.inject.name.Names;
+import com.google.inject.spi.InjectionListener;
+import com.google.inject.spi.TypeEncounter;
+import com.google.inject.spi.TypeListener;
import org.apache.shiro.config.ConfigurationException;
import org.apache.shiro.env.Environment;
+import org.apache.shiro.event.EventBus;
+import org.apache.shiro.event.EventBusAware;
+import org.apache.shiro.event.Subscribe;
+import org.apache.shiro.event.support.DefaultEventBus;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.session.mgt.SessionManager;
+import org.apache.shiro.util.ClassUtils;
import org.apache.shiro.util.Destroyable;
import com.google.inject.Key;
@@ -57,6 +70,9 @@ public abstract class ShiroModule extends PrivateModule implements Destroyable {
bindSessionManager(bind(SessionManager.class));
bindEnvironment(bind(Environment.class));
bindListener(BeanTypeListener.MATCHER, new BeanTypeListener());
+ bindEventBus(bind(EventBus.class));
+ bindListener(Matchers.any(), new SubscribedEventTypeListener());
+ bindListener(Matchers.any(), new EventBusAwareTypeListener());
final DestroyableInjectionListener.DestroyableRegistry registry = new DestroyableInjectionListener.DestroyableRegistry() {
public void add(Destroyable destroyable) {
ShiroModule.this.add(destroyable);
@@ -70,6 +86,7 @@ public abstract class ShiroModule extends PrivateModule implements Destroyable {
bindListener(LifecycleTypeListener.MATCHER, new LifecycleTypeListener(registry));
expose(SecurityManager.class);
+ expose(EventBus.class);
configureShiro();
bind(realmCollectionKey())
@@ -153,6 +170,15 @@ public abstract class ShiroModule extends PrivateModule implements Destroyable {
}
/**
+ * Binds the EventBus. Override this method in order to provide your own {@link EventBus} binding.
+ * @param bind
+ * @since 1.4
+ */
+ protected void bindEventBus(AnnotatedBindingBuilder<EventBus> bind) {
+ bind.to(DefaultEventBus.class).asEagerSingleton();
+ }
+
+ /**
* Destroys all beans created within this module that implement {@link org.apache.shiro.util.Destroyable}. Should be called when this
* module will no longer be used.
*
@@ -167,4 +193,39 @@ public abstract class ShiroModule extends PrivateModule implements Destroyable {
public void add(Destroyable destroyable) {
this.destroyables.add(destroyable);
}
+
+ private class SubscribedEventTypeListener implements TypeListener {
+ @Override
+ public <I> void hear(TypeLiteral<I> typeLiteral, TypeEncounter<I> typeEncounter) {
+
+ final Provider<EventBus> eventBusProvider = typeEncounter.getProvider(EventBus.class);
+
+ List<Method> methods = ClassUtils.getAnnotatedMethods(typeLiteral.getRawType(), Subscribe.class);
+ if (methods != null && !methods.isEmpty()) {
+ typeEncounter.register( new InjectionListener<I>() {
+ @Override
+ public void afterInjection(Object o) {
+ eventBusProvider.get().register(o);
+ }
+ });
+ }
+ }
+ }
+
+ private class EventBusAwareTypeListener implements TypeListener {
+ @Override
+ public <I> void hear(TypeLiteral<I> typeLiteral, TypeEncounter<I> typeEncounter) {
+
+ final Provider<EventBus> eventBusProvider = typeEncounter.getProvider(EventBus.class);
+
+ if (EventBusAware.class.isAssignableFrom(typeLiteral.getRawType())) {
+ typeEncounter.register( new InjectionListener<I>() {
+ @Override
+ public void afterInjection(Object o) {
+ ((EventBusAware)o).setEventBus(eventBusProvider.get());
+ }
+ });
+ }
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/shiro/blob/a63e1d85/support/guice/src/main/java/org/apache/shiro/guice/web/ShiroWebModule.java
----------------------------------------------------------------------
diff --git a/support/guice/src/main/java/org/apache/shiro/guice/web/ShiroWebModule.java b/support/guice/src/main/java/org/apache/shiro/guice/web/ShiroWebModule.java
index 45bc916..15431e5 100644
--- a/support/guice/src/main/java/org/apache/shiro/guice/web/ShiroWebModule.java
+++ b/support/guice/src/main/java/org/apache/shiro/guice/web/ShiroWebModule.java
@@ -18,10 +18,7 @@
*/
package org.apache.shiro.guice.web;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
+import java.util.*;
import javax.servlet.Filter;
import javax.servlet.ServletContext;
@@ -31,6 +28,7 @@ import org.apache.shiro.env.Environment;
import org.apache.shiro.guice.ShiroModule;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
+import org.apache.shiro.util.StringUtils;
import org.apache.shiro.web.env.WebEnvironment;
import org.apache.shiro.web.filter.PathMatchingFilter;
import org.apache.shiro.web.filter.authc.AnonymousFilter;
@@ -94,7 +92,7 @@ public abstract class ShiroWebModule extends ShiroModule {
* We use a LinkedHashMap here to ensure that iterator order is the same as add order. This is important, as the
* FilterChainResolver uses iterator order when searching for a matching chain.
*/
- private final Map<String, Key<? extends Filter>[]> filterChains = new LinkedHashMap<String, Key<? extends Filter>[]>();
+ private final Map<String, FilterConfig<? extends Filter>[]> filterChains = new LinkedHashMap<String, FilterConfig<? extends Filter>[]>();
private final ServletContext servletContext;
public ShiroWebModule(ServletContext servletContext) {
@@ -134,37 +132,65 @@ public abstract class ShiroWebModule extends ShiroModule {
this.configureShiroWeb();
- setupFilterChainConfigs();
-
- bind(FilterChainResolver.class).toProvider(new FilterChainResolverProvider(filterChains));
+ bind(FilterChainResolver.class).toProvider(new FilterChainResolverProvider(setupFilterChainConfigs()));
}
- private void setupFilterChainConfigs() {
- Map<Key<? extends PathMatchingFilter>, Map<String, String>> configs = new HashMap<Key<? extends PathMatchingFilter>, Map<String, String>>();
+ private Map<String, Key<? extends Filter>[]> setupFilterChainConfigs() {
+
+ // loop through and build a map of Filter Key -> Map<Path, Config>
+ Map<Key<? extends Filter>, Map<String, String>> filterToPathToConfig = new HashMap<Key<? extends Filter>, Map<String, String>>();
+
+ // At the same time build a map to return with Path -> Key[]
+ Map<String, Key<? extends Filter>[]> resultConfigMap = new HashMap<String, Key<? extends Filter>[]>();
+
+ for (Map.Entry<String, FilterConfig<? extends Filter>[]> filterChain : filterChains.entrySet()) {
+
+ String path = filterChain.getKey();
+
+ // collect the keys used for this path
+ List<Key<? extends Filter>> keysForPath = new ArrayList<Key<? extends Filter>>();
- for (Map.Entry<String, Key<? extends Filter>[]> filterChain : filterChains.entrySet()) {
for (int i = 0; i < filterChain.getValue().length; i++) {
- Key<? extends Filter> key = filterChain.getValue()[i];
- if (key instanceof FilterConfigKey) {
- FilterConfigKey<? extends PathMatchingFilter> configKey = (FilterConfigKey<? extends PathMatchingFilter>) key;
- key = configKey.getKey();
- filterChain.getValue()[i] = key;
- if (!PathMatchingFilter.class.isAssignableFrom(key.getTypeLiteral().getRawType())) {
- throw new ConfigurationException("Config information requires a PathMatchingFilter - can't apply to " + key.getTypeLiteral().getRawType());
- }
- if (configs.get(castToPathMatching(key)) == null) configs.put(castToPathMatching(key), new HashMap<String, String>());
- configs.get(castToPathMatching(key)).put(filterChain.getKey(), configKey.getConfigValue());
- } else if (PathMatchingFilter.class.isAssignableFrom(key.getTypeLiteral().getRawType())) {
- if (configs.get(castToPathMatching(key)) == null) configs.put(castToPathMatching(key), new HashMap<String, String>());
- configs.get(castToPathMatching(key)).put(filterChain.getKey(), "");
+ FilterConfig<? extends Filter> filterConfig = filterChain.getValue()[i];
+
+ Key<? extends Filter> key = filterConfig.getKey();
+ String config = filterConfig.getConfigValue();
+
+ // initialize key in filterToPathToConfig, if it doesn't exist
+ if (filterToPathToConfig.get(key) == null) {
+ filterToPathToConfig.put((key), new HashMap<String, String>());
+ }
+ // now set the value
+ filterToPathToConfig.get(key).put(path, config);
+
+ // Config error if someone configured a non PathMatchingFilter with a config value
+ if (StringUtils.hasText(config) && !PathMatchingFilter.class.isAssignableFrom(key.getTypeLiteral().getRawType())) {
+ throw new ConfigurationException("Config information requires a PathMatchingFilter - can't apply to " + key.getTypeLiteral().getRawType());
}
+
+ // store the key in keysForPath
+ keysForPath.add(key);
}
+
+ // map the current path to all of its Keys
+ resultConfigMap.put(path, keysForPath.toArray(new Key[keysForPath.size()]));
}
- for (Key<? extends PathMatchingFilter> filterKey : configs.keySet()) {
- bindPathMatchingFilter(filterKey, configs.get(filterKey));
+
+ // now we find only the PathMatchingFilter and configure bindings
+ // non PathMatchingFilter, can be loaded with the default provider via the class name
+ for (Key<? extends Filter> key : filterToPathToConfig.keySet()) {
+ if (PathMatchingFilter.class.isAssignableFrom(key.getTypeLiteral().getRawType())) {
+ bindPathMatchingFilter(castToPathMatching(key), filterToPathToConfig.get(key));
+ }
+ else {
+ bind(key);
+ }
}
+
+ return resultConfigMap;
}
+
private <T extends PathMatchingFilter> void bindPathMatchingFilter(Key<T> filterKey, Map<String, String> configs) {
bind(filterKey).toProvider(new PathMatchingFilterProvider<T>(filterKey, configs)).asEagerSingleton();
}
@@ -218,6 +244,126 @@ public abstract class ShiroWebModule extends ShiroModule {
bind.to(WebGuiceEnvironment.class).asEagerSingleton();
}
+ protected final void addFilterChain(String pattern, Key<? extends Filter> key) {
+ // check for legacy API
+ if (key instanceof FilterConfigKey) {
+ addLegacyFilterChain(pattern, (FilterConfigKey) key);
+ }
+ else {
+ addFilterChain(pattern, new FilterConfig<Filter>((Key<Filter>) key, ""));
+ }
+ }
+
+ /**
+ * Maps 'n' number of <code>filterConfig</code>s to a specific path pattern.<BR/>
+ * For example, a path of '/my_private_resource/**' to 'filterConfig(AUTHC)' would require
+ * any resource under the path '/my_private_resource' would be processed through the {@link FormAuthenticationFilter}.
+ *
+ * @param pattern URL patter to be mapped to a FilterConfig, e.g. '/my_private-path/**'
+ * @param filterConfigs FilterConfiguration representing the Filter and config to be used when processing resources on <code>pattern</code>.
+ * @since 1.4
+ */
+ protected final void addFilterChain(String pattern, FilterConfig<? extends Filter>... filterConfigs) {
+ filterChains.put(pattern, filterConfigs);
+ }
+
+ /**
+ * Builds a FilterConfig from a Filer and configuration String
+ * @param baseKey The Key of the Filter class to be used.
+ * @param <T> A Servlet Filter class.
+ * @return A FilterConfig used to map a String path to this configuration.
+ * @since 1.4
+ */
+ protected static <T extends Filter> FilterConfig<T> filterConfig(Key<T> baseKey, String configValue) {
+ return new FilterConfig<T>(baseKey, configValue);
+ }
+
+ /**
+ * Builds a FilterConfig from a Filer and configuration String
+ * @param baseKey The Key of the Filter class to be used.
+ * @param <T> A Servlet Filter class.
+ * @return A FilterConfig used to map a String path to this configuration.
+ * @since 1.4
+ */
+ protected static <T extends Filter> FilterConfig<T> filterConfig(Key<T> baseKey) {
+ return filterConfig(baseKey, "");
+ }
+
+ /**
+ * Builds a FilterConfig from a Filer and configuration String
+ * @param typeLiteral The TyleLiteral of the filter key to be used.
+ * @param configValue the configuration used.
+ * @param <T> A Servlet Filter class.
+ * @return A FilterConfig used to map a String path to this configuration.
+ * @since 1.4
+ */
+ @SuppressWarnings({"UnusedDeclaration"})
+ protected static <T extends Filter> FilterConfig<T> filterConfig(TypeLiteral<T> typeLiteral, String configValue) {
+ return filterConfig(Key.get(typeLiteral), configValue);
+ }
+
+ /**
+ * Builds a FilterConfig from a Filer and configuration String
+ * @param type The filter to be used.
+ * @param configValue the configuration used.
+ * @param <T> A Servlet Filter class.
+ * @return A FilterConfig used to map a String path to this configuration.
+ * @since 1.4
+ */
+ @SuppressWarnings({"UnusedDeclaration"})
+ protected static <T extends Filter> FilterConfig<T> filterConfig(Class<T> type, String configValue) {
+ return filterConfig(Key.get(type), configValue);
+ }
+
+
+ /**
+ * Filter configuration which pairs a Filter class with its configuration used on a path.
+ * @param <T> The Servlet Filter class.
+ * @since 1.4
+ */
+ public static class FilterConfig<T extends Filter> {
+ private Key<T> key;
+ private String configValue;
+
+ private FilterConfig(Key<T> key, String configValue) {
+ super();
+ this.key = key;
+ this.configValue = configValue;
+ }
+
+ public Key<T> getKey() {
+ return key;
+ }
+
+ public String getConfigValue() {
+ return configValue;
+ }
+ }
+
+
+
+
+
+
+
+ // legacy methods
+
+
+ static boolean isGuiceVersion3() {
+ try {
+ Class.forName("com.google.inject.multibindings.MapKey");
+ return false;
+ } catch (ClassNotFoundException e) {
+ return true;
+ }
+ }
+
+ private void addLegacyFilterChain(String pattern, FilterConfigKey filterConfigKey) {
+
+ FilterConfig<Filter> filterConfig = new FilterConfig<Filter>(filterConfigKey.getKey(), filterConfigKey.getConfigValue());
+ addFilterChain(pattern, filterConfig);
+ }
+
/**
* Adds a filter chain to the shiro configuration.
* <p/>
@@ -228,24 +374,52 @@ public abstract class ShiroWebModule extends ShiroModule {
* @param keys
*/
@SuppressWarnings({"UnusedDeclaration"})
+ @Deprecated
protected final void addFilterChain(String pattern, Key<? extends Filter>... keys) {
- filterChains.put(pattern, keys);
+
+ // We need to extract the keys and FilterConfigKey and convert to the new format.
+
+ FilterConfig[] filterConfigs = new FilterConfig[keys.length];
+ for (int ii = 0; ii < keys.length; ii++) {
+ Key<? extends Filter> key = keys[ii];
+ // If this is a path matching filter, we need to remember the config
+ if (key instanceof FilterConfigKey) {
+ // legacy config
+ FilterConfigKey legacyKey = (FilterConfigKey) key;
+ filterConfigs[ii] = new FilterConfig(legacyKey.getKey(), legacyKey.getConfigValue());
+ }
+ else {
+ // Some other type of Filter key, no config
+ filterConfigs[ii] = new FilterConfig(key, "");
+ }
+ }
+
+ filterChains.put(pattern, filterConfigs);
}
+ @Deprecated
protected static <T extends PathMatchingFilter> Key<T> config(Key<T> baseKey, String configValue) {
+
+ if( !isGuiceVersion3()) {
+ throw new ConfigurationException("Method ShiroWebModule.config(Key<? extends PathMatchingFilter>, String configValue), is not supported when using Guice 4+");
+ }
+
return new FilterConfigKey<T>(baseKey, configValue);
}
@SuppressWarnings({"UnusedDeclaration"})
+ @Deprecated
protected static <T extends PathMatchingFilter> Key<T> config(TypeLiteral<T> typeLiteral, String configValue) {
return config(Key.get(typeLiteral), configValue);
}
@SuppressWarnings({"UnusedDeclaration"})
+ @Deprecated
protected static <T extends PathMatchingFilter> Key<T> config(Class<T> type, String configValue) {
return config(Key.get(type), configValue);
}
+ @Deprecated
private static class FilterConfigKey<T extends PathMatchingFilter> extends Key<T> {
private Key<T> key;
private String configValue;
@@ -264,4 +438,5 @@ public abstract class ShiroWebModule extends ShiroModule {
return configValue;
}
}
+
}
http://git-wip-us.apache.org/repos/asf/shiro/blob/a63e1d85/support/guice/src/main/java/org/apache/shiro/guice/web/SimpleFilterChain.java
----------------------------------------------------------------------
diff --git a/support/guice/src/main/java/org/apache/shiro/guice/web/SimpleFilterChain.java b/support/guice/src/main/java/org/apache/shiro/guice/web/SimpleFilterChain.java
index 4ff8b56..eee6230 100644
--- a/support/guice/src/main/java/org/apache/shiro/guice/web/SimpleFilterChain.java
+++ b/support/guice/src/main/java/org/apache/shiro/guice/web/SimpleFilterChain.java
@@ -44,4 +44,13 @@ class SimpleFilterChain implements FilterChain {
originalChain.doFilter(request, response);
}
}
+
+ /**
+ * Exposed for testing, not part of public API.
+ * @return an Iterater of filters.
+ */
+ Iterator<? extends Filter> getFilters() {
+ return chain;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/shiro/blob/a63e1d85/support/guice/src/test/java/org/apache/shiro/guice/ShiroModuleTest.java
----------------------------------------------------------------------
diff --git a/support/guice/src/test/java/org/apache/shiro/guice/ShiroModuleTest.java b/support/guice/src/test/java/org/apache/shiro/guice/ShiroModuleTest.java
index 4507076..526f4f7 100644
--- a/support/guice/src/test/java/org/apache/shiro/guice/ShiroModuleTest.java
+++ b/support/guice/src/test/java/org/apache/shiro/guice/ShiroModuleTest.java
@@ -28,6 +28,10 @@ import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.env.Environment;
+import org.apache.shiro.event.EventBus;
+import org.apache.shiro.event.EventBusAware;
+import org.apache.shiro.event.Subscribe;
+import org.apache.shiro.event.support.DefaultEventBus;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
@@ -37,11 +41,13 @@ import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Destroyable;
import org.junit.Test;
+import java.lang.reflect.Field;
import java.util.Collection;
+import java.util.Map;
import static org.easymock.EasyMock.*;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.*;
public class ShiroModuleTest {
@@ -204,6 +210,82 @@ public class ShiroModuleTest {
verify(myDestroyable);
}
+ /**
+ * @since 1.4
+ * @throws Exception
+ */
+ @Test
+ public void testEventListener() throws Exception {
+
+ final MockRealm mockRealm = createMock(MockRealm.class);
+ final EventBus eventBus = createMock(EventBus.class);
+
+ // expect both objects to be registered
+ eventBus.register(anyObject(MockEventListener1.class));
+ eventBus.register(anyObject(MockEventListener2.class));
+ replay(eventBus);
+
+ final ShiroModule shiroModule = new ShiroModule() {
+ @Override
+ protected void configureShiro() {
+ bindRealm().to(MockRealm.class);
+
+ // bind our event listeners
+ binder().bind(MockEventListener1.class).asEagerSingleton();
+ binder().bind(MockEventListener2.class).asEagerSingleton();
+ }
+
+ @Override
+ protected void bindEventBus(AnnotatedBindingBuilder<EventBus> bind) {
+ bind.toInstance(eventBus);
+ }
+
+ @Provides
+ public MockRealm createRealm() {
+ return mockRealm;
+ }
+
+ };
+ Guice.createInjector(shiroModule);
+
+ verify(eventBus);
+
+ }
+
+ /**
+ * @since 1.4
+ * @throws Exception
+ */
+ @Test
+ public void testEventBusAware() throws Exception {
+
+ final MockRealm mockRealm = createMock(MockRealm.class);
+
+ final ShiroModule shiroModule = new ShiroModule() {
+ @Override
+ protected void configureShiro() {
+ bindRealm().to(MockRealm.class);
+
+ binder().bind(MockEventBusAware.class).asEagerSingleton();
+ expose(MockEventBusAware.class);
+ }
+
+ @Provides
+ public MockRealm createRealm() {
+ return mockRealm;
+ }
+
+ };
+ Injector injector = Guice.createInjector(shiroModule);
+ EventBus eventBus = injector.getInstance(EventBus.class);
+ SecurityManager securityManager = injector.getInstance(SecurityManager.class);
+
+ MockEventBusAware eventBusAware = injector.getInstance(MockEventBusAware.class);
+
+ assertSame(eventBus, eventBusAware.eventBus);
+ assertSame(eventBus, ((DefaultSecurityManager)securityManager).getEventBus());
+ }
+
public static interface MockRealm extends Realm {
}
@@ -227,4 +309,27 @@ public class ShiroModuleTest {
public static interface MyDestroyable extends Destroyable {
}
+
+ public static class MockEventListener1 {
+ @Subscribe
+ public void listenToAllAndDoNothing(Object o) {}
+ }
+
+ public static class MockEventListener2 {
+ @Subscribe
+ public void listenToAllAndDoNothing(Object o) {}
+ }
+
+ public static class MockEventBusAware implements EventBusAware {
+ private EventBus eventBus;
+
+ public EventBus getEventBus() {
+ return eventBus;
+ }
+
+ @Override
+ public void setEventBus(EventBus eventBus) {
+ this.eventBus = eventBus;
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/shiro/blob/a63e1d85/support/guice/src/test/java/org/apache/shiro/guice/web/FilterConfigTest.java
----------------------------------------------------------------------
diff --git a/support/guice/src/test/java/org/apache/shiro/guice/web/FilterConfigTest.java b/support/guice/src/test/java/org/apache/shiro/guice/web/FilterConfigTest.java
index 98add89..c1b3c32 100644
--- a/support/guice/src/test/java/org/apache/shiro/guice/web/FilterConfigTest.java
+++ b/support/guice/src/test/java/org/apache/shiro/guice/web/FilterConfigTest.java
@@ -45,7 +45,8 @@ public class FilterConfigTest {
bindRealm().to(ShiroModuleTest.MockRealm.class);
addFilterChain("/index.html", AUTHC_BASIC);
- addFilterChain("/index2.html", config(PERMS, "permission"));
+// addFilterChain("/index2.html", config(PERMS, "permission"));
+ addFilterChain("/index2.html", filterConfig(PERMS, "permission"));
}
@Provides
http://git-wip-us.apache.org/repos/asf/shiro/blob/a63e1d85/support/guice/src/test/java/org/apache/shiro/guice/web/ShiroWebModuleTest.java
----------------------------------------------------------------------
diff --git a/support/guice/src/test/java/org/apache/shiro/guice/web/ShiroWebModuleTest.java b/support/guice/src/test/java/org/apache/shiro/guice/web/ShiroWebModuleTest.java
index a3a3f76..ff50d0f 100644
--- a/support/guice/src/test/java/org/apache/shiro/guice/web/ShiroWebModuleTest.java
+++ b/support/guice/src/test/java/org/apache/shiro/guice/web/ShiroWebModuleTest.java
@@ -21,6 +21,7 @@ package org.apache.shiro.guice.web;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
+import com.google.inject.Key;
import com.google.inject.Provides;
import com.google.inject.binder.AnnotatedBindingBuilder;
import org.apache.shiro.guice.ShiroModuleTest;
@@ -28,21 +29,38 @@ import org.apache.shiro.env.Environment;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
+import org.apache.shiro.web.env.EnvironmentLoader;
import org.apache.shiro.web.env.WebEnvironment;
+import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
+import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
+import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter;
+import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;
import org.apache.shiro.web.filter.mgt.FilterChainResolver;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.mgt.WebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.session.mgt.ServletContainerSessionManager;
+import org.easymock.EasyMock;
+import org.junit.Assume;
import org.junit.Test;
import javax.inject.Named;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
import java.util.Collection;
+import java.util.Iterator;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.*;
-import static org.easymock.EasyMock.createMock;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
public class ShiroWebModuleTest {
@@ -146,6 +164,162 @@ public class ShiroWebModuleTest {
assertTrue( environment == webEnvironment );
}
+ /**
+ * @since 1.4
+ */
+ @Test
+ public void testAddFilterChainGuice3and4() {
+
+ final ShiroModuleTest.MockRealm mockRealm = createMock(ShiroModuleTest.MockRealm.class);
+ ServletContext servletContext = createMock(ServletContext.class);
+ HttpServletRequest request = createMock(HttpServletRequest.class);
+
+ servletContext.setAttribute(eq(EnvironmentLoader.ENVIRONMENT_ATTRIBUTE_KEY), EasyMock.anyObject());
+ expect(request.getAttribute("javax.servlet.include.context_path")).andReturn("").anyTimes();
+ expect(request.getCharacterEncoding()).andReturn("UTF-8").anyTimes();
+ expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_authc");
+ expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_custom_filter");
+ expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_authc_basic");
+ expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_perms");
+ expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/multiple_configs");
+ replay(servletContext, request);
+
+ Injector injector = Guice.createInjector(new ShiroWebModule(servletContext) {
+ @Override
+ protected void configureShiroWeb() {
+ bindRealm().to(ShiroModuleTest.MockRealm.class);
+ expose(FilterChainResolver.class);
+ this.addFilterChain("/test_authc/**", filterConfig(AUTHC));
+ this.addFilterChain("/test_custom_filter/**", Key.get(CustomFilter.class));
+ this.addFilterChain("/test_authc_basic/**", AUTHC_BASIC);
+ this.addFilterChain("/test_perms/**", filterConfig(PERMS, "remote:invoke:lan,wan"));
+ this.addFilterChain("/multiple_configs/**", filterConfig(AUTHC), filterConfig(ROLES, "b2bClient"), filterConfig(PERMS, "remote:invoke:lan,wan"));
+ }
+
+ @Provides
+ public ShiroModuleTest.MockRealm createRealm() {
+ return mockRealm;
+ }
+ });
+
+ FilterChainResolver resolver = injector.getInstance(FilterChainResolver.class);
+ assertThat(resolver, instanceOf(SimpleFilterChainResolver.class));
+ SimpleFilterChainResolver simpleFilterChainResolver = (SimpleFilterChainResolver) resolver;
+
+ // test the /test_authc resource
+ FilterChain filterChain = simpleFilterChainResolver.getChain(request, null, null);
+ assertThat(filterChain, instanceOf(SimpleFilterChain.class));
+ Filter nextFilter = getNextFilter((SimpleFilterChain) filterChain);
+ assertThat(nextFilter, instanceOf(FormAuthenticationFilter.class));
+
+ // test the /test_custom_filter resource
+ filterChain = simpleFilterChainResolver.getChain(request, null, null);
+ assertThat(filterChain, instanceOf(SimpleFilterChain.class));
+ nextFilter = getNextFilter((SimpleFilterChain) filterChain);
+ assertThat(nextFilter, instanceOf(CustomFilter.class));
+
+ // test the /test_authc_basic resource
+ filterChain = simpleFilterChainResolver.getChain(request, null, null);
+ assertThat(filterChain, instanceOf(SimpleFilterChain.class));
+ nextFilter = getNextFilter((SimpleFilterChain) filterChain);
+ assertThat(nextFilter, instanceOf(BasicHttpAuthenticationFilter.class));
+
+ // test the /test_perms resource
+ filterChain = simpleFilterChainResolver.getChain(request, null, null);
+ assertThat(filterChain, instanceOf(SimpleFilterChain.class));
+ nextFilter = getNextFilter((SimpleFilterChain) filterChain);
+ assertThat(nextFilter, instanceOf(PermissionsAuthorizationFilter.class));
+
+ // test the /multiple_configs resource
+ filterChain = simpleFilterChainResolver.getChain(request, null, null);
+ assertThat(filterChain, instanceOf(SimpleFilterChain.class));
+ assertThat(getNextFilter((SimpleFilterChain) filterChain), instanceOf(FormAuthenticationFilter.class));
+ assertThat(getNextFilter((SimpleFilterChain) filterChain), instanceOf(RolesAuthorizationFilter.class));
+ assertThat(getNextFilter((SimpleFilterChain) filterChain), instanceOf(PermissionsAuthorizationFilter.class));
+
+ verify(servletContext, request);
+ }
+
+ /**
+ * @since 1.4
+ */
+ @Test
+ public void testAddFilterChainGuice3Only() {
+
+ Assume.assumeTrue("This test only runs agains Guice 3.x", ShiroWebModule.isGuiceVersion3());
+
+ final ShiroModuleTest.MockRealm mockRealm = createMock(ShiroModuleTest.MockRealm.class);
+ ServletContext servletContext = createMock(ServletContext.class);
+ HttpServletRequest request = createMock(HttpServletRequest.class);
+
+ servletContext.setAttribute(eq(EnvironmentLoader.ENVIRONMENT_ATTRIBUTE_KEY), EasyMock.anyObject());
+ expect(request.getAttribute("javax.servlet.include.context_path")).andReturn("").anyTimes();
+ expect(request.getCharacterEncoding()).andReturn("UTF-8").anyTimes();
+ expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_authc");
+ expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_custom_filter");
+ expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_perms");
+ expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/multiple_configs");
+ replay(servletContext, request);
+
+ Injector injector = Guice.createInjector(new ShiroWebModule(servletContext) {
+ @Override
+ protected void configureShiroWeb() {
+ bindRealm().to(ShiroModuleTest.MockRealm.class);
+ expose(FilterChainResolver.class);
+ this.addFilterChain("/test_authc/**", AUTHC);
+ this.addFilterChain("/test_custom_filter/**", Key.get(CustomFilter.class));
+ this.addFilterChain("/test_perms/**", config(PERMS, "remote:invoke:lan,wan"));
+ this.addFilterChain("/multiple_configs/**", AUTHC, config(ROLES, "b2bClient"), config(PERMS, "remote:invoke:lan,wan"));
+ }
+
+ @Provides
+ public ShiroModuleTest.MockRealm createRealm() {
+ return mockRealm;
+ }
+ });
+
+ FilterChainResolver resolver = injector.getInstance(FilterChainResolver.class);
+ assertThat(resolver, instanceOf(SimpleFilterChainResolver.class));
+ SimpleFilterChainResolver simpleFilterChainResolver = (SimpleFilterChainResolver) resolver;
+
+ // test the /test_authc resource
+ FilterChain filterChain = simpleFilterChainResolver.getChain(request, null, null);
+ assertThat(filterChain, instanceOf(SimpleFilterChain.class));
+ Filter nextFilter = getNextFilter((SimpleFilterChain) filterChain);
+ assertThat(nextFilter, instanceOf(FormAuthenticationFilter.class));
+
+ // test the /test_custom_filter resource
+ filterChain = simpleFilterChainResolver.getChain(request, null, null);
+ assertThat(filterChain, instanceOf(SimpleFilterChain.class));
+ nextFilter = getNextFilter((SimpleFilterChain) filterChain);
+ assertThat(nextFilter, instanceOf(CustomFilter.class));
+
+ // test the /test_perms resource
+ filterChain = simpleFilterChainResolver.getChain(request, null, null);
+ assertThat(filterChain, instanceOf(SimpleFilterChain.class));
+ nextFilter = getNextFilter((SimpleFilterChain) filterChain);
+ assertThat(nextFilter, instanceOf(PermissionsAuthorizationFilter.class));
+
+ // test the /multiple_configs resource
+ filterChain = simpleFilterChainResolver.getChain(request, null, null);
+ assertThat(filterChain, instanceOf(SimpleFilterChain.class));
+ assertThat(getNextFilter((SimpleFilterChain) filterChain), instanceOf(FormAuthenticationFilter.class));
+ assertThat(getNextFilter((SimpleFilterChain) filterChain), instanceOf(RolesAuthorizationFilter.class));
+ assertThat(getNextFilter((SimpleFilterChain) filterChain), instanceOf(PermissionsAuthorizationFilter.class));
+
+ verify(servletContext, request);
+ }
+
+ private Filter getNextFilter(SimpleFilterChain filterChain) {
+
+ Iterator<? extends Filter> filters = filterChain.getFilters();
+ if (filters.hasNext()) {
+ return filters.next();
+ }
+
+ return null;
+ }
+
public static class MyDefaultWebSecurityManager extends DefaultWebSecurityManager {
@Inject
public MyDefaultWebSecurityManager(Collection<Realm> realms) {
@@ -162,4 +336,16 @@ public class ShiroWebModuleTest {
super(filterChainResolver, servletContext, securityManager);
}
}
+
+ public static class CustomFilter implements Filter {
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {}
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {}
+
+ @Override
+ public void destroy() {}
+ }
}
http://git-wip-us.apache.org/repos/asf/shiro/blob/a63e1d85/support/guice/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/support/guice/src/test/resources/log4j.properties b/support/guice/src/test/resources/log4j.properties
new file mode 100644
index 0000000..bbb023d
--- /dev/null
+++ b/support/guice/src/test/resources/log4j.properties
@@ -0,0 +1,34 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+log4j.rootLogger=TRACE, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n
+
+# Pattern to output: date priority [category] - message
+log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
+log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
+
+# General Apache libraries is WARN
+log4j.logger.org.apache=WARN
+
+log4j.logger.org.apache.shiro=TRACE
+log4j.logger.org.apache.shiro.util.ThreadContext=WARN
\ No newline at end of file