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