]
Martin Mazanek reassigned ELY-1677:
-----------------------------------
Assignee: Martin Mazanek (was: Darran Lofthouse)
Elytron Bearer Token Authentication - Return a 401 on Invalid Token
-------------------------------------------------------------------
Key: ELY-1677
URL:
https://issues.jboss.org/browse/ELY-1677
Project: WildFly Elytron
Issue Type: Feature Request
Components: Authentication Mechanisms
Affects Versions: 1.7.0.CR1
Reporter: Edward Stathopoulos
Assignee: Martin Mazanek
Priority: Major
Fix For: 1.8.0.CR3
*Issue*
Currently, Elytron will send back a 403 Response when an invalid bearer token is sent.
For the built-in JWT validator (the token validation we are using), this [includes a few
checks like signature, expiration time, audience and
issuer|https://github.com/wildfly-security/wildfly-elytron/blob/1.7.0.CR1...].
It seems that the current
[
BearerTokenAuthenticationMechanism|https://github.com/wildfly-security/wi...]
does not differentiate between failed authentication and failed authorization, returning a
403 in both cases. This produces conflicting and erroneous results. Did I fail to
authenticate (say, expired JWT) or did I authenticate but do not have access to the
resource in question?
This would also be closer in line with [RFC 6750 (The OAuth 2.0 Authorization Framework:
Bearer Token
Usage)|https://tools.ietf.org/html/rfc6750#section-3] which includes an
example of an expired (invalid) token.
{quote}
And in response to a protected resource request with an
authentication attempt using an expired access token:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="example",
error="invalid_token",
error_description="The access token expired"
{quote}
*Potential Solution*
Perhaps this could be ameliorated by something akin to the following change in
BearerTokenAuthenticationMechanism::evaluateRequest by differentiating between failure to
authorize and failure to authenticate the token. Merely a quick, unvetted example as I
haven't had enough time to dig in to the source.
{code}
if (verifyCallback.isVerified()) {
AuthorizeCallback authorizeCallback = new AuthorizeCallback(null, null);
handleCallback(authorizeCallback);
if (authorizeCallback.isAuthorized()) {
httpBearer.debugf("Token authentication successful.");
handleCallback(new IdentityCredentialCallback(new
BearerTokenCredential(tokenEvidence.getToken()), true));
handleCallback(AuthenticationCompleteCallback.SUCCEEDED);
request.authenticationComplete();
return;
}
else{
httpBearer.debugf("Token authorization failed message.");
request.authenticationFailed("Some token unauthorized message", response
-> response.setStatusCode(FORBIDDEN));
return;
}
}
httpBearer.debugf("Token authentication failed.");
request.authenticationFailed("Invalid bearer token", response ->
response.setStatusCode(UNAUTHORIZED));
return;
{code}