/cc @vpavic @jzheaux @rwinch @tnwang @nlebas
Let's revisit the Authentication scheme case-insensitivity as it seems we're not all on the same page as of yet. This is related to #6150 #5586 #6195
I've re-read the 3 related specs and have provided references below along with my comments.
RFC 6750 - The OAuth 2.0 Authorization Framework: Bearer Token Usage
Key references
** Take note of the highlighted
2.1. Authorization Request Header Field
When sending the access token in the "Authorization" request header field defined by HTTP/1.1 [RFC2617], the client uses the "Bearer" authentication scheme to transmit the access token.
For example:
GET /resource HTTP/1.1
Host: server.example.com
Authorization: Bearer mF_9.B5f-4.1JqM
The syntax of the "Authorization" header field for this scheme follows the usage of the Basic scheme defined in Section 2 of [RFC2617]. Note that, as with Basic, it does not conform to the generic syntax defined in Section 1.2 of [RFC2617] but is compatible with the general authentication framework being developed for HTTP 1.1 [HTTP-AUTH], although it does not follow the preferred practice outlined therein in order to reflect existing deployments. The syntax for Bearer credentials is as follows:
b64token = 1*( ALPHA / DIGIT /
"-" / "." / "_" / "~" / "+" / "/" ) *"="
credentials = "Bearer" 1*SP b64token
Clients SHOULD make authenticated requests with a bearer token using the "Authorization" request header field with the "Bearer" HTTP authorization scheme. Resource servers MUST support this method.
Comments:
- Bearer scheme follows the usage of the Basic scheme defined in Section 2 RFC 2617
- Basic scheme does not conform to the generic syntax defined in Section 1.2 of RFC 2617 (which is case-insensitivity for auth-scheme) but is compatible with the general authentication framework. The key point in the last sentence is COMPATIBILITY. So IMO, accepting a lower-case bearer or basic auth-scheme promotes this compatibility.
RFC 2617 - HTTP Authentication: Basic and Digest Access Authentication
Key references
** Take note of the highlighted
1.2 Access Authentication Framework
HTTP provides a simple challenge-response authentication mechanism that MAY be used by a server to challenge a client request and by a client to provide authentication information. It uses an extensible, case-insensitive token to identify the authentication scheme, followed by a comma-separated list of attribute-value pairs which carry the parameters necessary for achieving authentication via that scheme.
2. Basic Authentication Scheme
The "basic" authentication scheme is based on the model that the client must authenticate itself with a user-ID and a password for each realm. The realm value should be considered an opaque string which can only be compared for equality with other realms on that server. The server will service the request only if it can validate the user-ID and password for the protection space of the Request-URI. There are no optional authentication parameters.
For Basic, the framework above is utilized as follows:
challenge = "Basic" realm
credentials = "Basic" basic-credentials
Comments:
- The challenge-response authentication mechanism explicitly states...it uses an extensible case-insensitive token to identify the authentication scheme. Therefore, the server MAY send back bearer or basic as the auth-scheme in the challenge as it is case-insensitive. Now given that the server may send back a case-insensitive auth-scheme, would it be logical to assume that the server may accept a case-insensitive auth-scheme in the client response as well? IMO, this makes sense and validates that auth-scheme is in fact case-insensitive on both ends.
RFC 7617 - The 'Basic' HTTP Authentication Scheme
Key references
** Take note of the highlighted
This document defines the "Basic" Hypertext Transfer Protocol (HTTP) authentication scheme, which transmits credentials as user-id/ password pairs, encoded using Base64 (HTTP authentication schemes are defined in [RFC7235]).
This scheme is not considered to be a secure method of user authentication unless used in conjunction with some external secure system such as TLS (Transport Layer Security, [RFC5246]), as the user-id and password are passed over the network as cleartext.
The "Basic" scheme previously was defined in Section 2 of [RFC2617]. This document updates the definition, and also addresses internationalization issues by introducing the 'charset' authentication parameter (Section 2.1).
2. The 'Basic' Authentication Scheme
The Basic authentication scheme is based on the model that the client needs to authenticate itself with a user-id and a password for each protection space ("realm"). The realm value is a free-form string that can only be compared for equality with other realms on that server. The server will service the request only if it can validate the user-id and password for the protection space applying to the requested resource.
The Basic authentication scheme utilizes the Authentication Framework as follows.
In challenges:
o The scheme name is "Basic".
o The authentication parameter 'realm' is REQUIRED ([RFC7235], Section 2.2).
o The authentication parameter 'charset' is OPTIONAL (see Section 2.1).
o No other authentication parameters are defined -- unknown parameters MUST be ignored by recipients, and new parameters can only be defined by revising this specification.
See also Section 4.1 of [RFC7235], which discusses the complexity of parsing challenges properly.
Note that both scheme and parameter names are matched case- insensitively.
For credentials, the "token68" syntax defined in Section 2.1 of [RFC7235] is used. The value is computed based on user-id and password as defined below.
Comments:
- NOTE: RFC 7617 (this one) updates RFC2617.
- This spec also states...both scheme and parameter names are matched case- insensitively. Although it refers to the auth-scheme in the challenge, IMO it should also support case-insensitivity in the client response (eg. Authorization header). It simply does not make sense if the server returns "basic" as the auth-scheme in the challenge and does not support "basic" in the client response Authorization header.
Comment From: vpavic
I'm only going to address the Bearer part here, but it's really nothing outside of the thoughts I already expressed in my comments on #6150.
The section 2.1 of RFC 6750 is quite explicit on the syntax of Authorization header for Bearer authentication scheme. There's no ambiguity there that would warrant pulling other Authorization header related specs into the mix (for the Bearer part that is).
With the current situation, if one wants to build a fully spec compliant service (which behaves like Google's, for example) they need to provide a custom (?!) BearerTokenResolver implementation. And on the principal, it's hard for me to understand that the spec aligned default is being changed due to other parties that aren't fully spec aligned.
Comment From: jzheaux
If the spec states that the scheme should be case insensitive, this should be our default, and then we should make it easy to deviate from that default.
The case for it being case-sensitive, as I see it, is here:
The syntax for Bearer credentials is as follows:
b64token = 1*( ALPHA / DIGIT /
"-" / "." / "_" / "~" / "+" / "/" ) *"="
credentials = "Bearer" 1*SP b64token
This BNF doesn't leave room for case-insensitivity. And the spec doesn't make any comment to clarify.
The case for it being case-insensitive is that this paragraph:
The syntax of the "Authorization" header field for this scheme
*follows the usage of the Basic scheme* defined in Section 2 of
[RFC2617]. Note that, **as with Basic**, it does not conform to the
generic syntax defined in Section 1.2 of [RFC2617] but is compatible
with the general authentication framework
Implies that what is true for Basic is true for Bearer.
The syntax for Basic, from RFC2617 is:
credentials = "Basic" basic-credentials
But RFC2617 also says:
It uses an extensible, case-insensitive token to identify the authentication scheme
followed by:
auth-scheme = token
Placing these three statements together means that simply consulting the Bearer BNF isn't sufficient since the paragraph preceding the BNF clearly states that Bearer should be like Basic.
I do not see the same explicitness that @vpavic sees. Personally, if the paragraph didn't say "follows the usage of the Basic scheme" and "as with Basic", I would agree that we'd be left only with RFC 6750 to consult.
My conclusion is that the spec is unclear. Since it is unclear, Spring Security will likely be unsuccessful at stating that it defaults to case-sensitivity because it "follows the spec", implying that others do not.
Because the spec is ambiguous, then the next quality to look for is compatibility.
I don't have a lot to say about compatibility; @jgrandja mentioned to me offline that he was looking a bit into that, and we have anecdotes from members of the community that the components they use send bearer instead of Bearer.
However, a couple of quick points about the open-source authentication community:
- Keycloak is case-insensitive for both Basic and Bearer authentication.
- pac4j is case-sensitive for both Basic and Bearer authentication
I do not know whether pac4j's case-sensitivity is a proactive choice since it takes more thought to say equalsIgnoreCase than equals. However, with Keycloak it seems clear that a proactive decision was made to match the auth-scheme insensitively, and I would wager it was a compatibility choice.
Another point, then, is to consider consistency across Spring Security. BasicAuthenticationFilter allows for case-insensitivity, and so it is more surprising to the user to find out that we are case-insensitive there while being case-sensitive with bearer token authentication. If the spec were clear, I would advocate deviating from the pattern Spring Security already established. But since the spec is not clear on this point and since other frameworks and products are lenient on this point, Spring Security should be as well.
Comment From: jgrandja
I did a quick test with oauth2Login() to access the UserInfo Endpoint with (lowercase) bearer and this actually failed for Google and Okta. However, it did succeed for UAA. So there is definitely inconsistencies amongst different provider's.
Comment From: jgrandja
@rwinch @jzheaux @vpavic This issue has been open for quite some time. Can we close this or is there more to address?
Comment From: rwinch
Can we support strict case sensitivity and case insensitive environments?
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: jgrandja
@rwinch
Can we support strict case sensitivity and case insensitive environments?
Can you please elaborate so I can better understand.
Comment From: rwinch
We spoke about this offline and determined this is completed.