mod_http_oauth2: Limit revocation to clients own tokens in strict mode
RFC 7009 section 2.1 states:
> The authorization server first validates the client credentials (in
> case of a confidential client) and then verifies whether the token was
> issued to the client making the revocation request. If this
> validation fails, the request is refused and the client is informed of
> the error by the authorization server as described below.
The first part was already covered (in strict mode). This adds the later
part using the hash of client_id recorded in 0860497152af
It still seems weird to me that revoking a leaked token should not be
allowed whoever might have discovered it, as that seems the responsible
thing to do.
--- a/mod_http_oauth2/mod_http_oauth2.lua Sun Oct 29 11:20:15 2023 +0100
+++ b/mod_http_oauth2/mod_http_oauth2.lua Sun Oct 29 11:30:49 2023 +0100
@@ -1099,15 +1099,17 @@
};
end
+-- RFC 7009 says that the authorization server should validate that only the client that a token was issued to should be able to revoke it. However
+-- this would prevent someone who comes across a leaked token from doing the responsible thing and revoking it, so this is not enforced by default.
local strict_auth_revoke = module:get_option_boolean("oauth2_require_auth_revoke", false);
local function handle_revocation_request(event)
local request, response = event.request, event.response;
response.headers.cache_control = "no-store";
response.headers.pragma = "no-cache";
- if request.headers.authorization then
- local credentials = get_request_credentials(request);
- if not credentials or credentials.type ~= "basic" then
+ local credentials = get_request_credentials(request);
+ if credentials then
+ if credentials.type ~= "basic" then
response.headers.www_authenticate = string.format("Basic realm=%q", module.host.."/"..module.name);
return 401;
end
@@ -1127,6 +1129,22 @@
response.headers.accept = "application/x-www-form-urlencoded";
return 415;
end
+
+ if credentials then
+ local client = check_client(credentials.username);
+ if not client then
+ return 401;
+ end
+ local token_info = tokens.get_token_info(form_data.token);
+ if not token_info then
+ return 404;
+ end
+ local token_client = token_info.grant.data.oauth2_client;
+ if not token_client or token_client.hash ~= client.client_hash then
+ return 403;
+ end
+ end
+
local ok, err = tokens.revoke_token(form_data.token);
if not ok then
module:log("warn", "Unable to revoke token: %s", tostring(err));