Spring Security 5.x, WebFlux, Reactive, How to store Authentication in ReactiveSecurityContextHolder

Viewed 1643

I am building a OAuth2 authorization server using Spring Boot 2.3.1 and WebFlux. I am running into a issue. After successfully authenticating, the Authorization object is missing from the ReactiveSecurityContextHolder object.

I have an implementation of ServerSecurityContextRepository which implements the load method as below.

@Override public Mono load(ServerWebExchange swe) {

return swe.getSession().map(WebSession::getAttributes).flatMap((attrs) -> {
  ServerHttpRequest request = swe.getRequest();
  String authHeader = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);

  if (authHeader != null && authHeader.startsWith("Bearer ") && authHeader.contains(" ")) {
    // Split the auth header at space and the second token is the authToken.
    String authToken = authHeader.split(" ")[1];

    try {

// Some code removed here.
      Authentication auth = new UsernamePasswordAuthenticationToken(principal, authToken);
      SecurityContext sc = (SecurityContext)attrs.get(VarahamihirConstants.SECURITY_CONTEXT_ATTRIBUTE);
      if (sc == null) {
        sc = new SecurityContextImpl(auth);
        save(swe, sc);
      }
      final SecurityContext context = sc;
      return this.authenticationManager.authenticate(auth).map((authentication) -> {
        context.setAuthentication(authentication);
        return context;
      });
    } catch (ParseException|JOSEException|BadJOSEException e) {
      return Mono.error(new UnauthorizedException("The auth token is invalid."));
    }
  } else {
    return Mono.empty();
  }
});

}

I also have an implementation of ReactiveAuthenticationManager which implements authenticate method.

public Mono<Authentication> authenticate(Authentication authentication) {
String authToken = authentication.getCredentials().toString();
try {
  Principal principal = authentication.getPrincipal();
  if (!jwtUtil.validateToken(principal.getAuthToken())) {
    return Mono.empty();
  }
// Some code removed.
                Authentication auth = new UsernamePasswordAuthenticationToken(principal,
                        authToken,
                        actualAuthorities);
                return Mono.just(auth);
              })
      return Mono.just(auth);
  }
  //SecurityContextHolder.getContext().setAuthentication(auth);
} catch (Exception e) {
  e.printStackTrace();
  return Mono.error(e);
}
return Mono.error(new UnauthorizedException("Unreachable place."));

}

After this, the code works fine in handling the authentication flow but the ReactiveSecurityContextHolder does not contain any context. Also because of that any of the PrePost annotations can't be used.

I intuitively understand, somewhere I have to save the context into context holder but where?

0 Answers
Related