Add BadJwtException

Updated NimbusJwtDecoder and NimbusReactiveJwtDecoder to throw.
Updated JwtAuthenticationProvider and JwtReactiveAuthenticationManager
to catch.

Fixes gh-7885
This commit is contained in:
Josh Cummings
2020-01-31 16:41:52 -07:00
parent fbdecdafb8
commit 0c3754c811
12 changed files with 157 additions and 47 deletions

View File

@@ -20,9 +20,11 @@ import java.util.Collection;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.jwt.BadJwtException;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtException;
@@ -80,8 +82,10 @@ public final class JwtAuthenticationProvider implements AuthenticationProvider {
Jwt jwt;
try {
jwt = this.jwtDecoder.decode(bearer.getToken());
} catch (JwtException failed) {
} catch (BadJwtException failed) {
throw new InvalidBearerTokenException(failed.getMessage(), failed);
} catch (JwtException failed) {
throw new AuthenticationServiceException(failed.getMessage(), failed);
}
AbstractAuthenticationToken token = this.jwtAuthenticationConverter.convert(jwt);

View File

@@ -20,9 +20,11 @@ import reactor.core.publisher.Mono;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.jwt.BadJwtException;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtException;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
@@ -71,7 +73,11 @@ public final class JwtReactiveAuthenticationManager implements ReactiveAuthentic
this.jwtAuthenticationConverter = jwtAuthenticationConverter;
}
private OAuth2AuthenticationException onError(JwtException e) {
return new InvalidBearerTokenException(e.getMessage(), e);
private AuthenticationException onError(JwtException e) {
if (e instanceof BadJwtException) {
return new InvalidBearerTokenException(e.getMessage(), e);
} else {
return new AuthenticationServiceException(e.getMessage(), e);
}
}
}

View File

@@ -24,7 +24,9 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.jwt.BadJwtException;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtException;
@@ -78,7 +80,7 @@ public class JwtAuthenticationProviderTests {
public void authenticateWhenJwtDecodeFailsThenRespondsWithInvalidToken() {
BearerTokenAuthenticationToken token = this.authentication();
when(this.jwtDecoder.decode("token")).thenThrow(JwtException.class);
when(this.jwtDecoder.decode("token")).thenThrow(BadJwtException.class);
assertThatCode(() -> this.provider.authenticate(token))
.matches(failed -> failed instanceof OAuth2AuthenticationException)
@@ -89,7 +91,7 @@ public class JwtAuthenticationProviderTests {
public void authenticateWhenDecoderThrowsIncompatibleErrorMessageThenWrapsWithGenericOne() {
BearerTokenAuthenticationToken token = this.authentication();
when(this.jwtDecoder.decode(token.getToken())).thenThrow(new JwtException("with \"invalid\" chars"));
when(this.jwtDecoder.decode(token.getToken())).thenThrow(new BadJwtException("with \"invalid\" chars"));
assertThatCode(() -> this.provider.authenticate(token))
.isInstanceOf(OAuth2AuthenticationException.class)
@@ -98,6 +100,18 @@ public class JwtAuthenticationProviderTests {
"Invalid token");
}
// gh-7785
@Test
public void authenticateWhenDecoderFailsGenericallyThenThrowsGenericException() {
BearerTokenAuthenticationToken token = this.authentication();
when(this.jwtDecoder.decode(token.getToken())).thenThrow(new JwtException("no jwk set"));
assertThatCode(() -> this.provider.authenticate(token))
.isInstanceOf(AuthenticationException.class)
.isNotInstanceOf(OAuth2AuthenticationException.class);
}
@Test
public void authenticateWhenConverterReturnsAuthenticationThenProviderPropagatesIt() {
BearerTokenAuthenticationToken token = this.authentication();

View File

@@ -25,8 +25,10 @@ import reactor.core.publisher.Mono;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.jwt.BadJwtException;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtException;
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
@@ -82,7 +84,7 @@ public class JwtReactiveAuthenticationManagerTests {
@Test
public void authenticateWhenJwtExceptionThenOAuth2AuthenticationException() {
BearerTokenAuthenticationToken token = new BearerTokenAuthenticationToken("token-1");
when(this.jwtDecoder.decode(any())).thenReturn(Mono.error(new JwtException("Oops")));
when(this.jwtDecoder.decode(any())).thenReturn(Mono.error(new BadJwtException("Oops")));
assertThatCode(() -> this.manager.authenticate(token).block())
.isInstanceOf(OAuth2AuthenticationException.class);
@@ -92,7 +94,7 @@ public class JwtReactiveAuthenticationManagerTests {
@Test
public void authenticateWhenDecoderThrowsIncompatibleErrorMessageThenWrapsWithGenericOne() {
BearerTokenAuthenticationToken token = new BearerTokenAuthenticationToken("token-1");
when(this.jwtDecoder.decode(token.getToken())).thenThrow(new JwtException("with \"invalid\" chars"));
when(this.jwtDecoder.decode(token.getToken())).thenThrow(new BadJwtException("with \"invalid\" chars"));
assertThatCode(() -> this.manager.authenticate(token).block())
.isInstanceOf(OAuth2AuthenticationException.class)
@@ -101,6 +103,17 @@ public class JwtReactiveAuthenticationManagerTests {
"Invalid token");
}
// gh-7785
@Test
public void authenticateWhenDecoderFailsGenericallyThenThrowsGenericException() {
BearerTokenAuthenticationToken token = new BearerTokenAuthenticationToken("token-1");
when(this.jwtDecoder.decode(token.getToken())).thenThrow(new JwtException("no jwk set"));
assertThatCode(() -> this.manager.authenticate(token).block())
.isInstanceOf(AuthenticationException.class)
.isNotInstanceOf(OAuth2AuthenticationException.class);
}
@Test
public void authenticateWhenNotJwtExceptionThenPropagates() {
BearerTokenAuthenticationToken token = new BearerTokenAuthenticationToken("token-1");