# HG changeset patch # User Kim Alvefur # Date 1683826424 -7200 # Node ID aa4828f040c5db5ec458977e2488797c01cd3132 # Parent dd7bddc87f989dabc2fa98f36c44101e771272af mod_http_oauth2: Enforce client scope restrictions in authorization When registering a client, a scope field can be included as a promise to only ever use those. Here we enforce that promise, if given, ensuring a client can't request or be granted a scope it didn't provide in its registration. While currently there is no restrictions at registration time, this could be changed in the future in various ways. diff -r dd7bddc87f98 -r aa4828f040c5 mod_http_oauth2/mod_http_oauth2.lua --- a/mod_http_oauth2/mod_http_oauth2.lua Thu May 11 21:37:35 2023 +0200 +++ b/mod_http_oauth2/mod_http_oauth2.lua Thu May 11 19:33:44 2023 +0200 @@ -477,14 +477,14 @@ }; end - local scope = array():append(form):filter(function(field) + local scopes = array():append(form):filter(function(field) return field.name == "scope"; - end):pluck("value"):concat(" "); + end):pluck("value"); user.token = form.user_token; return { user = user; - scope = scope; + scopes = scopes; consent = form.consent == "granted"; }; end @@ -649,13 +649,21 @@ return oauth_error("invalid_client", "response_type not allowed"); end + local requested_scopes = parse_scopes(params.scope or ""); + if client.scope then + local client_scopes = set.new(parse_scopes(client.scope)); + requested_scopes:filter(function(scope) + return client_scopes:contains(scope); + end); + end + local auth_state = get_auth_state(request); if not auth_state.user then -- Render login page return render_page(templates.login, { state = auth_state, client = client }); elseif auth_state.consent == nil then -- Render consent page - local scopes, roles = split_scopes(parse_scopes(params.scope or "")); + local scopes, roles = split_scopes(requested_scopes); return render_page(templates.consent, { state = auth_state; client = client; scopes = scopes+roles }, true); elseif not auth_state.consent then -- Notify client of rejection @@ -663,7 +671,15 @@ end -- else auth_state.consent == true - params.scope = auth_state.scope; + local granted_scopes = auth_state.scopes + if client.scope then + local client_scopes = set.new(parse_scopes(client.scope)); + granted_scopes:filter(function(scope) + return client_scopes:contains(scope); + end); + end + + params.scope = granted_scopes:concat(" "); local user_jid = jid.join(auth_state.user.username, module.host); local client_secret = make_client_secret(params.client_id);