I am testing a Spring MVC controller that updates a customer's subscription and then immediately refreshes the security context to apply the new settings:

def change(@AuthenticationPrincipal UserDetails userDetails,
        @Valid @ModelAttribute PlanChangeWithTokenForm form,
        SecurityContext securityContext) {

    // re-retrieve in case the person's metadata has changed in the DB but not been reflected in session    
    Person user = people.findByKey(userDetails.username)
    subscriptionService.update(user, form)        
    securityContext.setAuthentication(new CustomUserDetails(user).toAuthentication())

    new ModelAndView(PLAN_PAGE, [updated: true])
}

This works correctly run live. However, when using @WithUserDetails and MockMvc, the change in the context applied in the controller method is discarded between requests, so that when I make a subsequent request I see the stale data.

(This may belong on the main JIRA, but I reported here because it appears to be a problem with the security support, perhaps in TestSecurityContextHolder; changing arbitrary session attributes works as expected.)

Comment From: chrylis

Now that I am returning for further enhancements, the SecurityContext injection has stopped working; instead, Spring is injecting a JDK proxy with no backing targets whatsoever, and so all calls are silently dropped. If using the SecurityContext as a method parameter is not supported (and I don't see an argument resolver for it), I'm mystified whether it worked in the first place (and perhaps an OOTB argument resolver would be worthwhile).

Comment From: rwinch

@chrylis

However, when using @WithUserDetails and MockMvc, the change in the context applied in the controller method is discarded between requests, so that when I make a subsequent request I see the stale data.

@WithUserDetails will establish the same user for ever request. This is as designed. If you want the initial user to only be on the first request you can use .with(user(userDetails)).

This may belong on the main JIRA, but I reported here because it appears to be a problem with the security support

We have moved to GitHub issues, so this is the correct place :) We are hoping GitHub issues will get more community involvement than JIRA was. I'm working with our admin to get redirects in place.

Comment From: chrylis

Is @WithUserDetails supposed to reset the authentication for every request or just every test case? I have some test cases where I need to fiddle with the user's database attributes (which of course happens after the stock Authentication object is created), and modifying the DB and then logging in seems to retain the new login as I expected.

Comment From: rwinch

@chrylis Every request. If you need to control it on each specific request, then you need to use .with(user(userDetails)).

modifying the DB and then logging in seems to retain the new login as I expected.

This is because it will look up the user for each request. So if you update the source, then it will be correct.

Comment From: chrylis

This actually works the way that I expected it to (login does update the security context persistently). I'm using the MockMvc HtmlUnit support, so the .with isn't even an option.

Comment From: LajosPolya

Was this issue originally resolved? I'm running into the exact same problem.

Comment From: jzheaux

@LajosPolya can you clarify what you mean by "the exact same problem"? I believe it was resolved that there was nothing to do on this ticket, so we'll need more information to help point you in the right direction.

Comment From: LajosPolya

@jzheaux If I recall correctly, if I annotated a test class with WithUserDetails annotation then only the first API call I made would be authenticated. Every consecutive API call would have an empty SecurityContext so I would have to manually set it.

Comment From: jzheaux

@WithUserDetails applies for the surrounding test. From the docs:

By default the SecurityContext is set during the TestExecutionListener.beforeTestMethod event. This is the equivalent of happening before JUnit’s @Before.

What that means is that every API call within a given annotated test would use the same SecurityContext.

If you still feel like there's an issue, consider filing a separate ticket with more details about what you are experiencing.