Skip to content

Commit e146a7c

Browse files
committed
OAuth2LoginAuthenticationWebFilter should handle OAuth2AuthorizationException
Issue gh-8609
1 parent a372ec9 commit e146a7c

File tree

4 files changed

+44
-20
lines changed

4 files changed

+44
-20
lines changed

config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
import java.util.Optional;
3535
import java.util.function.Function;
3636

37+
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
38+
import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
3739
import reactor.core.publisher.Mono;
3840
import reactor.util.context.Context;
3941

@@ -578,7 +580,12 @@ public OAuth2LoginSpec authenticationConverter(ServerAuthenticationConverter aut
578580

579581
private ServerAuthenticationConverter getAuthenticationConverter(ReactiveClientRegistrationRepository clientRegistrationRepository) {
580582
if (this.authenticationConverter == null) {
581-
this.authenticationConverter = new ServerOAuth2AuthorizationCodeAuthenticationTokenConverter(clientRegistrationRepository);
583+
ServerOAuth2AuthorizationCodeAuthenticationTokenConverter delegate =
584+
new ServerOAuth2AuthorizationCodeAuthenticationTokenConverter(clientRegistrationRepository);
585+
ServerAuthenticationConverter authenticationConverter = exchange ->
586+
delegate.convert(exchange).onErrorMap(OAuth2AuthorizationException.class,
587+
e -> new OAuth2AuthenticationException(e.getError(), e.getError().toString()));
588+
this.authenticationConverter = authenticationConverter;
582589
}
583590
return this.authenticationConverter;
584591
}

config/src/test/java/org/springframework/security/config/web/server/OAuth2LoginTests.java

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,6 @@
1616

1717
package org.springframework.security.config.web.server;
1818

19-
import static org.assertj.core.api.Assertions.assertThat;
20-
import static org.mockito.ArgumentMatchers.any;
21-
import static org.mockito.Mockito.mock;
22-
import static org.mockito.Mockito.verify;
23-
import static org.mockito.Mockito.when;
24-
2519
import org.junit.Rule;
2620
import org.junit.Test;
2721
import org.openqa.selenium.WebDriver;
@@ -67,13 +61,18 @@
6761
import org.springframework.web.server.ServerWebExchange;
6862
import org.springframework.web.server.WebFilter;
6963
import org.springframework.web.server.WebFilterChain;
70-
7164
import org.springframework.web.server.WebHandler;
7265
import reactor.core.publisher.Mono;
7366

7467
import java.time.Duration;
7568
import java.time.Instant;
7669

70+
import static org.assertj.core.api.Assertions.assertThat;
71+
import static org.mockito.ArgumentMatchers.any;
72+
import static org.mockito.Mockito.mock;
73+
import static org.mockito.Mockito.verify;
74+
import static org.mockito.Mockito.when;
75+
7776
/**
7877
* @author Rob Winch
7978
* @since 5.1
@@ -301,6 +300,24 @@ public ReactiveOAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantReque
301300
}
302301
}
303302

303+
// gh-8609
304+
@Test
305+
public void oauth2LoginWhenAuthenticationConverterFailsThenDefaultRedirectToLogin() {
306+
this.spring.register(OAuth2LoginWithMulitpleClientRegistrations.class).autowire();
307+
308+
WebTestClient webTestClient = WebTestClientBuilder
309+
.bindToWebFilters(this.springSecurity)
310+
.build();
311+
312+
webTestClient.get()
313+
.uri("/login/oauth2/code/google")
314+
.exchange()
315+
.expectStatus()
316+
.is3xxRedirection()
317+
.expectHeader()
318+
.valueEquals("Location", "/login?error");
319+
}
320+
304321
static class GitHubWebFilter implements WebFilter {
305322

306323
@Override

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeReactiveAuthenticationManager.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -117,13 +117,14 @@ public Mono<Authentication> authenticate(Authentication authentication) {
117117
.getAuthorizationExchange().getAuthorizationResponse();
118118

119119
if (authorizationResponse.statusError()) {
120-
throw new OAuth2AuthenticationException(
121-
authorizationResponse.getError(), authorizationResponse.getError().toString());
120+
return Mono.error(new OAuth2AuthenticationException(
121+
authorizationResponse.getError(), authorizationResponse.getError().toString()));
122122
}
123123

124124
if (!authorizationResponse.getState().equals(authorizationRequest.getState())) {
125125
OAuth2Error oauth2Error = new OAuth2Error(INVALID_STATE_PARAMETER_ERROR_CODE);
126-
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
126+
return Mono.error(new OAuth2AuthenticationException(
127+
oauth2Error, oauth2Error.toString()));
127128
}
128129

129130
OAuth2AuthorizationCodeGrantRequest authzRequest = new OAuth2AuthorizationCodeGrantRequest(
@@ -156,7 +157,7 @@ private Mono<OAuth2LoginAuthenticationToken> authenticationResult(OAuth2Authoriz
156157
INVALID_ID_TOKEN_ERROR_CODE,
157158
"Missing (required) ID Token in Token Response for Client Registration: " + clientRegistration.getRegistrationId(),
158159
null);
159-
throw new OAuth2AuthenticationException(invalidIdTokenError, invalidIdTokenError.toString());
160+
return Mono.error(new OAuth2AuthenticationException(invalidIdTokenError, invalidIdTokenError.toString()));
160161
}
161162

162163
return createOidcToken(clientRegistration, accessTokenResponse)

web/src/main/java/org/springframework/security/web/server/authentication/AuthenticationWebFilter.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -89,17 +89,16 @@ public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
8989
.filter( matchResult -> matchResult.isMatch())
9090
.flatMap( matchResult -> this.authenticationConverter.convert(exchange))
9191
.switchIfEmpty(chain.filter(exchange).then(Mono.empty()))
92-
.flatMap( token -> authenticate(exchange, chain, token));
92+
.flatMap( token -> authenticate(exchange, chain, token))
93+
.onErrorResume(AuthenticationException.class, e -> this.authenticationFailureHandler
94+
.onAuthenticationFailure(new WebFilterExchange(exchange, chain), e));
9395
}
9496

95-
private Mono<Void> authenticate(ServerWebExchange exchange,
96-
WebFilterChain chain, Authentication token) {
97+
private Mono<Void> authenticate(ServerWebExchange exchange, WebFilterChain chain, Authentication token) {
9798
WebFilterExchange webFilterExchange = new WebFilterExchange(exchange, chain);
9899
return this.authenticationManager.authenticate(token)
99100
.switchIfEmpty(Mono.defer(() -> Mono.error(new IllegalStateException("No provider found for " + token.getClass()))))
100-
.flatMap(authentication -> onAuthenticationSuccess(authentication, webFilterExchange))
101-
.onErrorResume(AuthenticationException.class, e -> this.authenticationFailureHandler
102-
.onAuthenticationFailure(webFilterExchange, e));
101+
.flatMap(authentication -> onAuthenticationSuccess(authentication, webFilterExchange));
103102
}
104103

105104
protected Mono<Void> onAuthenticationSuccess(Authentication authentication, WebFilterExchange webFilterExchange) {

0 commit comments

Comments
 (0)