Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Security - how I can enable Method Security annotations?

There is lot of similar questions at StackOverflow, but I can't find any answered :(

I have web.xml like:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /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>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring-web.xml</param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<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>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

and trying to configure method security with annotations. As I see it must be done by <sec:global-method-security pre-post-annotations="enabled"/>, placed at same context as other components, spring-web.xml at my case. So I have following spring-web.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:sec="http://www.springframework.org/schema/security"
       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"
        default-autowire="byName">

    <context:component-scan base-package="com.cleanplates.apiserv"/>
    <sec:global-method-security pre-post-annotations="enabled"/>

</beans>

and spring-security.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:sec="http://www.springframework.org/schema/security"
       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">

    <bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
        <sec:filter-chain-map path-type="ant">
            <sec:filter-chain pattern="/**"
                              filters="
                                usernamePasswordProcessingFilter,
                                rememberMeFilter,
                                anonymousProcessingFilter,
                                exceptionTranslationFilter,
                                filterInvocationInterceptor"/>
        </sec:filter-chain-map>
    </bean>

    <bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
        <property name="decisionVoters">
            <list>
                <bean class="org.springframework.security.access.vote.RoleVoter"/>
            </list>
        </property>
    </bean>

    <bean id="anonymousProcessingFilter"
          class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
        <property name="key" value="********"/>
        <property name="userAttribute">
            <bean class="org.springframework.security.core.userdetails.memory.UserAttribute">
                <property name="authoritiesAsString">
                    <list>
                        <value>ROLE_ANONYMOUS</value>
                    </list>
                </property>
                <property name="password" value="none"/>
            </bean>
        </property>
    </bean>

    <bean id="usernamePasswordProcessingFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
        <property name="filterProcessesUrl" value="/auth/password"/>
        <property name="usernameParameter" value="username"/>
        <property name="passwordParameter" value="password"/>
        <property name="authenticationManager" ref="authenticationManager"/>
    </bean>

    <bean id="rememberMeFilter" class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
        <property name="rememberMeServices" ref="rememberMeServices"/>
        <property name="authenticationManager" ref="authenticationManager" />
    </bean>

    <bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
        <property name="userDetailsService" ref="myUserDetailsService"/>
        <property name="key" value="*******"/>
        <property name="alwaysRemember" value="true"/>
    </bean>

    <bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
        <property name="key" value="******"/>
    </bean>

    <bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter">
        <property name="authenticationEntryPoint">
            <bean class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/>
        </property>
    </bean>

    <bean id="filterInvocationInterceptor"
        class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="securityMetadataSource">
            <sec:filter-security-metadata-source>
              <sec:intercept-url pattern="/**" access="ROLE_ANONYMOUS,ROLE_USER" method="GET"/>
              <sec:intercept-url pattern="/**" access="ROLE_ADMIN" method="POST"/>
              <sec:intercept-url pattern="/**" access="ROLE_ADMIN" method="PUT"/>
              <sec:intercept-url pattern="/**" access="ROLE_ADMIN" method="DELETE"/>
            </sec:filter-security-metadata-source>
        </property>
        <property name="accessDecisionManager" ref="accessDecisionManager"/>
    </bean>

    <bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
        <property name="providers">
            <list>
                <bean class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
                    <property name="key" value="***"/>
                </bean>
                <bean class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
                    <property name="saltSource">
                        <bean class="org.springframework.security.authentication.dao.ReflectionSaltSource">
                            <property name="userPropertyToUse" value="salt"/>
                        </bean>
                    </property>
                    <property name="userDetailsService" ref="myUserDetailsService"/>
                    <property name="passwordEncoder" ref="passwordEncoder"/>
                </bean>
            </list>
        </property>
    </bean>

    <bean id="myUserDetailsService" class=".UserDetailsServiceImpl">
    </bean>

    <bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder">
    </bean>

</beans>

The problem that after adding <sec:global-method-security all controllers stop working. And I have following in logs:

PageNotFound:noHandlerFound:947 - No mapping found for HTTP request with URI [/some/page] in DispatcherServlet with name 'spring'

Everything is working when i remove this global-security element. If i'm adding it into spring-security.xml - nothing changes. Seems that it's not used, because methods annotated with @PreAuthorize("hasRole('ROLE_ADMIN')") (or any other role) are accessible by anyone.

PS I'm using Spring 3.0.5.RELEASE and Spring Security 3.0.5.RELEASE

like image 212
Igor Artamonov Avatar asked Nov 05 '22 10:11

Igor Artamonov


1 Answers

After you enable <sec:global-method-security> spring security creates proxies for your controllers. spring-mvc can't find annotations like @RequestMapping on bean in this case. If you want to use security annotations on your controllers you should extract interface of controller and put mvc annotations on it. Spring documentation contains following note about this:

NOTE: When using controller interfaces (e.g. for AOP proxying), make sure to consistently put all your mapping annotations - such as @RequestMapping and @SessionAttributes - on the controller interface rather than on the implementation class.

like image 156
qnox Avatar answered Nov 15 '22 11:11

qnox