ŁukaszBachman
ŁukaszBachman

Reputation: 33735

Missing ROLE_ANONYMOUS in Spring Security

I have been using Spring Security 2.x for some time now, but recently I switched to 3.x. I always use my own implementation of UserDetails interface and authentication against DB.

Everything works fine (logging in, logging out, url filters, seeing username of authorized user, etc.).

The only thing left to do was to display "Please login" message when user is not authorized. I tried few approaches:

<sec:authorize access="not isAnonymous()">
or
<sec:authorize access="hasRole('ROLE_ANONYMOUS')">
etc.

None of them worked. Finally I added <sec:authentication property="principal.authorities" /> to my home page output to debug what roles user really has. This is what I see:

It looks like I somehow lost the default ROLE_ANONYMOUS authority, which was always added by Spring, if I recall correctly. Was that recently dropped or something? Perhaps I have to take care of this anonymous access in some other manner?

Relevant part of security context:

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

    <!-- UNPROTECTED RESOURCES -->
    <http pattern="/" security="none"/>
    <http pattern="/favicon.ico" security="none"/>
    <http pattern="/home" security="none"/>
    <http pattern="/login*" security="none"/>
    <http pattern="/resources/**" security="none"/>

    <!-- PROTECTED RESOURCES -->
    <http auto-config='true' use-expressions="true">
        <intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
        <intercept-url pattern="/admin/**" access="hasRole('ROLE_USER,ROLE_ADMIN')"/>
        <form-login login-page="/login" default-target-url="/dashboard" authentication-failure-url="/login?login_error=true"/>
        <logout logout-url="/logout"/>
    </http>

    <beans:bean id="userAccountsAuthenticationProvider" class="pl.xxx.utils.UserAccountsAuthenticationProvider" />

    <beans:bean id="saltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource">
        <beans:property name="userPropertyToUse" value="salt" />
    </beans:bean>

    <authentication-manager>
        <authentication-provider user-service-ref="userAccountsAuthenticationProvider">
            <password-encoder ref="standardPasswordEncoder"/>
        </authentication-provider>
    </authentication-manager>
</beans:beans>

Upvotes: 2

Views: 11572

Answers (1)

Grzegorz Rożniecki
Grzegorz Rożniecki

Reputation: 28035

Anonymous Authentication can be configured in few different ways - do you use <http auto-config="true">, <anonymous> tag or define beans by yourself as custom filter? It'll be easier if you posted your security-context.xml.

Anyway, you want to display "Please login", so I assume you really wanted

<sec:authorize access="isAnonymous()">Please login</sec:authorize>

without "not" (by the way I can't find if "not" is a valid part of expression in this context).

Another way is to use isAuthenticated() instead, negate it in EL and see if it works in your case:

<sec:authorize access="isAuthenticated()" var="isAuthenticated" />
<c:if test="${not isAuthenticated}">
  <!-- do stuff -->
</c:if>

EDIT:

Change security="none" to access="IS_AUTHENTICATED_ANONYMOUSLY" and move chosen patterns to intercept-url. It should enable Spring Security's Filter Chain and apply AnonymousAuthenticationFilter on request:

<!-- UNPROTECTED RESOURCES -->
<http pattern="/favicon.ico" security="none"/>
<http pattern="/resources/**" security="none"/>

<!-- PROTECTED RESOURCES -->
<http auto-config='true' use-expressions="true">
    <intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    <intercept-url pattern="/home" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    <intercept-url pattern="/login*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    <intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
    <intercept-url pattern="/admin/**" access="hasRole('ROLE_USER,ROLE_ADMIN')"/>
    <form-login login-page="/login" default-target-url="/dashboard" authentication-failure-url="/login?login_error=true"/>
    <logout logout-url="/logout"/>
</http>

assuming you want use isAnonymous() in /, /home and /login*.

My previous solution worked, because with security="none" checking for isAuthenticated() always yielded false, so negating it was like checking for not being loggged.

Upvotes: 3

Related Questions