Question

I'm trying to figure out how to have Spring Security return a UserDetails object for anonymous users for this call:

SecurityContextHolder.getContext().getAuthentication().getPrincipal()

I know that without special configuration, that call will return a string instead of a UserDetails object you create with a custom UserDetailsService implementation, but I'd rather not constantly check for "if(principal instanceof String)" everywhere. Is there a way to do this with the Spring configuration - a way that will store the anonymous UserDetails object in the user's session context until they log in? Ostensibly, I'd like a unique anonymous UserDetails for each guest so I can track individual usage with it.

I've also noticed that methods I have secured with the "PreAuthorize" annotation don't seem to honour the hasRole check with anonymous users. I'm sure that is a symptom of whatever I'm doing wrong. Here's an example of that:

@RequestMapping(value = "/almanac/new", method = RequestMethod.GET)
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String newSetup(ModelMap model) {

Here's my spring security context (complete except for the enclosing beans node). You can note that I tried enabling the "anonymous"

<debug />
<http pattern="/js/**"  security="none" />
<http pattern="/css/**"  security="none" />
<http pattern="/images/**"  security="none" />
<http pattern="/loggedout.jsp" security="none"/>
<http name="httpSiteMap" use-expressions="true">
    <custom-filter ref="almanacUsrPwdAuthProcFilter" before="FORM_LOGIN_FILTER"/>
    <intercept-url pattern="/login*" access="isAnonymous()" />
    <intercept-url pattern="/home/**" access="hasRole('ROLE_USER')" />
    <intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" />
    <intercept-url pattern="/**" access="isAnonymous()" />
    <form-login  login-page="/login.jsp"
                 default-target-url="/home.htm"
                 always-use-default-target="false" />
    <logout logout-success-url="/loggedout.jsp" delete-cookies="JSESSIONID"/>
    <session-management invalid-session-url="/timeout.jsp">
        <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
    </session-management>
    <anonymous enabled="true" />
</http>

<global-method-security pre-post-annotations="enabled" secured-annotations="enabled" />

<authentication-manager alias="mainAuthMgr">
    <authentication-provider ref="almanacAuthenticationProvider"/>
</authentication-manager>

Any other suggestions based on the code you see here would be welcome.

Was it helpful?

Solution

You haven't really given much detail on what data you want to extract from the UserDetails for an anonymous user. If you just want to check the user name, you can use Authentication.getName().

In any case, if you need more detailed access to the security context, it is a good idea to use a custom interface to decouple your application code from Spring Security classes (see my answer on using a security context accessor). That way you should only be checking the type of the principal in one place, rather than repeating the check "everywhere" that you want to access the user data.

If you absolutely want to always have the same principal type in the authentication object, regardless of whether the user is anonymous, then you would have to disable anonymous authentication via the namespace and add a custom filter to do the job, based on the existing AnonymousAuthenticationFilter.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top