SpringSecurity WithSecurityContext MockMvc OAuth2 is always unauthorized

I followed the links below to try and verify OAuth2 @PreAuthorise (e.g. hasAnyRole ('ADMIN', 'TEST'), but I cannot pass any tests or even authenticate.

When I try to access an endpoint using an administrator (or any role), it will never authenticate properly. I missed something obvious, it seems I have everything as in the examples. I also tried another alternative WithSecurityContext Factory with OAuth Independent Authentication and still no luck. Any help would be appreciated.

https://stackoverflow.com/a/4646262/2126328

My controller I am testing

@RestController @RequestMapping("/bookmark/") public class GroupBookmarkController { @Autowired BookmarkService bookmarkService; /** * Get list of all bookmarks */ @RequestMapping(value = "{groupId}", method = RequestMethod.GET) @PreAuthorize("hasAnyRole(['ADMIN', 'USER'])") public ResponseEntity<List<Bookmark>> listAllGroupBookmarks(@PathVariable("groupId") String groupId) throws BookmarkNotFoundException { List<Bookmark> bookmarks = bookmarkService.findAllBookmarksByGroupId(groupId); return new ResponseEntity<>(bookmarks, HttpStatus.OK); } ... } 

My testing class

 @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = BookmarkServiceApplication.class) @WebAppConfiguration public class BookmarkServiceApplicationTests { private MockMvc mockMvc; @Autowired private WebApplicationContext webApplicationContext; @Before public void loadData() { this.mockMvc = MockMvcBuilders .webAppContextSetup(webApplicationContext) .apply(springSecurity()) .alwaysDo(print()) .build(); } @Test @WithMockCustomUser(username = "test") public void getBookmarkAuthorised() throws Exception { mockMvc.perform(get("/bookmark/nvjdbngkjlsdfngkjlfdsnlkgsd")) .andExpect(status().is(HttpStatus.SC_OK)); // always 401 here } } 

My BookmarkServiceApplication

 @SpringBootApplication @EnableResourceServer public class BookmarkServiceApplication { public static void main(String[] args) { SpringApplication.run(BookmarkServiceApplication.class, args); } } 

My WithSecurityContextFactory

 public class WithMockCustomUserSecurityContextFactory implements WithSecurityContextFactory<WithMockCustomUser> { @Override public SecurityContext createSecurityContext(WithMockCustomUser customUser) { SecurityContext context = SecurityContextHolder.createEmptyContext(); List<GrantedAuthority> grantedAuthorities = new ArrayList<>(); grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); UserDetails principal = new User(customUser.username(), "password", true, true, true, true, grantedAuthorities); Authentication authentication = new UsernamePasswordAuthenticationToken( principal, principal.getPassword(), principal.getAuthorities()); context.setAuthentication(authentication); return context; } } 

My WithSecurityContext Annotation

 @Retention(RetentionPolicy.RUNTIME) @WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class) public @interface WithMockCustomUser { String username() default "user"; String name() default "Test User"; } 

According to @RobWinch answer

Hi @RobWinch I tried your suggestion with the stateless flag, this helped with part of the answer. However, in the answer to this question [Spring OAuth and Boot Integration Test] ( https://stackoverflow.com/a/165282/ ) you mentioned

You no longer need to worry about starting in stateless mode or not

Why do I need to add stateless flags, is this a mistake or do we use it a little differently?

Another thing I need to do to get this to work is to add OAuth2Request and OAuth2Authentication to WithSecurityContextFactory, as you can see in the following

 public class WithMockCustomUserSecurityContextFactory implements WithSecurityContextFactory<WithMockOAuthUser> { @Override public SecurityContext createSecurityContext(WithMockOAuthUser withClient) { // Get the username String username = withClient.username(); if (username == null) { throw new IllegalArgumentException("Username cannot be null"); } // Get the user roles List<GrantedAuthority> authorities = new ArrayList<>(); for (String role : withClient.roles()) { if (role.startsWith("ROLE_")) { throw new IllegalArgumentException("roles cannot start with ROLE_ Got " + role); } authorities.add(new SimpleGrantedAuthority("ROLE_" + role)); } // Get the client id String clientId = withClient.clientId(); // get the oauth scopes String[] scopes = withClient.scope(); Set<String> scopeCollection = Sets.newSet(scopes); // Create the UsernamePasswordAuthenticationToken User principal = new User(username, withClient.password(), true, true, true, true, authorities); Authentication authentication = new UsernamePasswordAuthenticationToken(principal, principal.getPassword(), principal.getAuthorities()); // Create the authorization request and OAuth2Authentication object OAuth2Request authRequest = new OAuth2Request(null, clientId, null, true, scopeCollection, null, null, null, null); OAuth2Authentication oAuth = new OAuth2Authentication(authRequest, authentication); // Add the OAuth2Authentication object to the security context SecurityContext context = SecurityContextHolder.createEmptyContext(); context.setAuthentication(oAuth); return context; } } 
+5
source share
2 answers

The problem is that OAuth2AuthenticationProcessingFilter will clear the SecurityContext if it is marked as stateless. To get around this, configure it to allow state filling from the outside (i.e. Stateless = false).

+2
source

to add additional information on how to set the stateless attribute to false:

in your ResourceServerConfigurerAdapter do the following:

  @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.stateless(false); } 

who worked for me.

+1
source

All Articles