Mercurial > prosody-modules
comparison mod_http_oauth2/mod_http_oauth2.lua @ 5447:aa4828f040c5
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.
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Thu, 11 May 2023 19:33:44 +0200 |
| parents | dd7bddc87f98 |
| children | 9d542e86e19a |
comparison
equal
deleted
inserted
replaced
| 5446:dd7bddc87f98 | 5447:aa4828f040c5 |
|---|---|
| 475 return { | 475 return { |
| 476 error = user == "token-expired" and "Session expired - try again" or nil; | 476 error = user == "token-expired" and "Session expired - try again" or nil; |
| 477 }; | 477 }; |
| 478 end | 478 end |
| 479 | 479 |
| 480 local scope = array():append(form):filter(function(field) | 480 local scopes = array():append(form):filter(function(field) |
| 481 return field.name == "scope"; | 481 return field.name == "scope"; |
| 482 end):pluck("value"):concat(" "); | 482 end):pluck("value"); |
| 483 | 483 |
| 484 user.token = form.user_token; | 484 user.token = form.user_token; |
| 485 return { | 485 return { |
| 486 user = user; | 486 user = user; |
| 487 scope = scope; | 487 scopes = scopes; |
| 488 consent = form.consent == "granted"; | 488 consent = form.consent == "granted"; |
| 489 }; | 489 }; |
| 490 end | 490 end |
| 491 | 491 |
| 492 return {}; | 492 return {}; |
| 647 client_response_types = set.intersection(client_response_types, allowed_response_type_handlers); | 647 client_response_types = set.intersection(client_response_types, allowed_response_type_handlers); |
| 648 if not client_response_types:contains(params.response_type) then | 648 if not client_response_types:contains(params.response_type) then |
| 649 return oauth_error("invalid_client", "response_type not allowed"); | 649 return oauth_error("invalid_client", "response_type not allowed"); |
| 650 end | 650 end |
| 651 | 651 |
| 652 local requested_scopes = parse_scopes(params.scope or ""); | |
| 653 if client.scope then | |
| 654 local client_scopes = set.new(parse_scopes(client.scope)); | |
| 655 requested_scopes:filter(function(scope) | |
| 656 return client_scopes:contains(scope); | |
| 657 end); | |
| 658 end | |
| 659 | |
| 652 local auth_state = get_auth_state(request); | 660 local auth_state = get_auth_state(request); |
| 653 if not auth_state.user then | 661 if not auth_state.user then |
| 654 -- Render login page | 662 -- Render login page |
| 655 return render_page(templates.login, { state = auth_state, client = client }); | 663 return render_page(templates.login, { state = auth_state, client = client }); |
| 656 elseif auth_state.consent == nil then | 664 elseif auth_state.consent == nil then |
| 657 -- Render consent page | 665 -- Render consent page |
| 658 local scopes, roles = split_scopes(parse_scopes(params.scope or "")); | 666 local scopes, roles = split_scopes(requested_scopes); |
| 659 return render_page(templates.consent, { state = auth_state; client = client; scopes = scopes+roles }, true); | 667 return render_page(templates.consent, { state = auth_state; client = client; scopes = scopes+roles }, true); |
| 660 elseif not auth_state.consent then | 668 elseif not auth_state.consent then |
| 661 -- Notify client of rejection | 669 -- Notify client of rejection |
| 662 return error_response(request, oauth_error("access_denied")); | 670 return error_response(request, oauth_error("access_denied")); |
| 663 end | 671 end |
| 664 -- else auth_state.consent == true | 672 -- else auth_state.consent == true |
| 665 | 673 |
| 666 params.scope = auth_state.scope; | 674 local granted_scopes = auth_state.scopes |
| 675 if client.scope then | |
| 676 local client_scopes = set.new(parse_scopes(client.scope)); | |
| 677 granted_scopes:filter(function(scope) | |
| 678 return client_scopes:contains(scope); | |
| 679 end); | |
| 680 end | |
| 681 | |
| 682 params.scope = granted_scopes:concat(" "); | |
| 667 | 683 |
| 668 local user_jid = jid.join(auth_state.user.username, module.host); | 684 local user_jid = jid.join(auth_state.user.username, module.host); |
| 669 local client_secret = make_client_secret(params.client_id); | 685 local client_secret = make_client_secret(params.client_id); |
| 670 local id_token_signer = jwt.new_signer("HS256", client_secret); | 686 local id_token_signer = jwt.new_signer("HS256", client_secret); |
| 671 local id_token = id_token_signer({ | 687 local id_token = id_token_signer({ |
