AmanMohla
AmanMohla

Reputation: 129

AOP MethodSecurityInterceptor not getting invoked in Spring Security

I am using Spring Security 3.0.7 and my application is deployed on JBOSS.

I am setting up org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor for my application to add restrictions on invocation of certain methods in services layer. But for some reason the interceptor is not getting called and I am able to invoke all the methods from a user with a role, ROLE_USER. My security.xml looks like this:

<security:http auto-config='true' authentication-manager-ref="authenticationManager" use-expressions="true" request-matcher="ant" create-session="always"
    entry-point-ref="authenticationEntryPoint" >

    <security:intercept-url pattern="/login.jsp" access="permitAll" />
    <security:intercept-url pattern="/configure/" access="hasRole('ROLE_ADMIN')"  />
    <security:intercept-url pattern="/**" access="isAuthenticated()" />

    <security:form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?error=Authentication Failed!" default-target-url="/landing.do" 
    always-use-default-target="true"  />

    <security:logout invalidate-session="true" delete-cookies="true" />


    <security:session-management>
        <security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" expired-url="/login.jsp"/>
    </security:session-management>    
</security:http>

<security:method-security-metadata-source id="securityMetadataSource">
        <security:protect method="com.services.CreateUserService.createUser" access="ROLE_ADMIN"/>
        <security:protect method="com.services.DeleteUser.deleteUser" access="ROLE_ADMIN"/>
</security:method-security-metadata-source>

<security:global-method-security authentication-manager-ref="authenticationManager" access-decision-manager-ref="accessDecisionManager" 
metadata-source-ref="securityMetadataSource" pre-post-annotations="disabled" secured-annotations="disabled" />

<bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
    <property name="loginFormUrl" value="/login.jsp"/>
</bean>

<bean id="myRoleVoter" class="com.interceptors.MyRoleVoter" />

<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager" >
    <property name="providers">
        <list>
            <ref local="daoAuthenticationProvider"/>
        </list>
    </property>
</bean> 

<bean id="accessDecisionManager" class="com.interceptors.MyAccessDecisionManager"  p:allowIfAllAbstainDecisions="false" >
    <property name="decisionVoters">
        <list>
            <ref local="myRoleVoter"/>
        </list>
    </property> 
</bean>


<bean id="methodSecurity" class="org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="accessDecisionManager" ref="accessDecisionManager"/>
        <property name="securityMetadataSource" ref="securityMetadataSource" />
</bean> 

The authentication part is working absolutely fine. However, my MethodSecurityInterceptor is never invoked and hence not even my AccessDecisionManager or RoleVoter.

If I add the reference of my accessDecisionManager in the first line, then my authentication layer stops working. All the requests pass to the AccessDecisionManager with the user as anonymous.

<security:http security="none" pattern="/login.jsp" />

<security:http auto-config='true' authentication-manager-ref="authenticationManager" access-decision-manager-ref="accessDecisionManager" use-expressions="true" request-matcher="ant" create-session="always"
    entry-point-ref="authenticationEntryPoint" >

I know either I am missing some TINY configuration, but I am unable to find that configuration anywhere in the docs.

Upvotes: 1

Views: 3513

Answers (3)

gavenkoa
gavenkoa

Reputation: 48753

Another usual reason why AOP MethodSecurityInterceptor is not invoked - you miss cglib or similar for byte code manipulation.

So only java.lang.reflect.Proxy used and thus it is not possible to proxy private methods! Just make @Secured methods public - and all be fine!

Upvotes: 1

AmanMohla
AmanMohla

Reputation: 129

I have figured out the solution. I have to define two authentication manager and one access decision manager. One authentication manager goes in my root context and would be used by the global method security to create the form login authentication mechanism.

The other authentication manager and the access decision manager goes in services context, where it would be used to create my custom method security interceptor.

applicationContext-Security.xml

<!-- The authentication manager responsible for authenticating the users -->
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager" >
    <property name="providers">
        <list>
            <ref local="daoAuthenticationProvider"/>
        </list>
    </property>
</bean> 

The context file for the services. service.security.xml

    <!--we need a separate authentication manager for method security -->
    <bean id="methodAuthenticationManager" class="org.springframework.security.authentication.ProviderManager" >
        <property name="providers">
            <list>
                <ref local="daoAuthenticationProvider"/>
            </list>
        </property>
    </bean> 

    <!--we need a separate accessDecisionManager for method security -->
    <bean id="methodAccessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased" >
        <property name="decisionVoters">
            <list>
                <ref local="myRoleVoter"/> <!-- the voter will decide weather methodInvocation is allowed or not -->
            </list>
        </property> 
    </bean>

    <!-- The Method Security Interceptor to intercept all the calls to methods -->
    <bean id="methodSecurityInterceptor" class="org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
        <property name="authenticationManager" ref="methodAuthenticationManager"/>
        <property name="accessDecisionManager" ref="methodAccessDecisionManager"/>
        <property name="securityMetadataSource" ref="swiftSecurityMethodMetadataSource" />
    </bean>


<security:method-security-metadata-source id="securityMetadataSource">
    <security:protect method="fullyQualifiedMethod" access="Administrator"/>
</security:method-security-metadata-source>

<security:global-method-security authentication-manager-ref="methodAuthenticationManager" access-decision-manager-ref="methodAccessDecisionManager" 
    metadata-source-ref="swiftSecurityMethodMetadataSource" jsr250-annotations="disabled" secured-annotations="disabled"/>

Upvotes: 1

Boris Treukhov
Boris Treukhov

Reputation: 17774

Possibly, you have declared your MethodSecurityInterceptor in your application root context, and expect it to work for the beans in the servlet context.

If you want global-method-security to work in the servlet context, you should declare it explicitly in the servlet xml configuration.

It's a very common mistake to declare AOP interceptors in the wrong context, so please check that your service layer beans are not being created(for example by autoscanning) in the servlet context.

Upvotes: 1

Related Questions