Polish Bearer Token Error Handling
Issue gh-7822 Issue gh-7823
This commit is contained in:
		
							parent
							
								
									1b15f74f57
								
							
						
					
					
						commit
						3e07b35611
					
				|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2019 the original author or authors. |  * Copyright 2002-2020 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. | ||||||
|  | @ -269,7 +269,7 @@ public class OAuth2ResourceServerConfigurerTests { | ||||||
| 
 | 
 | ||||||
| 		this.mvc.perform(get("/").with(bearerToken(token))) | 		this.mvc.perform(get("/").with(bearerToken(token))) | ||||||
| 				.andExpect(status().isUnauthorized()) | 				.andExpect(status().isUnauthorized()) | ||||||
| 				.andExpect(invalidTokenHeader("An error occurred while attempting to decode the Jwt")); | 				.andExpect(invalidTokenHeader("Invalid token")); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2018 the original author or authors. |  * Copyright 2002-2020 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,20 +18,16 @@ package org.springframework.security.oauth2.server.resource.authentication; | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
| 
 | 
 | ||||||
| import org.springframework.core.convert.converter.Converter; | import org.springframework.core.convert.converter.Converter; | ||||||
| import org.springframework.http.HttpStatus; |  | ||||||
| import org.springframework.security.authentication.AbstractAuthenticationToken; | import org.springframework.security.authentication.AbstractAuthenticationToken; | ||||||
| import org.springframework.security.authentication.AuthenticationProvider; | import org.springframework.security.authentication.AuthenticationProvider; | ||||||
| import org.springframework.security.core.Authentication; | import org.springframework.security.core.Authentication; | ||||||
| import org.springframework.security.core.AuthenticationException; | import org.springframework.security.core.AuthenticationException; | ||||||
| import org.springframework.security.core.GrantedAuthority; | import org.springframework.security.core.GrantedAuthority; | ||||||
| import org.springframework.security.oauth2.core.OAuth2AuthenticationException; |  | ||||||
| import org.springframework.security.oauth2.core.OAuth2Error; |  | ||||||
| import org.springframework.security.oauth2.jwt.Jwt; | import org.springframework.security.oauth2.jwt.Jwt; | ||||||
| import org.springframework.security.oauth2.jwt.JwtDecoder; | import org.springframework.security.oauth2.jwt.JwtDecoder; | ||||||
| import org.springframework.security.oauth2.jwt.JwtException; | import org.springframework.security.oauth2.jwt.JwtException; | ||||||
| import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken; | import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken; | ||||||
| import org.springframework.security.oauth2.server.resource.BearerTokenError; | import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException; | ||||||
| import org.springframework.security.oauth2.server.resource.BearerTokenErrorCodes; |  | ||||||
| import org.springframework.util.Assert; | import org.springframework.util.Assert; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | @ -63,9 +59,6 @@ public final class JwtAuthenticationProvider implements AuthenticationProvider { | ||||||
| 
 | 
 | ||||||
| 	private Converter<Jwt, ? extends AbstractAuthenticationToken> jwtAuthenticationConverter = new JwtAuthenticationConverter(); | 	private Converter<Jwt, ? extends AbstractAuthenticationToken> jwtAuthenticationConverter = new JwtAuthenticationConverter(); | ||||||
| 
 | 
 | ||||||
| 	private static final OAuth2Error DEFAULT_INVALID_TOKEN = |  | ||||||
| 			invalidToken("An error occurred while attempting to decode the Jwt: Invalid token"); |  | ||||||
| 
 |  | ||||||
| 	public JwtAuthenticationProvider(JwtDecoder jwtDecoder) { | 	public JwtAuthenticationProvider(JwtDecoder jwtDecoder) { | ||||||
| 		Assert.notNull(jwtDecoder, "jwtDecoder cannot be null"); | 		Assert.notNull(jwtDecoder, "jwtDecoder cannot be null"); | ||||||
| 		this.jwtDecoder = jwtDecoder; | 		this.jwtDecoder = jwtDecoder; | ||||||
|  | @ -88,8 +81,7 @@ public final class JwtAuthenticationProvider implements AuthenticationProvider { | ||||||
| 		try { | 		try { | ||||||
| 			jwt = this.jwtDecoder.decode(bearer.getToken()); | 			jwt = this.jwtDecoder.decode(bearer.getToken()); | ||||||
| 		} catch (JwtException failed) { | 		} catch (JwtException failed) { | ||||||
| 			OAuth2Error invalidToken = invalidToken(failed.getMessage()); | 			throw new InvalidBearerTokenException(failed.getMessage(), failed); | ||||||
| 			throw new OAuth2AuthenticationException(invalidToken, invalidToken.getDescription(), failed); |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		AbstractAuthenticationToken token = this.jwtAuthenticationConverter.convert(jwt); | 		AbstractAuthenticationToken token = this.jwtAuthenticationConverter.convert(jwt); | ||||||
|  | @ -112,17 +104,4 @@ public final class JwtAuthenticationProvider implements AuthenticationProvider { | ||||||
| 		Assert.notNull(jwtAuthenticationConverter, "jwtAuthenticationConverter cannot be null"); | 		Assert.notNull(jwtAuthenticationConverter, "jwtAuthenticationConverter cannot be null"); | ||||||
| 		this.jwtAuthenticationConverter = jwtAuthenticationConverter; | 		this.jwtAuthenticationConverter = jwtAuthenticationConverter; | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	private static OAuth2Error invalidToken(String message) { |  | ||||||
| 		try { |  | ||||||
| 			return new BearerTokenError( |  | ||||||
| 					BearerTokenErrorCodes.INVALID_TOKEN, |  | ||||||
| 					HttpStatus.UNAUTHORIZED, |  | ||||||
| 					message, |  | ||||||
| 					"https://tools.ietf.org/html/rfc6750#section-3.1"); |  | ||||||
| 		} catch (IllegalArgumentException malformed) { |  | ||||||
| 			// some third-party library error messages are not suitable for RFC 6750's error message charset |  | ||||||
| 			return DEFAULT_INVALID_TOKEN; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2019 the original author or authors. |  * Copyright 2002-2020 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. | ||||||
|  | @ -27,16 +27,13 @@ import javax.servlet.http.HttpServletRequest; | ||||||
| import com.nimbusds.jwt.JWTParser; | import com.nimbusds.jwt.JWTParser; | ||||||
| 
 | 
 | ||||||
| import org.springframework.core.convert.converter.Converter; | import org.springframework.core.convert.converter.Converter; | ||||||
| import org.springframework.http.HttpStatus; |  | ||||||
| import org.springframework.lang.NonNull; | import org.springframework.lang.NonNull; | ||||||
| import org.springframework.security.authentication.AuthenticationManager; | import org.springframework.security.authentication.AuthenticationManager; | ||||||
| import org.springframework.security.authentication.AuthenticationManagerResolver; | import org.springframework.security.authentication.AuthenticationManagerResolver; | ||||||
| import org.springframework.security.oauth2.core.OAuth2AuthenticationException; | import org.springframework.security.oauth2.core.OAuth2AuthenticationException; | ||||||
| import org.springframework.security.oauth2.core.OAuth2Error; |  | ||||||
| import org.springframework.security.oauth2.jwt.JwtDecoder; | import org.springframework.security.oauth2.jwt.JwtDecoder; | ||||||
| import org.springframework.security.oauth2.jwt.JwtDecoders; | import org.springframework.security.oauth2.jwt.JwtDecoders; | ||||||
| import org.springframework.security.oauth2.server.resource.BearerTokenError; | import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException; | ||||||
| import org.springframework.security.oauth2.server.resource.BearerTokenErrorCodes; |  | ||||||
| import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver; | import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver; | ||||||
| import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver; | import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver; | ||||||
| import org.springframework.util.Assert; | import org.springframework.util.Assert; | ||||||
|  | @ -57,8 +54,6 @@ import org.springframework.util.Assert; | ||||||
|  * @since 5.3 |  * @since 5.3 | ||||||
|  */ |  */ | ||||||
| public final class JwtIssuerAuthenticationManagerResolver implements AuthenticationManagerResolver<HttpServletRequest> { | public final class JwtIssuerAuthenticationManagerResolver implements AuthenticationManagerResolver<HttpServletRequest> { | ||||||
| 	private static final OAuth2Error DEFAULT_INVALID_TOKEN = invalidToken("Invalid token"); |  | ||||||
| 
 |  | ||||||
| 	private final AuthenticationManagerResolver<String> issuerAuthenticationManagerResolver; | 	private final AuthenticationManagerResolver<String> issuerAuthenticationManagerResolver; | ||||||
| 	private final Converter<HttpServletRequest, String> issuerConverter = new JwtClaimIssuerConverter(); | 	private final Converter<HttpServletRequest, String> issuerConverter = new JwtClaimIssuerConverter(); | ||||||
| 
 | 
 | ||||||
|  | @ -118,7 +113,7 @@ public final class JwtIssuerAuthenticationManagerResolver implements Authenticat | ||||||
| 		String issuer = this.issuerConverter.convert(request); | 		String issuer = this.issuerConverter.convert(request); | ||||||
| 		AuthenticationManager authenticationManager = this.issuerAuthenticationManagerResolver.resolve(issuer); | 		AuthenticationManager authenticationManager = this.issuerAuthenticationManagerResolver.resolve(issuer); | ||||||
| 		if (authenticationManager == null) { | 		if (authenticationManager == null) { | ||||||
| 			throw new OAuth2AuthenticationException(invalidToken("Invalid issuer " + issuer)); | 			throw new InvalidBearerTokenException("Invalid issuer"); | ||||||
| 		} | 		} | ||||||
| 		return authenticationManager; | 		return authenticationManager; | ||||||
| 	} | 	} | ||||||
|  | @ -137,9 +132,9 @@ public final class JwtIssuerAuthenticationManagerResolver implements Authenticat | ||||||
| 					return issuer; | 					return issuer; | ||||||
| 				} | 				} | ||||||
| 			} catch (Exception e) { | 			} catch (Exception e) { | ||||||
| 				throw new OAuth2AuthenticationException(invalidToken(e.getMessage())); | 				throw new InvalidBearerTokenException(e.getMessage(), e); | ||||||
| 			} | 			} | ||||||
| 			throw new OAuth2AuthenticationException(invalidToken("Missing issuer")); | 			throw new InvalidBearerTokenException("Missing issuer"); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -164,17 +159,4 @@ public final class JwtIssuerAuthenticationManagerResolver implements Authenticat | ||||||
| 			return null; | 			return null; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	private static OAuth2Error invalidToken(String message) { |  | ||||||
| 		try { |  | ||||||
| 			return new BearerTokenError( |  | ||||||
| 				BearerTokenErrorCodes.INVALID_TOKEN, |  | ||||||
| 				HttpStatus.UNAUTHORIZED, |  | ||||||
| 				message, |  | ||||||
| 				"https://tools.ietf.org/html/rfc6750#section-3.1"); |  | ||||||
| 		} catch (IllegalArgumentException malformed) { |  | ||||||
| 			// some third-party library error messages are not suitable for RFC 6750's error message charset |  | ||||||
| 			return DEFAULT_INVALID_TOKEN; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2018 the original author or authors. |  * Copyright 2002-2020 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. | ||||||
|  | @ -19,18 +19,15 @@ package org.springframework.security.oauth2.server.resource.authentication; | ||||||
| import reactor.core.publisher.Mono; | import reactor.core.publisher.Mono; | ||||||
| 
 | 
 | ||||||
| import org.springframework.core.convert.converter.Converter; | import org.springframework.core.convert.converter.Converter; | ||||||
| import org.springframework.http.HttpStatus; |  | ||||||
| import org.springframework.security.authentication.AbstractAuthenticationToken; | import org.springframework.security.authentication.AbstractAuthenticationToken; | ||||||
| import org.springframework.security.authentication.ReactiveAuthenticationManager; | import org.springframework.security.authentication.ReactiveAuthenticationManager; | ||||||
| import org.springframework.security.core.Authentication; | import org.springframework.security.core.Authentication; | ||||||
| import org.springframework.security.oauth2.core.OAuth2AuthenticationException; | import org.springframework.security.oauth2.core.OAuth2AuthenticationException; | ||||||
| import org.springframework.security.oauth2.core.OAuth2Error; |  | ||||||
| import org.springframework.security.oauth2.jwt.Jwt; | import org.springframework.security.oauth2.jwt.Jwt; | ||||||
| import org.springframework.security.oauth2.jwt.JwtException; | import org.springframework.security.oauth2.jwt.JwtException; | ||||||
| import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; | import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; | ||||||
| import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken; | import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken; | ||||||
| import org.springframework.security.oauth2.server.resource.BearerTokenError; | import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException; | ||||||
| import org.springframework.security.oauth2.server.resource.BearerTokenErrorCodes; |  | ||||||
| import org.springframework.util.Assert; | import org.springframework.util.Assert; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | @ -45,9 +42,6 @@ public final class JwtReactiveAuthenticationManager implements ReactiveAuthentic | ||||||
| 	private Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter | 	private Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter | ||||||
| 			= new ReactiveJwtAuthenticationConverterAdapter(new JwtAuthenticationConverter()); | 			= new ReactiveJwtAuthenticationConverterAdapter(new JwtAuthenticationConverter()); | ||||||
| 
 | 
 | ||||||
| 	private static final OAuth2Error DEFAULT_INVALID_TOKEN = |  | ||||||
| 			invalidToken("An error occurred while attempting to decode the Jwt: Invalid token"); |  | ||||||
| 
 |  | ||||||
| 	public JwtReactiveAuthenticationManager(ReactiveJwtDecoder jwtDecoder) { | 	public JwtReactiveAuthenticationManager(ReactiveJwtDecoder jwtDecoder) { | ||||||
| 		Assert.notNull(jwtDecoder, "jwtDecoder cannot be null"); | 		Assert.notNull(jwtDecoder, "jwtDecoder cannot be null"); | ||||||
| 		this.jwtDecoder = jwtDecoder; | 		this.jwtDecoder = jwtDecoder; | ||||||
|  | @ -78,20 +72,6 @@ public final class JwtReactiveAuthenticationManager implements ReactiveAuthentic | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private OAuth2AuthenticationException onError(JwtException e) { | 	private OAuth2AuthenticationException onError(JwtException e) { | ||||||
| 		OAuth2Error invalidRequest = invalidToken(e.getMessage()); | 		return new InvalidBearerTokenException(e.getMessage(), e); | ||||||
| 		return new OAuth2AuthenticationException(invalidRequest, invalidRequest.getDescription(), e); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private static OAuth2Error invalidToken(String message) { |  | ||||||
| 		try { |  | ||||||
| 			return new BearerTokenError( |  | ||||||
| 					BearerTokenErrorCodes.INVALID_TOKEN, |  | ||||||
| 					HttpStatus.UNAUTHORIZED, |  | ||||||
| 					message, |  | ||||||
| 					"https://tools.ietf.org/html/rfc6750#section-3.1"); |  | ||||||
| 		} catch (IllegalArgumentException malformed) { |  | ||||||
| 			// some third-party library error messages are not suitable for RFC 6750's error message charset |  | ||||||
| 			return DEFAULT_INVALID_TOKEN; |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2019 the original author or authors. |  * Copyright 2002-2020 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,7 +18,6 @@ package org.springframework.security.oauth2.server.resource.authentication; | ||||||
| import java.time.Instant; | import java.time.Instant; | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
| 
 | 
 | ||||||
| import org.springframework.http.HttpStatus; |  | ||||||
| import org.springframework.security.authentication.AbstractAuthenticationToken; | import org.springframework.security.authentication.AbstractAuthenticationToken; | ||||||
| import org.springframework.security.authentication.AuthenticationProvider; | import org.springframework.security.authentication.AuthenticationProvider; | ||||||
| import org.springframework.security.core.Authentication; | import org.springframework.security.core.Authentication; | ||||||
|  | @ -26,10 +25,8 @@ import org.springframework.security.core.AuthenticationException; | ||||||
| import org.springframework.security.core.GrantedAuthority; | import org.springframework.security.core.GrantedAuthority; | ||||||
| import org.springframework.security.oauth2.core.OAuth2AccessToken; | import org.springframework.security.oauth2.core.OAuth2AccessToken; | ||||||
| import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal; | import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal; | ||||||
| import org.springframework.security.oauth2.core.OAuth2AuthenticationException; |  | ||||||
| import org.springframework.security.oauth2.core.OAuth2Error; |  | ||||||
| import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken; | import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken; | ||||||
| import org.springframework.security.oauth2.server.resource.BearerTokenError; | import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException; | ||||||
| import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException; | import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException; | ||||||
| import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector; | import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector; | ||||||
| import org.springframework.util.Assert; | import org.springframework.util.Assert; | ||||||
|  | @ -60,9 +57,6 @@ import static org.springframework.security.oauth2.server.resource.introspection. | ||||||
|  * @see AuthenticationProvider |  * @see AuthenticationProvider | ||||||
|  */ |  */ | ||||||
| public final class OpaqueTokenAuthenticationProvider implements AuthenticationProvider { | public final class OpaqueTokenAuthenticationProvider implements AuthenticationProvider { | ||||||
| 	private static final BearerTokenError DEFAULT_INVALID_TOKEN = |  | ||||||
| 			invalidToken("An error occurred while attempting to introspect the token: Invalid token"); |  | ||||||
| 
 |  | ||||||
| 	private OpaqueTokenIntrospector introspector; | 	private OpaqueTokenIntrospector introspector; | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -95,8 +89,7 @@ public final class OpaqueTokenAuthenticationProvider implements AuthenticationPr | ||||||
| 		try { | 		try { | ||||||
| 			principal = this.introspector.introspect(bearer.getToken()); | 			principal = this.introspector.introspect(bearer.getToken()); | ||||||
| 		} catch (OAuth2IntrospectionException failed) { | 		} catch (OAuth2IntrospectionException failed) { | ||||||
| 			OAuth2Error invalidToken = invalidToken(failed.getMessage()); | 			throw new InvalidBearerTokenException(failed.getMessage()); | ||||||
| 			throw new OAuth2AuthenticationException(invalidToken); |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		AbstractAuthenticationToken result = convert(principal, bearer.getToken()); | 		AbstractAuthenticationToken result = convert(principal, bearer.getToken()); | ||||||
|  | @ -119,15 +112,4 @@ public final class OpaqueTokenAuthenticationProvider implements AuthenticationPr | ||||||
| 				token, iat, exp); | 				token, iat, exp); | ||||||
| 		return new BearerTokenAuthentication(principal, accessToken, principal.getAuthorities()); | 		return new BearerTokenAuthentication(principal, accessToken, principal.getAuthorities()); | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	private static BearerTokenError invalidToken(String message) { |  | ||||||
| 		try { |  | ||||||
| 			return new BearerTokenError("invalid_token", |  | ||||||
| 					HttpStatus.UNAUTHORIZED, message, |  | ||||||
| 					"https://tools.ietf.org/html/rfc7662#section-2.2"); |  | ||||||
| 		} catch (IllegalArgumentException malformed) { |  | ||||||
| 			// some third-party library error messages are not suitable for RFC 6750's error message charset |  | ||||||
| 			return DEFAULT_INVALID_TOKEN; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2019 the original author or authors. |  * Copyright 2002-2020 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. | ||||||
|  | @ -21,15 +21,13 @@ import java.util.Collection; | ||||||
| 
 | 
 | ||||||
| import reactor.core.publisher.Mono; | import reactor.core.publisher.Mono; | ||||||
| 
 | 
 | ||||||
| import org.springframework.http.HttpStatus; |  | ||||||
| import org.springframework.security.authentication.ReactiveAuthenticationManager; | import org.springframework.security.authentication.ReactiveAuthenticationManager; | ||||||
| import org.springframework.security.core.Authentication; | import org.springframework.security.core.Authentication; | ||||||
| import org.springframework.security.core.GrantedAuthority; | import org.springframework.security.core.GrantedAuthority; | ||||||
| import org.springframework.security.oauth2.core.OAuth2AccessToken; | import org.springframework.security.oauth2.core.OAuth2AccessToken; | ||||||
| import org.springframework.security.oauth2.core.OAuth2AuthenticationException; | import org.springframework.security.oauth2.core.OAuth2AuthenticationException; | ||||||
| import org.springframework.security.oauth2.core.OAuth2Error; |  | ||||||
| import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken; | import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken; | ||||||
| import org.springframework.security.oauth2.server.resource.BearerTokenError; | import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException; | ||||||
| import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException; | import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException; | ||||||
| import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector; | import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector; | ||||||
| import org.springframework.util.Assert; | import org.springframework.util.Assert; | ||||||
|  | @ -60,9 +58,6 @@ import static org.springframework.security.oauth2.server.resource.introspection. | ||||||
|  * @see ReactiveAuthenticationManager |  * @see ReactiveAuthenticationManager | ||||||
|  */ |  */ | ||||||
| public class OpaqueTokenReactiveAuthenticationManager implements ReactiveAuthenticationManager { | public class OpaqueTokenReactiveAuthenticationManager implements ReactiveAuthenticationManager { | ||||||
| 	private static final BearerTokenError DEFAULT_INVALID_TOKEN = |  | ||||||
| 			invalidToken("An error occurred while attempting to introspect the token: Invalid token"); |  | ||||||
| 
 |  | ||||||
| 	private ReactiveOpaqueTokenIntrospector introspector; | 	private ReactiveOpaqueTokenIntrospector introspector; | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -99,19 +94,7 @@ public class OpaqueTokenReactiveAuthenticationManager implements ReactiveAuthent | ||||||
| 				.onErrorMap(OAuth2IntrospectionException.class, this::onError); | 				.onErrorMap(OAuth2IntrospectionException.class, this::onError); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private static BearerTokenError invalidToken(String message) { |  | ||||||
| 		try { |  | ||||||
| 			return new BearerTokenError("invalid_token", |  | ||||||
| 					HttpStatus.UNAUTHORIZED, message, |  | ||||||
| 					"https://tools.ietf.org/html/rfc7662#section-2.2"); |  | ||||||
| 		} catch (IllegalArgumentException e) { |  | ||||||
| 			// some third-party library error messages are not suitable for RFC 6750's error message charset |  | ||||||
| 			return DEFAULT_INVALID_TOKEN; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private OAuth2AuthenticationException onError(OAuth2IntrospectionException e) { | 	private OAuth2AuthenticationException onError(OAuth2IntrospectionException e) { | ||||||
| 		OAuth2Error invalidRequest = invalidToken(e.getMessage()); | 		return new InvalidBearerTokenException(e.getMessage(), e); | ||||||
| 		return new OAuth2AuthenticationException(invalidRequest, e.getMessage()); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2018 the original author or authors. |  * Copyright 2002-2020 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. | ||||||
|  | @ -21,12 +21,13 @@ import java.util.regex.Pattern; | ||||||
| import javax.servlet.http.HttpServletRequest; | import javax.servlet.http.HttpServletRequest; | ||||||
| 
 | 
 | ||||||
| import org.springframework.http.HttpHeaders; | import org.springframework.http.HttpHeaders; | ||||||
| import org.springframework.http.HttpStatus; |  | ||||||
| import org.springframework.security.oauth2.core.OAuth2AuthenticationException; | import org.springframework.security.oauth2.core.OAuth2AuthenticationException; | ||||||
| import org.springframework.security.oauth2.server.resource.BearerTokenError; | import org.springframework.security.oauth2.server.resource.BearerTokenError; | ||||||
| import org.springframework.security.oauth2.server.resource.BearerTokenErrorCodes; |  | ||||||
| import org.springframework.util.StringUtils; | import org.springframework.util.StringUtils; | ||||||
| 
 | 
 | ||||||
|  | import static org.springframework.security.oauth2.server.resource.BearerTokenErrors.invalidRequest; | ||||||
|  | import static org.springframework.security.oauth2.server.resource.BearerTokenErrors.invalidToken; | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * The default {@link BearerTokenResolver} implementation based on RFC 6750. |  * The default {@link BearerTokenResolver} implementation based on RFC 6750. | ||||||
|  * |  * | ||||||
|  | @ -53,10 +54,7 @@ public final class DefaultBearerTokenResolver implements BearerTokenResolver { | ||||||
| 		String parameterToken = resolveFromRequestParameters(request); | 		String parameterToken = resolveFromRequestParameters(request); | ||||||
| 		if (authorizationHeaderToken != null) { | 		if (authorizationHeaderToken != null) { | ||||||
| 			if (parameterToken != null) { | 			if (parameterToken != null) { | ||||||
| 				BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_REQUEST, | 				BearerTokenError error = invalidRequest("Found multiple bearer tokens in the request"); | ||||||
| 						HttpStatus.BAD_REQUEST, |  | ||||||
| 						"Found multiple bearer tokens in the request", |  | ||||||
| 						"https://tools.ietf.org/html/rfc6750#section-3.1"); |  | ||||||
| 				throw new OAuth2AuthenticationException(error); | 				throw new OAuth2AuthenticationException(error); | ||||||
| 			} | 			} | ||||||
| 			return authorizationHeaderToken; | 			return authorizationHeaderToken; | ||||||
|  | @ -93,10 +91,7 @@ public final class DefaultBearerTokenResolver implements BearerTokenResolver { | ||||||
| 			Matcher matcher = authorizationPattern.matcher(authorization); | 			Matcher matcher = authorizationPattern.matcher(authorization); | ||||||
| 
 | 
 | ||||||
| 			if (!matcher.matches()) { | 			if (!matcher.matches()) { | ||||||
| 				BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_TOKEN, | 				BearerTokenError error = invalidToken("Bearer token is malformed"); | ||||||
| 						HttpStatus.UNAUTHORIZED, |  | ||||||
| 						"Bearer token is malformed", |  | ||||||
| 						"https://tools.ietf.org/html/rfc6750#section-3.1"); |  | ||||||
| 				throw new OAuth2AuthenticationException(error); | 				throw new OAuth2AuthenticationException(error); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | @ -115,10 +110,7 @@ public final class DefaultBearerTokenResolver implements BearerTokenResolver { | ||||||
| 			return values[0]; | 			return values[0]; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_REQUEST, | 		BearerTokenError error = invalidRequest("Found multiple bearer tokens in the request"); | ||||||
| 				HttpStatus.BAD_REQUEST, |  | ||||||
| 				"Found multiple bearer tokens in the request", |  | ||||||
| 				"https://tools.ietf.org/html/rfc6750#section-3.1"); |  | ||||||
| 		throw new OAuth2AuthenticationException(error); | 		throw new OAuth2AuthenticationException(error); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2018 the original author or authors. |  * Copyright 2002-2020 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. | ||||||
|  | @ -16,22 +16,24 @@ | ||||||
| 
 | 
 | ||||||
| package org.springframework.security.oauth2.server.resource.web.server; | package org.springframework.security.oauth2.server.resource.web.server; | ||||||
| 
 | 
 | ||||||
|  | import java.util.regex.Matcher; | ||||||
|  | import java.util.regex.Pattern; | ||||||
|  | 
 | ||||||
|  | import reactor.core.publisher.Mono; | ||||||
|  | 
 | ||||||
| import org.springframework.http.HttpHeaders; | import org.springframework.http.HttpHeaders; | ||||||
| import org.springframework.http.HttpMethod; | import org.springframework.http.HttpMethod; | ||||||
| import org.springframework.http.HttpStatus; |  | ||||||
| import org.springframework.http.server.reactive.ServerHttpRequest; | import org.springframework.http.server.reactive.ServerHttpRequest; | ||||||
| import org.springframework.security.core.Authentication; | import org.springframework.security.core.Authentication; | ||||||
| import org.springframework.security.oauth2.core.OAuth2AuthenticationException; | import org.springframework.security.oauth2.core.OAuth2AuthenticationException; | ||||||
| import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken; | import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken; | ||||||
| import org.springframework.security.oauth2.server.resource.BearerTokenError; | import org.springframework.security.oauth2.server.resource.BearerTokenError; | ||||||
| import org.springframework.security.oauth2.server.resource.BearerTokenErrorCodes; |  | ||||||
| import org.springframework.security.web.server.authentication.ServerAuthenticationConverter; | import org.springframework.security.web.server.authentication.ServerAuthenticationConverter; | ||||||
| import org.springframework.util.StringUtils; | import org.springframework.util.StringUtils; | ||||||
| import org.springframework.web.server.ServerWebExchange; | import org.springframework.web.server.ServerWebExchange; | ||||||
| import reactor.core.publisher.Mono; |  | ||||||
| 
 | 
 | ||||||
| import java.util.regex.Matcher; | import static org.springframework.security.oauth2.server.resource.BearerTokenErrors.invalidRequest; | ||||||
| import java.util.regex.Pattern; | import static org.springframework.security.oauth2.server.resource.BearerTokenErrors.invalidToken; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * A strategy for resolving <a href="https://tools.ietf.org/html/rfc6750#section-1.2" target="_blank">Bearer Token</a>s |  * A strategy for resolving <a href="https://tools.ietf.org/html/rfc6750#section-1.2" target="_blank">Bearer Token</a>s | ||||||
|  | @ -65,10 +67,7 @@ public class ServerBearerTokenAuthenticationConverter | ||||||
| 		String parameterToken = request.getQueryParams().getFirst("access_token"); | 		String parameterToken = request.getQueryParams().getFirst("access_token"); | ||||||
| 		if (authorizationHeaderToken != null) { | 		if (authorizationHeaderToken != null) { | ||||||
| 			if (parameterToken != null) { | 			if (parameterToken != null) { | ||||||
| 				BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_REQUEST, | 				BearerTokenError error = invalidRequest("Found multiple bearer tokens in the request"); | ||||||
| 						HttpStatus.BAD_REQUEST, |  | ||||||
| 						"Found multiple bearer tokens in the request", |  | ||||||
| 						"https://tools.ietf.org/html/rfc6750#section-3.1"); |  | ||||||
| 				throw new OAuth2AuthenticationException(error); | 				throw new OAuth2AuthenticationException(error); | ||||||
| 			} | 			} | ||||||
| 			return authorizationHeaderToken; | 			return authorizationHeaderToken; | ||||||
|  | @ -107,10 +106,7 @@ public class ServerBearerTokenAuthenticationConverter | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private static BearerTokenError invalidTokenError() { | 	private static BearerTokenError invalidTokenError() { | ||||||
| 		return new BearerTokenError(BearerTokenErrorCodes.INVALID_TOKEN, | 		return invalidToken("Bearer token is malformed"); | ||||||
| 							HttpStatus.UNAUTHORIZED, |  | ||||||
| 							"Bearer token is malformed", |  | ||||||
| 							"https://tools.ietf.org/html/rfc6750#section-3.1"); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private boolean isParameterTokenSupportedForRequest(ServerHttpRequest request) { | 	private boolean isParameterTokenSupportedForRequest(ServerHttpRequest request) { | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2018 the original author or authors. |  * Copyright 2002-2020 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. | ||||||
|  | @ -95,7 +95,7 @@ public class JwtAuthenticationProviderTests { | ||||||
| 				.isInstanceOf(OAuth2AuthenticationException.class) | 				.isInstanceOf(OAuth2AuthenticationException.class) | ||||||
| 				.hasFieldOrPropertyWithValue( | 				.hasFieldOrPropertyWithValue( | ||||||
| 						"error.description", | 						"error.description", | ||||||
| 						"An error occurred while attempting to decode the Jwt: Invalid token"); | 						"Invalid token"); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2019 the original author or authors. |  * Copyright 2002-2020 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. | ||||||
|  | @ -162,7 +162,7 @@ public class JwtIssuerAuthenticationManagerResolverTests { | ||||||
| 		request.addHeader("Authorization", "Bearer " + this.evil); | 		request.addHeader("Authorization", "Bearer " + this.evil); | ||||||
| 		assertThatCode(() -> authenticationManagerResolver.resolve(request)) | 		assertThatCode(() -> authenticationManagerResolver.resolve(request)) | ||||||
| 				.isInstanceOf(OAuth2AuthenticationException.class) | 				.isInstanceOf(OAuth2AuthenticationException.class) | ||||||
| 				.hasMessage("Invalid token"); | 				.hasMessage("Invalid issuer"); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2018 the original author or authors. |  * Copyright 2002-2020 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. | ||||||
|  | @ -98,7 +98,7 @@ public class JwtReactiveAuthenticationManagerTests { | ||||||
| 				.isInstanceOf(OAuth2AuthenticationException.class) | 				.isInstanceOf(OAuth2AuthenticationException.class) | ||||||
| 				.hasFieldOrPropertyWithValue( | 				.hasFieldOrPropertyWithValue( | ||||||
| 						"error.description", | 						"error.description", | ||||||
| 						"An error occurred while attempting to decode the Jwt: Invalid token"); | 						"Invalid token"); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2019 the original author or authors. |  * Copyright 2002-2020 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. | ||||||
|  | @ -111,7 +111,7 @@ public class OpaqueTokenAuthenticationProviderTests { | ||||||
| 		assertThatCode(() -> provider.authenticate(new BearerTokenAuthenticationToken("token"))) | 		assertThatCode(() -> provider.authenticate(new BearerTokenAuthenticationToken("token"))) | ||||||
| 				.isInstanceOf(OAuth2AuthenticationException.class) | 				.isInstanceOf(OAuth2AuthenticationException.class) | ||||||
| 				.extracting("error.description") | 				.extracting("error.description") | ||||||
| 				.isEqualTo("An error occurred while attempting to introspect the token: Invalid token"); | 				.isEqualTo("Invalid token"); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2019 the original author or authors. |  * Copyright 2002-2020 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. | ||||||
|  | @ -117,7 +117,7 @@ public class OpaqueTokenReactiveAuthenticationManagerTests { | ||||||
| 		assertThatCode(() -> provider.authenticate(new BearerTokenAuthenticationToken("token")).block()) | 		assertThatCode(() -> provider.authenticate(new BearerTokenAuthenticationToken("token")).block()) | ||||||
| 				.isInstanceOf(OAuth2AuthenticationException.class) | 				.isInstanceOf(OAuth2AuthenticationException.class) | ||||||
| 				.extracting("error.description") | 				.extracting("error.description") | ||||||
| 				.isEqualTo("An error occurred while attempting to introspect the token: Invalid token"); | 				.isEqualTo("Invalid token"); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Test | 	@Test | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue