Announcement Announcement Module
Collapse
No announcement yet.
MVC Controller method security not working Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • MVC Controller method security not working

    Hi,

    I am trying to secure my web controllers. I am using the non annotation based Spring MVC configuration. When i try to secure my controller method as follows, it does not appear to have any affect as I can access the controller with any role:

    Code:
    public class MainAdminController extends AbstractController {
    
        @Override
        @PreAuthorize("hasRole('ROLE_ADMIN')")
        public ModelAndView handleRequestInternal(final HttpServletRequest arg0, final HttpServletResponse arg1) throws Exception {
     
            final ModelAndView mav = new ModelAndView("adminpage");
            return mav;
        }
    The following are my 3 basic configuration files (the dispatcher's -servlet.xml , applicationContext.xml , and the security context xml files) I have omitted the xmlns declarations here for clarity:

    spring-servlet.xml

    Code:
      <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" 
        		p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
    
      <bean id="simpleUrlMapping"  class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
              <prop key="/auth/login.htm">loginLogoutController</prop>
              <prop key="/main/admin.htm">mainAdminController</prop>
             </props>
        </property>
     </bean>
    spring-security.xml

    Code:
     	<security:global-method-security pre-post-annotations="enabled" />
    	<security:http auto-config="true" use-expressions="true" access-denied-page="/auth/denied.htm" >
    		<security:form-login
    				login-page="/auth/login.htm" 
    				authentication-failure-url="/auth/login.htm?error=true" 
    				default-target-url="/main/admin.htm"/>
    			
    		<security:logout 
    				invalidate-session="true" 
    				logout-success-url="/auth/login.htm" 
    				logout-url="/auth/logout.htm"/>
    	</security:http>
    	
    
    	<security:authentication-manager>
    	        <security:authentication-provider user-service-ref="userDetailsService">
    	        </security:authentication-provider>
    	</security:authentication-manager>
    
    	 <security:user-service id="userDetailsService">
    	    <security:user name="admin" password="admin" authorities="ROLE_USER, ROLE_ADMIN" />
    	    <security:user name="user" password="user" authorities="ROLE_USER" />
    	  </security:user-service>
    applicationContext.xml

    Code:
     <bean id="loginLogoutController" class="com.jpmorgan.rps.sandbox.controller.LoginLogoutController">
      </bean>
    
      <bean id="mainAdminController" class="com.jpmorgan.rps.sandbox.controller.MainAdminController">
      </bean>
    Any help would be greatly appreciated. FYI...my output log shows the controller being proxied by Spring:

    Code:
    [DEBUG] (DefaultSingletonBeanRegistry.java:getSingleton:214) Creating shared instance of singleton bean 'mainAdminController'
    [DEBUG] (AbstractAutowireCapableBeanFactory.java:createBean:430) Creating instance of bean 'mainAdminController'
    [DEBUG] (AbstractAutowireCapableBeanFactory.java:doCreateBean:504) Eagerly caching bean 'mainAdminController' to allow for resolving potential circular references
    [DEBUG] (AbstractBeanFactory.java:doGetBean:242) Returning cached instance of singleton bean 'org.springframework.security.methodSecurityMetadataSourceAdvisor'
    [DEBUG] (PrePostAnnotationSecurityMetadataSource.java:findAnnotation:93) @org.springframework.security.access.prepost.PreAuthorize(value=hasRole('ROLE_ADMIN')) found on specific method: public org.springframework.web.servlet.ModelAndView com.jpmorgan.rps.sandbox.controller.MainAdminController.handleRequestInternal(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.lang.Exception
    [DEBUG] (DelegatingMethodSecurityMetadataSource.java:getAttributes:66) Adding security method [CacheKey[com.jpmorgan.rps.sandbox.controller.MainAdminController; public org.springframework.web.servlet.ModelAndView com.jpmorgan.rps.sandbox.controller.MainAdminController.handleRequestInternal(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.lang.Exception]] with attributes [[authorize: 'hasRole('ROLE_ADMIN')', filter: 'null', filterTarget: 'null']]
    [DEBUG] (AbstractAutoProxyCreator.java:buildAdvisors:537) Creating implicit proxy for bean 'mainAdminController' with 0 common interceptors and 1 specific interceptors
    [DEBUG] (JdkDynamicAopProxy.java:getProxy:113) Creating JDK dynamic proxy: target source is SingletonTargetSource for target object [[email protected]]
    [DEBUG] (AbstractAutowireCapableBeanFactory.java:createBean:458) Finished creating instance of bean 'mainAdminController'
    However, the issue is that i am able to hit the MainAdminController as any user, regardless of what role that user may have.

    Thanks

  • #2
    Additional information i did not mention above:

    I am using spring 3.0.5 and spring-security 3.0.5

    If i use annotation based spring mvc controller configuration, then i am able to successfully secure the controller methods. However when i switch to the non-annotation based mvc controller configuration then none of the spring-security method annotations (i.e. @PreAuthorize , @Secured etc) work on the controller.

    Regardless of which approach i take, i am always able to secure the service layer methods with spring security annotations.

    So, it appears that i am simply unable to use spring security to secure spring MVC controllers when i use the non-annotation based spring mvc configuration.

    Comment


    • #3
      See if the FAQ helps.

      Comment


      • #4
        Hi,

        I did look at that faq as well and tried all possible combinations by moving my <global-method-security> element to the various config files. However that did not help.

        I have also tried to force the use of cglib proxy by putting the proxy-target-class="true" in my <global-method-security> element. That did not help either.

        Thank You !

        Comment


        • #5
          Please post your web.xml

          Comment


          • #6
            Please find my web.xml below.

            FYI...i tried to switch the sequence of the files in the contextConfigLocation from

            /WEB-INF/applicationContext.xml
            /WEB-INF/spring-security.xml
            to
            /WEB-INF/spring-security.xml
            /WEB-INF/applicationContext.xml

            but that did not help either.

            Code:
            <?xml version="1.0" encoding="UTF-8"?>
            <web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
            
            	<filter>
            	        <filter-name>springSecurityFilterChain</filter-name>
            	        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
            	</filter>
            	
            	<filter-mapping>
            	        <filter-name>springSecurityFilterChain</filter-name>
            	        <url-pattern>/*</url-pattern>
            	</filter-mapping>
            
            	<context-param>
            		<param-name>contextConfigLocation</param-name>
            		<param-value>
                    /WEB-INF/applicationContext.xml
            		/WEB-INF/spring-security.xml
            		</param-value>
            	</context-param>
            	
            	<servlet>
            		<servlet-name>spring</servlet-name>
            		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            		<load-on-startup>1</load-on-startup>
            	</servlet>
            	
            	<servlet-mapping>
            		<servlet-name>spring</servlet-name>
            		<url-pattern>*.htm</url-pattern>
            	</servlet-mapping>
            
            	<listener>
            		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
            	</listener>
              
                <welcome-file-list>
                    <welcome-file>index.jsp</welcome-file>
                </welcome-file-list>
              
            	
            </web-app>
            Thank You !

            Comment


            • #7
              From what you have posted here, it does not look like the Spring Security configuration is included in your mvc configuration. If you are trying to secure the controllers, try placing the global-security element into the spring-servlet.xml

              Comment


              • #8
                My spring-servlet.xml now looks like the one below. It still does not resolve the problem.

                Code:
                <?xml version="1.0" encoding="UTF-8"?>
                <beans xmlns="http://www.springframework.org/schema/beans"
                       xmlns:security="http://www.springframework.org/schema/security"
                	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                	xmlns:p="http://www.springframework.org/schema/p" 
                	xsi:schemaLocation="http://www.springframework.org/schema/beans 
                	   		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                                    http://www.springframework.org/schema/security 
                            http://www.springframework.org/schema/security/spring-security-3.0.xsd">
                	 
                  <security:global-method-security pre-post-annotations="enabled" />
                  
                  <bean id="loginLogoutController" class="com.jpmorgan.rps.sandbox.controller.LoginLogoutController">
                  </bean>
                
                  <bean id="mainAdminController" class="com.jpmorgan.rps.sandbox.controller.MainAdminController">
                  </bean>
                
                  <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" 
                    		p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
                
                  <bean id="simpleUrlMapping"  class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
                    <property name="mappings">
                        <props>
                          <prop key="/auth/login.htm">loginLogoutController</prop>
                          <prop key="/main/admin.htm">mainAdminController</prop>
                          <prop key="/main/admin2.htm">mainAdmin2Controller</prop>
                         </props>
                    </property>
                </bean>
                
                
                </beans>
                Thanks

                Comment


                • #9
                  Ensure you are not creating your controllers anywhere else also. For example, remove the controllers from the applicationContext.xml. Also you will probably need to ensure you specify to proxy classes.

                  Comment


                  • #10
                    Hi rwinch,

                    I have validated that i did not have my controllers defined anywhere else.

                    Can you please elaborate a little on what you mean by "you will probably need to ensure you specify to proxy classes." ?

                    Thank you for your time.

                    Comment


                    • #11
                      Originally posted by amitter View Post
                      I have validated that i did not have my controllers defined anywhere else.
                      So you removed it from your applicationContext.xml? Previously you posted an applicationContext.xml that defined the controllers.

                      Originally posted by amitter View Post
                      applicationContext.xml

                      Code:
                       <bean id="loginLogoutController" class="com.jpmorgan.rps.sandbox.controller.LoginLogoutController">
                        </bean>
                      
                        <bean id="mainAdminController" class="com.jpmorgan.rps.sandbox.controller.MainAdminController">
                        </bean>

                      Originally posted by amitter View Post
                      Can you please elaborate a little on what you mean by "you will probably need to ensure you specify to proxy classes." ?.
                      I mean you probably need to use

                      Code:
                      <security:global-method-security proxy-target-class="true"/>
                      You might consider looking at this blog post as it goes into details about security Spring MVC controllers with the global-method-security element. I haven't looked through the blog but it appears to be pretty comprehensive.

                      Cheers,

                      Comment


                      • #12
                        Hi, I have had a similar problem.
                        I believe you cannot annotate a method unless it is externally visible.
                        As you are extending AbstractController you are overriding handleRequestInternal (not externally visable) so the annotation isnt working.
                        AbstractController implements handleRequest which is the externally visible method you need to place your annotation on.
                        To make a long story short, add the following method to your controller and remove your secured annotation from handleRequestInternal and place it over this new method. This puts your secured annotation on handleRequest and calls the super class (AbstractController) version of it.

                        @Override
                        @Secured("ROLE_ADMIN")
                        public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
                        return super.handleRequest(request, response);
                        }

                        Comment


                        • #13
                          Good catch...I did not notice that this was the handleRequestInternal.

                          Comment


                          • #14
                            charliefryer,

                            Thank you very much for that great insight. I tried your recommended approach and i am seeing the expected behavior now !

                            Thanks!

                            Comment


                            • #15
                              @Secure Not working

                              my @Secured annotation inside my @Controller method is not working.

                              this is the snippet from my controller

                              @RequestMapping(value = "/admin/user/user-list", method = RequestMethod.GET)
                              @Secured(value = "USER_CREATE")
                              public ModelAndView getUserList() {
                              _LOG.debug("here");
                              }

                              ================================================== ====================================
                              in my security context i have enable @Secured annotation by: <sec:global-method-security secured-annotations="enabled"/>

                              this is the snippet from my security context

                              <sec:http entry-point-ref="casEntryPoint" use-expressions="true">
                              <sec:intercept-url pattern="/admin/user/**" access="hasAnyRole('USER_VIEW','USER_UPDATE','USER _DELETE')"/>
                              </sec:http>


                              The 'logged user' has only one role which is "USER_VIEW"

                              As far as I know, it shouldn't display the message 'here' but the message 'here' is still displayed in the console.

                              Comment

                              Working...
                              X