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({ |