spring-webflux-security-jwt icon indicating copy to clipboard operation
spring-webflux-security-jwt copied to clipboard

Split responsibility of ServerHttpBearerAuthenticationConverter

Open eximius313 opened this issue 7 years ago • 1 comments

I think ServerHttpBearerAuthenticationConverter should be used only for preparing the token for further processing:

Mono.justOrEmpty(serverWebExchange)
                .map(JWTAuthorizationPayload::extract)

while authenticating the token:

map(VerifySignedJWT::check)
                .map(UsernamePasswordAuthenticationFromJWTToken::create)

is the responsibility of JWTReactiveAuthenticationManager

By the way - instead of providing own implementation of JWTAuthorizationWebFilter just do:

@Component
public class JWTAuthenticationWebFilter extends AuthenticationWebFilter {

    public JWTAuthenticationWebFilter(final JWTAuthenticationManager authenticationManager,
            final ServerHttpBearerAuthenticationConverter converter,
            final UnauthorizedAuthenticationEntryPoint entryPoint) {
        super(authenticationManager);
        setAuthenticationConverter(converter);
        setAuthenticationFailureHandler(new ServerAuthenticationEntryPointFailureHandler(entryPoint));
        setRequiresAuthenticationMatcher(new JWTHeadersExchangeMatcher()); //this is necessary to match headers. Requests without JWT header should not be taken into account by this filter
    }
    private static class JWTHeadersExchangeMatcher implements ServerWebExchangeMatcher {

        @Override
        public Mono<MatchResult> matches(final ServerWebExchange exchange) {
            return Mono.just(exchange)
                    .map(ServerWebExchange::getRequest)
                    .map(ServerHttpRequest::getHeaders)
                    .filter(h -> h.containsKey("some JWT header"))
                    .flatMap($ -> MatchResult.match())
                    .switchIfEmpty(MatchResult.notMatch());
        }
    }
}

And don't forget to set:

        http
            .exceptionHandling()
                .authenticationEntryPoint(new UnauthorizedAuthenticationEntryPoint ())
            .and()

where

@Component
public class UnauthorizedAuthenticationEntryPoint implements ServerAuthenticationEntryPoint {

	@Override
	public Mono<Void> commence(final ServerWebExchange exchange, final AuthenticationException e) {
		return Mono.fromRunnable(() -> exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED));
	}
}

otherwise SpringSecurity will still display BasicAuth on requests without headers

eximius313 avatar Apr 05 '18 11:04 eximius313

🤔 thank you for your suggestion. I will go through this and see what I can do

raphaelDL avatar Apr 07 '18 16:04 raphaelDL