Coverage Report - org.apache.shiro.guice.web.ShiroWebModule
 
Classes in this File Line Coverage Branch Coverage Complexity
ShiroWebModule
84%
61/72
75%
12/16
1.478
ShiroWebModule$1
0%
0/3
N/A
1.478
ShiroWebModule$FilterConfigKey
100%
7/7
N/A
1.478
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *     http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.shiro.guice.web;
 20  
 
 21  
 import java.util.Collection;
 22  
 import java.util.HashMap;
 23  
 import java.util.LinkedHashMap;
 24  
 import java.util.Map;
 25  
 
 26  
 import javax.servlet.Filter;
 27  
 import javax.servlet.ServletContext;
 28  
 
 29  
 import org.apache.shiro.config.ConfigurationException;
 30  
 import org.apache.shiro.env.Environment;
 31  
 import org.apache.shiro.guice.ShiroModule;
 32  
 import org.apache.shiro.mgt.SecurityManager;
 33  
 import org.apache.shiro.session.mgt.SessionManager;
 34  
 import org.apache.shiro.web.env.WebEnvironment;
 35  
 import org.apache.shiro.web.filter.PathMatchingFilter;
 36  
 import org.apache.shiro.web.filter.authc.AnonymousFilter;
 37  
 import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
 38  
 import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
 39  
 import org.apache.shiro.web.filter.authc.LogoutFilter;
 40  
 import org.apache.shiro.web.filter.authc.UserFilter;
 41  
 import org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter;
 42  
 import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter;
 43  
 import org.apache.shiro.web.filter.authz.PortFilter;
 44  
 import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;
 45  
 import org.apache.shiro.web.filter.authz.SslFilter;
 46  
 import org.apache.shiro.web.filter.mgt.FilterChainResolver;
 47  
 import org.apache.shiro.web.filter.session.NoSessionCreationFilter;
 48  
 import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
 49  
 import org.apache.shiro.web.mgt.WebSecurityManager;
 50  
 import org.apache.shiro.web.session.mgt.ServletContainerSessionManager;
 51  
 
 52  
 import com.google.inject.Binder;
 53  
 import com.google.inject.Key;
 54  
 import com.google.inject.TypeLiteral;
 55  
 import com.google.inject.binder.AnnotatedBindingBuilder;
 56  
 import com.google.inject.name.Names;
 57  
 import com.google.inject.servlet.ServletModule;
 58  
 
 59  
 /**
 60  
  * Sets up Shiro lifecycles within Guice, enables the injecting of Shiro objects, and binds a default
 61  
  * {@link org.apache.shiro.web.mgt.WebSecurityManager}, {@link org.apache.shiro.mgt.SecurityManager} and {@link org.apache.shiro.session.mgt.SessionManager}.  At least one realm must be added by
 62  
  * using {@link #bindRealm() bindRealm}.
 63  
  * <p/>
 64  
  * Also provides for the configuring of filter chains and binds a {@link org.apache.shiro.web.filter.mgt.FilterChainResolver} with that information.
 65  
  */
 66  
 public abstract class ShiroWebModule extends ShiroModule {
 67  
     @SuppressWarnings({"UnusedDeclaration"})
 68  1
     public static final Key<AnonymousFilter> ANON = Key.get(AnonymousFilter.class);
 69  
     @SuppressWarnings({"UnusedDeclaration"})
 70  1
     public static final Key<FormAuthenticationFilter> AUTHC = Key.get(FormAuthenticationFilter.class);
 71  
     @SuppressWarnings({"UnusedDeclaration"})
 72  1
     public static final Key<BasicHttpAuthenticationFilter> AUTHC_BASIC = Key.get(BasicHttpAuthenticationFilter.class);
 73  
     @SuppressWarnings({"UnusedDeclaration"})
 74  1
     public static final Key<NoSessionCreationFilter> NO_SESSION_CREATION = Key.get(NoSessionCreationFilter.class);
 75  
     @SuppressWarnings({"UnusedDeclaration"})
 76  1
     public static final Key<LogoutFilter> LOGOUT = Key.get(LogoutFilter.class);
 77  
     @SuppressWarnings({"UnusedDeclaration"})
 78  1
     public static final Key<PermissionsAuthorizationFilter> PERMS = Key.get(PermissionsAuthorizationFilter.class);
 79  
     @SuppressWarnings({"UnusedDeclaration"})
 80  1
     public static final Key<PortFilter> PORT = Key.get(PortFilter.class);
 81  
     @SuppressWarnings({"UnusedDeclaration"})
 82  1
     public static final Key<HttpMethodPermissionFilter> REST = Key.get(HttpMethodPermissionFilter.class);
 83  
     @SuppressWarnings({"UnusedDeclaration"})
 84  1
     public static final Key<RolesAuthorizationFilter> ROLES = Key.get(RolesAuthorizationFilter.class);
 85  
     @SuppressWarnings({"UnusedDeclaration"})
 86  1
     public static final Key<SslFilter> SSL = Key.get(SslFilter.class);
 87  
     @SuppressWarnings({"UnusedDeclaration"})
 88  1
     public static final Key<UserFilter> USER = Key.get(UserFilter.class);
 89  
 
 90  
 
 91  
     static final String NAME = "SHIRO";
 92  
 
 93  
     /**
 94  
      * We use a LinkedHashMap here to ensure that iterator order is the same as add order.  This is important, as the
 95  
      * FilterChainResolver uses iterator order when searching for a matching chain.
 96  
      */
 97  5
     private final Map<String, Key<? extends Filter>[]> filterChains = new LinkedHashMap<String, Key<? extends Filter>[]>();
 98  
     private final ServletContext servletContext;
 99  
 
 100  5
     public ShiroWebModule(ServletContext servletContext) {
 101  5
         this.servletContext = servletContext;
 102  5
     }
 103  
 
 104  
     public static void bindGuiceFilter(Binder binder) {
 105  0
         binder.install(guiceFilterModule());
 106  0
     }
 107  
 
 108  
     @SuppressWarnings({"UnusedDeclaration"})
 109  
     public static void bindGuiceFilter(final String pattern, Binder binder) {
 110  0
         binder.install(guiceFilterModule(pattern));
 111  0
     }
 112  
 
 113  
     public static ServletModule guiceFilterModule() {
 114  0
         return guiceFilterModule("/*");
 115  
     }
 116  
 
 117  
     public static ServletModule guiceFilterModule(final String pattern) {
 118  0
         return new ServletModule() {
 119  
             @Override
 120  
             protected void configureServlets() {
 121  0
                 filter(pattern).through(GuiceShiroFilter.class);
 122  0
             }
 123  
         };
 124  
     }
 125  
 
 126  
     @Override
 127  
     protected final void configureShiro() {
 128  5
         bindBeanType(TypeLiteral.get(ServletContext.class), Key.get(ServletContext.class, Names.named(NAME)));
 129  5
         bind(Key.get(ServletContext.class, Names.named(NAME))).toInstance(this.servletContext);
 130  5
         bindWebSecurityManager(bind(WebSecurityManager.class));
 131  5
         bindWebEnvironment(bind(WebEnvironment.class));
 132  5
         bind(GuiceShiroFilter.class).asEagerSingleton();
 133  5
         expose(GuiceShiroFilter.class);
 134  
 
 135  5
         this.configureShiroWeb();
 136  
 
 137  5
         setupFilterChainConfigs();
 138  
 
 139  5
         bind(FilterChainResolver.class).toProvider(new FilterChainResolverProvider(filterChains));
 140  5
     }
 141  
 
 142  
     private void setupFilterChainConfigs() {
 143  5
         Map<Key<? extends PathMatchingFilter>, Map<String, String>> configs = new HashMap<Key<? extends PathMatchingFilter>, Map<String, String>>();
 144  
 
 145  5
         for (Map.Entry<String, Key<? extends Filter>[]> filterChain : filterChains.entrySet()) {
 146  8
             for (int i = 0; i < filterChain.getValue().length; i++) {
 147  4
                 Key<? extends Filter> key = filterChain.getValue()[i];
 148  4
                 if (key instanceof FilterConfigKey) {
 149  2
                     FilterConfigKey<? extends PathMatchingFilter> configKey = (FilterConfigKey<? extends PathMatchingFilter>) key;
 150  2
                     key = configKey.getKey();
 151  2
                     filterChain.getValue()[i] = key;
 152  2
                     if (!PathMatchingFilter.class.isAssignableFrom(key.getTypeLiteral().getRawType())) {
 153  0
                         throw new ConfigurationException("Config information requires a PathMatchingFilter - can't apply to " + key.getTypeLiteral().getRawType());
 154  
                     }
 155  2
                     if (configs.get(castToPathMatching(key)) == null) configs.put(castToPathMatching(key), new HashMap<String, String>());
 156  2
                     configs.get(castToPathMatching(key)).put(filterChain.getKey(), configKey.getConfigValue());
 157  2
                 } else if (PathMatchingFilter.class.isAssignableFrom(key.getTypeLiteral().getRawType())) {
 158  2
                           if (configs.get(castToPathMatching(key)) == null) configs.put(castToPathMatching(key), new HashMap<String, String>());
 159  2
                     configs.get(castToPathMatching(key)).put(filterChain.getKey(), "");
 160  
                 }
 161  
             }
 162  4
         }
 163  5
         for (Key<? extends PathMatchingFilter> filterKey : configs.keySet()) {
 164  4
             bindPathMatchingFilter(filterKey, configs.get(filterKey));
 165  4
         }
 166  5
     }
 167  
 
 168  
     private <T extends PathMatchingFilter> void bindPathMatchingFilter(Key<T> filterKey, Map<String, String> configs) {
 169  4
         bind(filterKey).toProvider(new PathMatchingFilterProvider<T>(filterKey, configs)).asEagerSingleton();
 170  4
     }
 171  
 
 172  
     @SuppressWarnings({"unchecked"})
 173  
     private Key<? extends PathMatchingFilter> castToPathMatching(Key<? extends Filter> key) {
 174  12
         return (Key<? extends PathMatchingFilter>) key;
 175  
     }
 176  
 
 177  
     protected abstract void configureShiroWeb();
 178  
 
 179  
     @SuppressWarnings({"unchecked"})
 180  
     @Override
 181  
     protected final void bindSecurityManager(AnnotatedBindingBuilder<? super SecurityManager> bind) {
 182  5
         bindWebSecurityManager(bind);
 183  5
     }
 184  
 
 185  
     /**
 186  
      * Binds the security manager.  Override this method in order to provide your own security manager binding.
 187  
      * <p/>
 188  
      * By default, a {@link org.apache.shiro.web.mgt.DefaultWebSecurityManager} is bound as an eager singleton.
 189  
      *
 190  
      * @param bind
 191  
      */
 192  
     protected void bindWebSecurityManager(AnnotatedBindingBuilder<? super WebSecurityManager> bind) {
 193  
         try {
 194  8
             bind.toConstructor(DefaultWebSecurityManager.class.getConstructor(Collection.class)).asEagerSingleton();
 195  0
         } catch (NoSuchMethodException e) {
 196  0
             throw new ConfigurationException("This really shouldn't happen.  Either something has changed in Shiro, or there's a bug in ShiroModule.", e);
 197  8
         }
 198  8
     }
 199  
 
 200  
     /**
 201  
      * Binds the session manager.  Override this method in order to provide your own session manager binding.
 202  
      * <p/>
 203  
      * By default, a {@link org.apache.shiro.web.session.mgt.DefaultWebSessionManager} is bound as an eager singleton.
 204  
      *
 205  
      * @param bind
 206  
      */
 207  
     @Override
 208  
     protected void bindSessionManager(AnnotatedBindingBuilder<SessionManager> bind) {
 209  5
         bind.to(ServletContainerSessionManager.class).asEagerSingleton();
 210  5
     }
 211  
 
 212  
     @Override
 213  
     protected final void bindEnvironment(AnnotatedBindingBuilder<Environment> bind) {
 214  5
         bindWebEnvironment(bind);
 215  5
     }
 216  
 
 217  
     protected void bindWebEnvironment(AnnotatedBindingBuilder<? super WebEnvironment> bind) {
 218  8
         bind.to(WebGuiceEnvironment.class).asEagerSingleton();
 219  8
     }
 220  
 
 221  
     /**
 222  
      * Adds a filter chain to the shiro configuration.
 223  
      * <p/>
 224  
      * NOTE: If the provided key is for a subclass of {@link org.apache.shiro.web.filter.PathMatchingFilter}, it will be registered with a proper
 225  
      * provider.
 226  
      *
 227  
      * @param pattern
 228  
      * @param keys
 229  
      */
 230  
     @SuppressWarnings({"UnusedDeclaration"})
 231  
     protected final void addFilterChain(String pattern, Key<? extends Filter>... keys) {
 232  4
         filterChains.put(pattern, keys);
 233  4
     }
 234  
 
 235  
     protected static <T extends PathMatchingFilter> Key<T> config(Key<T> baseKey, String configValue) {
 236  2
         return new FilterConfigKey<T>(baseKey, configValue);
 237  
     }
 238  
 
 239  
     @SuppressWarnings({"UnusedDeclaration"})
 240  
     protected static <T extends PathMatchingFilter> Key<T> config(TypeLiteral<T> typeLiteral, String configValue) {
 241  0
         return config(Key.get(typeLiteral), configValue);
 242  
     }
 243  
 
 244  
     @SuppressWarnings({"UnusedDeclaration"})
 245  
     protected static <T extends PathMatchingFilter> Key<T> config(Class<T> type, String configValue) {
 246  0
         return config(Key.get(type), configValue);
 247  
     }
 248  
 
 249  2
     private static class FilterConfigKey<T extends PathMatchingFilter> extends Key<T> {
 250  
         private Key<T> key;
 251  
         private String configValue;
 252  
 
 253  
         private FilterConfigKey(Key<T> key, String configValue) {
 254  2
             super();
 255  2
             this.key = key;
 256  2
             this.configValue = configValue;
 257  2
         }
 258  
 
 259  
         public Key<T> getKey() {
 260  2
             return key;
 261  
         }
 262  
 
 263  
         public String getConfigValue() {
 264  2
             return configValue;
 265  
         }
 266  
     }
 267  
 }