Results 1 to 8 of 8

Thread: PreAuthorize being ignored

  1. #1

    Question PreAuthorize being ignored

    Hi all,

    I hope someone here can help with this, been stuck for a while.....

    Annotating with PreAuthorize on my controllers works perfectly but the annotations are being ignored if I annotate the DAO interface or it's implementation. I've put an invalid expression in the annotation (which causes exception in the controller for every request) on the implementation bean to be sure it's ignoring it.

    The only thing I can think of is that the bean isn't spring managed but it autowires OK so I guess it must be. The controllers are in uk.co.powergroup.portal.controller and the DAO implementation beans are in uk.co.powergroup.portal.dao.impl.

    With the below I always see the RuntimeException.

    The relevant part of the DAO implementation is:

    Code:
    package uk.co.powergroup.portal.dao.impl;
    
    @Repository
    public class UserDaoImpl implements UserDao
    {
    	@Override
    	@PreAuthorize("#p.equals('OK')") // Should fail as p is not a parameter
    	public void setPassword(HttpSession session, String password, String newPassword)
    	{
    		throw new RuntimeException("setPassword called");
    	}
    }
    My spring context:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:aop="http://www.springframework.org/schema/aop"
    	xmlns:context="http://www.springframework.org/schema/context"
    	xmlns:mvc="http://www.springframework.org/schema/mvc"
    	xmlns:p="http://www.springframework.org/schema/p"
    	xmlns:sec="http://www.springframework.org/schema/security"
    	xmlns:tx="http://www.springframework.org/schema/tx"
    	xmlns:util="http://www.springframework.org/schema/util"
    	xmlns:jee="http://www.springframework.org/schema/jee"
    	xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
    		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
    		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd
    		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
    		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    
       <bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver" p:basename="views" p:order="1"/>
    
        <context:component-scan base-package="uk.co.powergroup.portal.dao.impl" />
        <context:component-scan base-package="uk.co.powergroup.portal.controller" />
             
        <jee:jndi-lookup id="dataSource" resource-ref="true" jndi-name="jdbc/PortalDataSource"/>
         
        <bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    		<property name="dataSource" ref="dataSource"/>
    		<property name="loadTimeWeaver">
        		<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
    	 	</property>
    	 </bean>
    
      <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="myEmf"/>
      </bean>
    
      <bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer" p:definitions="/WEB-INF/tiles-defs.xml"/> 
    
      <tx:advice id="txAdvice" transaction-manager="txManager">
      <tx:attributes>
        <!-- all methods starting with 'get' are read-only -->
        <tx:method name="get*" read-only="true"/>
        <tx:method name="*" read-only="false"
        	no-rollback-for="org.springframework.security.core.AuthenticationException"
       	/>
      </tx:attributes>
      </tx:advice>
    
      <aop:config>
      <aop:pointcut id="txOperationController" expression="execution(* uk.co.powergroup.portal.controller.*.*(..))"/>
      <aop:pointcut id="txOperationSecurity" expression="execution(* uk.co.powergroup.portal.security.*.*(..))"/>
      <aop:advisor advice-ref="txAdvice" pointcut-ref="txOperationController"/>
      <aop:advisor advice-ref="txAdvice" pointcut-ref="txOperationSecurity"/>
      </aop:config>
    
    	<bean id="portalAuthenticator" class="uk.co.powergroup.portal.security.Authenticator"/>
    	
    	<sec:authentication-manager>
    		<sec:authentication-provider ref='portalAuthenticator'/>
    	</sec:authentication-manager>
    	<sec:http auto-config="false" use-expressions="true">
    		<sec:intercept-url pattern="/static/**" filters="none"/>
    		<sec:intercept-url pattern="/logged-out" filters="none"/>
    		<sec:intercept-url pattern="/login" filters="none"/>
        	<!--  <sec:intercept-url pattern="/**" access="isAuthenticated()" />-->
        	<sec:logout logout-url="/logout" logout-success-url="/logged-out"/>
        	<sec:form-login login-page="/login" login-processing-url="/login-security-check" authentication-failure-url="/login?login_error=true" />
        	<sec:custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
        	<sec:session-management session-authentication-strategy-ref="sas"/>
        	<sec:custom-filter ref="userValidator" after="FILTER_SECURITY_INTERCEPTOR"/>
    	</sec:http>
    	<sec:global-method-security pre-post-annotations="enabled" secured-annotations="enabled">
    		<sec:expression-handler ref="expressionHandler"/>
    	</sec:global-method-security>
    	<bean id="userValidator" class="uk.co.powergroup.portal.security.UserValidator">
    	</bean>
    	<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
    		<property name="permissionEvaluator" ref="myPermissionEvaluator"/>
    	</bean>
    	<bean id="myPermissionEvaluator" class="uk.co.powergroup.portal.security.PermissionChecker"/>
        <bean id="concurrencyFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter">
      		<property name="sessionRegistry" ref="sessionRegistry" />
    		<property name="expiredUrl" value="/login" />
    	</bean>
        <bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl"/>
    	<bean id="sas" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">
    		<constructor-arg name="sessionRegistry" ref="sessionRegistry" />
    		<property name="maximumSessions" value="-1"/>
    	</bean>
            
    	
    	<bean id="jsonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
    	    <property name="prefixJson" value="false"/>
        	<property name="supportedMediaTypes" value="application/json"/>
    	</bean>
    	
    	<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    		<property name="messageConverters">
    			<util:list id="beanList">
    				<ref bean="jsonHttpMessageConverter"/>
    			</util:list>
    		</property>
    	</bean>	
    </beans>
    Thanks in advance,

    Peter.

  2. #2

    Default

    Hmm, it's just occurred to me that I'm invoking the DAO method from the controller and Spring Security might not be intercepting the method call. Here's the relevant bit of the controller which is calling the method:

    Code:
    @Controller
    @RequestMapping("/users")
    public class Users
    {
    	@Autowired UserDao dao;
    	
    	@RequestMapping(value="/{id}", method=RequestMethod.PUT)
    	public ModelAndView putUser(@PathVariable("id") int id,
    			@RequestParam(value="new_password") String newPassword,
    			@RequestParam(value="confirm_password") String confirmPassword,
    			@ModelAttribute("user") User user,
    			BindingResult result,
    			HttpSession session)
    	{
    		// Lots of other code skipped
    
    		dao.setPassword(existing, newPassword);
    	}
    }
    Is there a different way I should be invoking the DAO methods?

    Thanks,

    Peter.

  3. #3

    Default

    Can no-one help with this? Seems like it's something simple I'm missing. When I throw an exception from the protected method the stack trace shows the controller calling the method directly so I guess there's no opportunity for Spring to intercept the call however loads of examples on how to do this just say annotate the methods of the DAO/Service interface and it'll work (which in my case it doesn't).

    Thanks,

    Peter.

  4. #4
    Join Date
    Jan 2008
    Posts
    1,826

    Default

    Are you certain your Spring configuration files are not creating the same UserDao twice (this is a common problem when using classpath scanning)? Ensure that there is only one way in which your UserDao will be created (i.e. check both your mvc Spring config and the parent config). If that doesn't help, post your web.xml and other Spring configs.
    Rob Winch - @rob_winch
    Spring Security Lead
    Pivotal

  5. #5
    Join Date
    Sep 2004
    Location
    Manchester, NH
    Posts
    1,236

    Default

    Sorry for the stupid question - are you calling the same setPassword method? The one with the annotation shows 3 parameters, and the one you show in your code listing from the controller has only 2 parameters.

    If there are issues with the AOP proxies not being set up correctly, the only time you will see it is on startup (context initialization) - look carefully at DEBUG level logging at startup time to see if the security annotations are being processed.
    Peter Mularien | Blog
    Author, Spring Security 3 (Book) - Packt Publishing, Available in print and eBook form
    SCJP 5, Oracle DBA
    Any postings are my own opinion, and should not be attributed to my employer or clients.


  6. #6

    Default

    Hi,

    Thanks for your replies I will investigate and report back on Monday when I return from a long weekend holiday

    Until then though:

    Quote Originally Posted by rwinch View Post
    Are you certain your Spring configuration files are not creating the same UserDao twice (this is a common problem when using classpath scanning)? Ensure that there is only one way in which your UserDao will be created (i.e. check both your mvc Spring config and the parent config). If that doesn't help, post your web.xml and other Spring configs.
    Yes I'm fairly sure there aren't two as then I'd get an exception when it tried to autowire. Also wouldn't the annotation apply to both beans?

    Quote Originally Posted by pmularien View Post
    Sorry for the stupid question - are you calling the same setPassword method? The one with the annotation shows 3 parameters, and the one you show in your code listing from the controller has only 2 parameters.

    If there are issues with the AOP proxies not being set up correctly, the only time you will see it is on startup (context initialization) - look carefully at DEBUG level logging at startup time to see if the security annotations are being processed.
    Well spotted regarding the setPassword signature, that was a cut and paste error! I'm sure it's calling the right one.

    I've verified through a stack trace of an exception that there are no proxies between the controller and the DAO and dao.getClass().getName() in the controller gives the class name of the DAO. I'll look at the startup debugging on Monday.

    Thanks for your help!

    Peter.

  7. #7
    Join Date
    Jan 2008
    Posts
    1,826

    Default

    Quote Originally Posted by peter_spikings View Post
    Yes I'm fairly sure there aren't two as then I'd get an exception when it tried to autowire. Also wouldn't the annotation apply to both beans?
    The annotation gets processed only where the BeanPostProcessor is located. So if you are creating two contexts and one of them does not have global-security specified, you may be getting the bean that is not post processed and thus is not secured.
    Rob Winch - @rob_winch
    Spring Security Lead
    Pivotal

  8. #8

    Default

    Hi,

    OK, I got to the bottom of this

    Startup Spring debugging showed it was unable to proxy references to the specific DAO I was trying to test. The reason in the end turned out to be autowiring the DAO into my implementation of PermissionEvaluator. I refactored the application to remove the reference and it's all working fine now.

    Question though: Could Spring be configured (presumably by default) to throw an exception on startup when something annotated with @Controller or @Respository is unable to be proxied? Would have saved a lot of time scratching my head.

    I guess this also means I'll have to test security in unit tests in case something else like this silently disables all the security!

    Thanks,

    Peter.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •