|
@@ -1,5 +1,5 @@
|
|
/*
|
|
/*
|
|
- * Copyright 2002-2017 the original author or authors.
|
|
|
|
|
|
+ * Copyright 2002-2021 the original author or authors.
|
|
*
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* you may not use this file except in compliance with the License.
|
|
@@ -18,9 +18,18 @@ package org.springframework.security.web.server.authorization;
|
|
|
|
|
|
import reactor.core.publisher.Mono;
|
|
import reactor.core.publisher.Mono;
|
|
|
|
|
|
|
|
+import org.springframework.context.MessageSource;
|
|
|
|
+import org.springframework.context.MessageSourceAware;
|
|
|
|
+import org.springframework.context.support.MessageSourceAccessor;
|
|
import org.springframework.http.HttpStatus;
|
|
import org.springframework.http.HttpStatus;
|
|
import org.springframework.security.access.AccessDeniedException;
|
|
import org.springframework.security.access.AccessDeniedException;
|
|
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
|
|
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
|
|
|
|
+import org.springframework.security.authentication.AuthenticationTrustResolver;
|
|
|
|
+import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
|
|
|
|
+import org.springframework.security.authentication.InsufficientAuthenticationException;
|
|
|
|
+import org.springframework.security.core.Authentication;
|
|
|
|
+import org.springframework.security.core.AuthenticationException;
|
|
|
|
+import org.springframework.security.core.SpringSecurityMessageSource;
|
|
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
|
|
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
|
|
import org.springframework.security.web.server.authentication.HttpBasicServerAuthenticationEntryPoint;
|
|
import org.springframework.security.web.server.authentication.HttpBasicServerAuthenticationEntryPoint;
|
|
import org.springframework.util.Assert;
|
|
import org.springframework.util.Assert;
|
|
@@ -30,20 +39,30 @@ import org.springframework.web.server.WebFilterChain;
|
|
|
|
|
|
/**
|
|
/**
|
|
* @author Rob Winch
|
|
* @author Rob Winch
|
|
|
|
+ * @author César Revert
|
|
* @since 5.0
|
|
* @since 5.0
|
|
*/
|
|
*/
|
|
-public class ExceptionTranslationWebFilter implements WebFilter {
|
|
|
|
|
|
+public class ExceptionTranslationWebFilter implements WebFilter, MessageSourceAware {
|
|
|
|
|
|
private ServerAuthenticationEntryPoint authenticationEntryPoint = new HttpBasicServerAuthenticationEntryPoint();
|
|
private ServerAuthenticationEntryPoint authenticationEntryPoint = new HttpBasicServerAuthenticationEntryPoint();
|
|
|
|
|
|
private ServerAccessDeniedHandler accessDeniedHandler = new HttpStatusServerAccessDeniedHandler(
|
|
private ServerAccessDeniedHandler accessDeniedHandler = new HttpStatusServerAccessDeniedHandler(
|
|
HttpStatus.FORBIDDEN);
|
|
HttpStatus.FORBIDDEN);
|
|
|
|
|
|
|
|
+ private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
|
|
|
|
+
|
|
|
|
+ protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
|
|
|
+
|
|
@Override
|
|
@Override
|
|
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
|
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
|
- return chain.filter(exchange).onErrorResume(AccessDeniedException.class,
|
|
|
|
- (denied) -> exchange.getPrincipal().switchIfEmpty(commenceAuthentication(exchange, denied))
|
|
|
|
- .flatMap((principal) -> this.accessDeniedHandler.handle(exchange, denied)));
|
|
|
|
|
|
+ return chain.filter(exchange).onErrorResume(AccessDeniedException.class, (denied) -> exchange.getPrincipal()
|
|
|
|
+ .filter((principal) -> (!(principal instanceof Authentication) || (principal instanceof Authentication
|
|
|
|
+ && !(this.authenticationTrustResolver.isAnonymous((Authentication) principal)))))
|
|
|
|
+ .switchIfEmpty(commenceAuthentication(exchange,
|
|
|
|
+ new InsufficientAuthenticationException(
|
|
|
|
+ this.messages.getMessage("ExceptionTranslationWebFilter.insufficientAuthentication",
|
|
|
|
+ "Full authentication is required to access this resource"))))
|
|
|
|
+ .flatMap((principal) -> this.accessDeniedHandler.handle(exchange, denied)).then());
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -66,7 +85,28 @@ public class ExceptionTranslationWebFilter implements WebFilter {
|
|
this.authenticationEntryPoint = authenticationEntryPoint;
|
|
this.authenticationEntryPoint = authenticationEntryPoint;
|
|
}
|
|
}
|
|
|
|
|
|
- private <T> Mono<T> commenceAuthentication(ServerWebExchange exchange, AccessDeniedException denied) {
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Sets the authentication trust resolver.
|
|
|
|
+ * @param authenticationTrustResolver the authentication trust resolver to use.
|
|
|
|
+ * Default is {@link AuthenticationTrustResolverImpl}
|
|
|
|
+ *
|
|
|
|
+ * @since 5.5
|
|
|
|
+ */
|
|
|
|
+ public void setAuthenticationTrustResolver(AuthenticationTrustResolver authenticationTrustResolver) {
|
|
|
|
+ Assert.notNull(authenticationTrustResolver, "authenticationTrustResolver must not be null");
|
|
|
|
+ this.authenticationTrustResolver = authenticationTrustResolver;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * @since 5.5
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public void setMessageSource(MessageSource messageSource) {
|
|
|
|
+ Assert.notNull(messageSource, "messageSource cannot be null");
|
|
|
|
+ this.messages = new MessageSourceAccessor(messageSource);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private <T> Mono<T> commenceAuthentication(ServerWebExchange exchange, AuthenticationException denied) {
|
|
return this.authenticationEntryPoint
|
|
return this.authenticationEntryPoint
|
|
.commence(exchange, new AuthenticationCredentialsNotFoundException("Not Authenticated", denied))
|
|
.commence(exchange, new AuthenticationCredentialsNotFoundException("Not Authenticated", denied))
|
|
.then(Mono.empty());
|
|
.then(Mono.empty());
|