comparison mod_http_oauth2/mod_http_oauth2.lua @ 5682:527c747711f3

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.
author Kim Alvefur <zash@zash.se>
date Sun, 29 Oct 2023 11:30:49 +0100
parents 8cb3da7df521
children 8488ebde5739
comparison
equal deleted inserted replaced
5681:8cb3da7df521 5682:527c747711f3
1097 jti = token_info.id; 1097 jti = token_info.id;
1098 }; 1098 };
1099 }; 1099 };
1100 end 1100 end
1101 1101
1102 -- 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
1103 -- 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.
1102 local strict_auth_revoke = module:get_option_boolean("oauth2_require_auth_revoke", false); 1104 local strict_auth_revoke = module:get_option_boolean("oauth2_require_auth_revoke", false);
1103 1105
1104 local function handle_revocation_request(event) 1106 local function handle_revocation_request(event)
1105 local request, response = event.request, event.response; 1107 local request, response = event.request, event.response;
1106 response.headers.cache_control = "no-store"; 1108 response.headers.cache_control = "no-store";
1107 response.headers.pragma = "no-cache"; 1109 response.headers.pragma = "no-cache";
1108 if request.headers.authorization then 1110 local credentials = get_request_credentials(request);
1109 local credentials = get_request_credentials(request); 1111 if credentials then
1110 if not credentials or credentials.type ~= "basic" then 1112 if credentials.type ~= "basic" then
1111 response.headers.www_authenticate = string.format("Basic realm=%q", module.host.."/"..module.name); 1113 response.headers.www_authenticate = string.format("Basic realm=%q", module.host.."/"..module.name);
1112 return 401; 1114 return 401;
1113 end 1115 end
1114 -- OAuth "client" credentials 1116 -- OAuth "client" credentials
1115 if not verify_client_secret(credentials.username, credentials.password) then 1117 if not verify_client_secret(credentials.username, credentials.password) then
1125 local form_data = strict_formdecode(event.request.body); 1127 local form_data = strict_formdecode(event.request.body);
1126 if not form_data or not form_data.token then 1128 if not form_data or not form_data.token then
1127 response.headers.accept = "application/x-www-form-urlencoded"; 1129 response.headers.accept = "application/x-www-form-urlencoded";
1128 return 415; 1130 return 415;
1129 end 1131 end
1132
1133 if credentials then
1134 local client = check_client(credentials.username);
1135 if not client then
1136 return 401;
1137 end
1138 local token_info = tokens.get_token_info(form_data.token);
1139 if not token_info then
1140 return 404;
1141 end
1142 local token_client = token_info.grant.data.oauth2_client;
1143 if not token_client or token_client.hash ~= client.client_hash then
1144 return 403;
1145 end
1146 end
1147
1130 local ok, err = tokens.revoke_token(form_data.token); 1148 local ok, err = tokens.revoke_token(form_data.token);
1131 if not ok then 1149 if not ok then
1132 module:log("warn", "Unable to revoke token: %s", tostring(err)); 1150 module:log("warn", "Unable to revoke token: %s", tostring(err));
1133 return 500; 1151 return 500;
1134 end 1152 end