Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.web.server.authentication;
import java.util.function.Function;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import reactor.core.publisher.Mono;
import org.springframework.core.log.LogMessage;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.ReactiveAuthenticationManagerResolver;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.web.server.WebFilterExchange;
import org.springframework.security.web.server.context.NoOpServerSecurityContextRepository;
import org.springframework.security.web.server.context.ServerSecurityContextRepository;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers;
import org.springframework.util.Assert;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
/**
* A {@link WebFilter} that performs authentication of a particular request. An outline of
* the logic:
*
*
*
A request comes in and if it does not match
* {@link #setRequiresAuthenticationMatcher(ServerWebExchangeMatcher)}, then this filter
* does nothing and the {@link WebFilterChain} is continued. If it does match then...
*
An attempt to convert the {@link ServerWebExchange} into an {@link Authentication}
* is made. If the result is empty, then the filter does nothing more and the
* {@link WebFilterChain} is continued. If it does create an {@link Authentication}...
*
*
The {@link ReactiveAuthenticationManager} specified in
* {@link #AuthenticationWebFilter(ReactiveAuthenticationManager)} is used to perform
* authentication.
*
The {@link ReactiveAuthenticationManagerResolver} specified in
* {@link #AuthenticationWebFilter(ReactiveAuthenticationManagerResolver)} is used to
* resolve the appropriate authentication manager from context to perform authentication.
*
*
If authentication is successful, {@link ServerAuthenticationSuccessHandler} is
* invoked and the authentication is set on {@link ReactiveSecurityContextHolder}, else
* {@link ServerAuthenticationFailureHandler} is invoked
*
*
* @author Rob Winch
* @author Rafiullah Hamedy
* @author Mathieu Ouellet
* @since 5.0
*/
public class AuthenticationWebFilter implements WebFilter {
private static final Log logger = LogFactory.getLog(AuthenticationWebFilter.class);
private final ReactiveAuthenticationManagerResolver authenticationManagerResolver;
private ServerAuthenticationSuccessHandler authenticationSuccessHandler = new WebFilterChainServerAuthenticationSuccessHandler();
private ServerAuthenticationConverter authenticationConverter = new ServerHttpBasicAuthenticationConverter();
private ServerAuthenticationFailureHandler authenticationFailureHandler = new ServerAuthenticationEntryPointFailureHandler(
new HttpBasicServerAuthenticationEntryPoint());
private ServerSecurityContextRepository securityContextRepository = NoOpServerSecurityContextRepository
.getInstance();
private ServerWebExchangeMatcher requiresAuthenticationMatcher = ServerWebExchangeMatchers.anyExchange();
/**
* Creates an instance
* @param authenticationManager the authentication manager to use
*/
public AuthenticationWebFilter(ReactiveAuthenticationManager authenticationManager) {
Assert.notNull(authenticationManager, "authenticationManager cannot be null");
this.authenticationManagerResolver = (request) -> Mono.just(authenticationManager);
}
/**
* Creates an instance
* @param authenticationManagerResolver the authentication manager resolver to use
* @since 5.3
*/
public AuthenticationWebFilter(
ReactiveAuthenticationManagerResolver authenticationManagerResolver) {
Assert.notNull(authenticationManagerResolver, "authenticationResolverManager cannot be null");
this.authenticationManagerResolver = authenticationManagerResolver;
}
@Override
public Mono filter(ServerWebExchange exchange, WebFilterChain chain) {
return this.requiresAuthenticationMatcher.matches(exchange)
.filter((matchResult) -> matchResult.isMatch())
.flatMap((matchResult) -> this.authenticationConverter.convert(exchange))
.switchIfEmpty(chain.filter(exchange).then(Mono.empty()))
.flatMap((token) -> authenticate(exchange, chain, token))
.onErrorResume(AuthenticationException.class, (ex) -> this.authenticationFailureHandler
.onAuthenticationFailure(new WebFilterExchange(exchange, chain), ex));
}
private Mono authenticate(ServerWebExchange exchange, WebFilterChain chain, Authentication token) {
return this.authenticationManagerResolver.resolve(exchange)
.flatMap((authenticationManager) -> authenticationManager.authenticate(token))
.switchIfEmpty(Mono
.defer(() -> Mono.error(new IllegalStateException("No provider found for " + token.getClass()))))
.flatMap(
(authentication) -> onAuthenticationSuccess(authentication, new WebFilterExchange(exchange, chain)))
.doOnError(AuthenticationException.class,
(ex) -> logger.debug(LogMessage.format("Authentication failed: %s", ex.getMessage()), ex));
}
protected Mono onAuthenticationSuccess(Authentication authentication, WebFilterExchange webFilterExchange) {
ServerWebExchange exchange = webFilterExchange.getExchange();
SecurityContextImpl securityContext = new SecurityContextImpl();
securityContext.setAuthentication(authentication);
return this.securityContextRepository.save(exchange, securityContext)
.then(this.authenticationSuccessHandler.onAuthenticationSuccess(webFilterExchange, authentication))
.contextWrite(ReactiveSecurityContextHolder.withSecurityContext(Mono.just(securityContext)));
}
/**
* Sets the repository for persisting the SecurityContext. Default is
* {@link NoOpServerSecurityContextRepository}
* @param securityContextRepository the repository to use
*/
public void setSecurityContextRepository(ServerSecurityContextRepository securityContextRepository) {
Assert.notNull(securityContextRepository, "securityContextRepository cannot be null");
this.securityContextRepository = securityContextRepository;
}
/**
* Sets the authentication success handler. Default is
* {@link WebFilterChainServerAuthenticationSuccessHandler}
* @param authenticationSuccessHandler the success handler to use
*/
public void setAuthenticationSuccessHandler(ServerAuthenticationSuccessHandler authenticationSuccessHandler) {
Assert.notNull(authenticationSuccessHandler, "authenticationSuccessHandler cannot be null");
this.authenticationSuccessHandler = authenticationSuccessHandler;
}
/**
* Sets the strategy used for converting from a {@link ServerWebExchange} to an
* {@link Authentication} used for authenticating with the provided
* {@link ReactiveAuthenticationManager}. If the result is empty, then it signals that
* no authentication attempt should be made. The default converter is
* {@link ServerHttpBasicAuthenticationConverter}
* @param authenticationConverter the converter to use
* @deprecated As of 5.1 in favor of
* {@link #setServerAuthenticationConverter(ServerAuthenticationConverter)}
* @see #setServerAuthenticationConverter(ServerAuthenticationConverter)
*/
@Deprecated
public void setAuthenticationConverter(Function> authenticationConverter) {
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
setServerAuthenticationConverter(authenticationConverter::apply);
}
/**
* Sets the strategy used for converting from a {@link ServerWebExchange} to an
* {@link Authentication} used for authenticating with the provided
* {@link ReactiveAuthenticationManager}. If the result is empty, then it signals that
* no authentication attempt should be made. The default converter is
* {@link ServerHttpBasicAuthenticationConverter}
* @param authenticationConverter the converter to use
* @since 5.1
*/
public void setServerAuthenticationConverter(ServerAuthenticationConverter authenticationConverter) {
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
this.authenticationConverter = authenticationConverter;
}
/**
* Sets the failure handler used when authentication fails. The default is to prompt
* for basic authentication.
* @param authenticationFailureHandler the handler to use. Cannot be null.
*/
public void setAuthenticationFailureHandler(ServerAuthenticationFailureHandler authenticationFailureHandler) {
Assert.notNull(authenticationFailureHandler, "authenticationFailureHandler cannot be null");
this.authenticationFailureHandler = authenticationFailureHandler;
}
/**
* Sets the matcher used to determine when creating an {@link Authentication} from
* {@link #setServerAuthenticationConverter(ServerAuthenticationConverter)} to be
* authentication. If the converter returns an empty result, then no authentication is
* attempted. The default is any request
* @param requiresAuthenticationMatcher the matcher to use. Cannot be null.
*/
public void setRequiresAuthenticationMatcher(ServerWebExchangeMatcher requiresAuthenticationMatcher) {
Assert.notNull(requiresAuthenticationMatcher, "requiresAuthenticationMatcher cannot be null");
this.requiresAuthenticationMatcher = requiresAuthenticationMatcher;
}
}