Open jacknie84 opened 1 week ago
Thanks for reaching out @jacknie84!
If the token is an
empty string
rather thannull
, anIllegalArgumentException
will be thrown when creating aBearerTokenAuthenticationToken
instance
This is standard practice throughout the Spring Security codebase and Spring at large. The contract for BearerTokenAuthenticationToken
specifies through that assertion that empty string is invalid. You can (for example) customize Spring Boot error handling in various ways to return a particular response for IllegalArgumentException
, with @ControllerAdvice
being one of the easier methods for this customization.
In that case, the HTTP response code will be
500
(Internal Server Error). I don't think this is an accurate response, and I think it should be a401
(Unauthorized) response.
I'm sorry you're seeing an error you don't want. Typically, an IllegalArgumentException
would be mapped at the application level to a 400 Bad Request
error.
Regardless, assuming the request is unauthenticated, Spring Security protects the ERROR
dispatch by default just as it does for any other request, and requires authentication. Forwarded errors (such as this case with Spring Boot's /error
page) would by default return a 401 Unauthorized
for that reason. If you have found a case that returns a 500 Internal Server Error
for an unauthenticated request (without permitting the ERROR
dispatch), please provide a minimal sample and I will take a look. Otherwise, I plan to close this issue with the above explanation.
@sjohnr Thanks for your response. I will create a sample right away and share it with you.
Thanks @jacknie84. Please note that I just spotted this line in your configuration:
http
....
.securityMatchers(it -> it.requestMatchers("/partners/**", "/pa/**"))
This leaves part of your application unprotected, including /error
. You should remove this line to have a 401 response returned for unauthenticated users. Alternatively, you can set up another filter chain to protect the rest of the application. In that case, make sure to order the filter chains accordingly with @Order
.
In any case, a 500 would still be returned for uathenticated users, and you need to set up error handling for that exception if you want to customize the response.
If I've missed something feel free to continue providing a sample, but if that line is the reason you're seeing 500 for unauthenticated users (I believe it is) then please don't feel the need to provide a sample.
Thanks @sjohnr
I understand that an IllegalArgumentException
is thrown and forwarded to the/error
path.
But my application does not protect the /error
path.
If the configuration line you mentioned is removed, when an IllegalArgumentException
is thrown, a series of logic will be executed, forwarding the /error
path. When executing the /error
request, the security filter chain recognizes the user as an unauthenticated user and sends a 401
response, but this is not what I want.
I think it should be processed so that a 401
response is possible within the security filter chain that handles the existing requested path rather than forwarding to the /error
path. If so, WWW-Authenticate: Bearer error="invalid_token", error_description="An error occurred while attempting to decode the Jwt: Malformed token", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1 "
I expect it to respond with a header.
I have prepared a simple sample. github repository link
When you start the sample application server I prepared, you can request the/sample
path and receive a 500
response.
Please check my PR for information on how to request the /sample
route and receive a 401
response.
@jacknie84 thanks for your reply and sample.
But my application does not protect the
/error
path.
I would recommend that the entire application be protected unless it is not possible for some other reason.
If the configuration line you mentioned is removed, when an
IllegalArgumentException
is thrown, a series of logic will be executed, forwarding the/error
path. When executing the/error
request, the security filter chain recognizes the user as an unauthenticated user and sends a401
response, but this is not what I want.
Spring Security uses a secure-by-default approach, so this is by design. If necessary, you can permit the /error
page or the ERROR dispatch if desired. For example:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
...
.authorizeHttpRequests(authorize -> authorize
// Either of the following lines will display errors
.dispatcherTypeMatchers(DispatcherType.ERROR).permitAll()
.requestMatchers("/error").permitAll()
...
.anyRequest().authenticated()
);
return http.build();
}
}
I think it should be processed so that a
401
response is possible within the security filter chain that handles the existing requested path rather than forwarding to the/error
path. If so,WWW-Authenticate: Bearer error="invalid_token", error_description="An error occurred while attempting to decode the Jwt: Malformed token", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1 "
I expect it to respond with a header.
An empty token value is not a malformed token, but is invalid input. The IllegalArgumentException
is the correct exception. The assertion in the constructor is part of the contract of BearerTokenAuthenticationToken
so it would be incorrect to change the constructor of this class to achieve the goal of getting a particular HTTP response.
In RFC 6750, it defines an error for invalid_request
with status 400 Bad Request
when the request is invalid.
invalid_request
The request is missing a required parameter, includes an unsupported parameter or parameter value, repeats the same parameter, uses more than one method for including an access token, or is otherwise malformed. The resource server SHOULD respond with the HTTP 400 (Bad Request) status code.
This error could be appropriate to return in this case. This change could be made in both DefaultBearerTokenResolver
and ServerBearerTokenAuthenticationConverter
. This would be a better change than what was provided in the PR, so please consider it instead. Let me know your thoughts on this.
Describe the bug If
allowFormEncodedBodyParameter
orallowUriQueryParameter
ofDefaultBearerTokenResolver
is set totrue
, a token will be retrieved from the request parameter. If the token is anempty string
rather thannull
, anIllegalArgumentException
will be thrown when creating aBearerTokenAuthenticationToken
instance in thedoFilterInternal
method code ofBearerTokenAuthenticationFilter
. In that case, the HTTP response code will be500
(Internal Server Error). I don't think this is an accurate response, and I think it should be a401
(Unauthorized) response.To Reproduce build.gradle
Configuration
curl
server log exception trace
Expected behavior
I think it should be a 401 (Unnauthoized) response.