comparison mod_http_oauth2/mod_http_oauth2.lua @ 5367:93d445b26063

mod_http_oauth2: Validate redirect URI depending on application type Per https://openid.net/specs/openid-connect-registration-1_0.html require that web applications use https:// and native applications must use either http://localhost or a custom (non-https) URI. Previous requirement that hostname matches that of client_uri is kept for web applications.
author Kim Alvefur <zash@zash.se>
date Tue, 25 Apr 2023 19:49:41 +0200
parents db4c66a1d24b
children 8b7d97f0ae8a
comparison
equal deleted inserted replaced
5366:db4c66a1d24b 5367:93d445b26063
655 "urn:ietf:params:oauth:grant-type:saml2-bearer"; 655 "urn:ietf:params:oauth:grant-type:saml2-bearer";
656 }; 656 };
657 }; 657 };
658 default = { "authorization_code" }; 658 default = { "authorization_code" };
659 }; 659 };
660 application_type = { type = "string"; enum = { "native"; "web" }; default = "web" };
660 response_types = { type = "array"; items = { type = "string"; enum = { "code"; "token" } }; default = { "code" } }; 661 response_types = { type = "array"; items = { type = "string"; enum = { "code"; "token" } }; default = { "code" } };
661 client_name = { type = "string" }; 662 client_name = { type = "string" };
662 client_uri = { type = "string"; format = "uri"; luaPattern = "^https:" }; 663 client_uri = { type = "string"; format = "uri"; luaPattern = "^https:" };
663 logo_uri = { type = "string"; format = "uri"; luaPattern = "^https:" }; 664 logo_uri = { type = "string"; format = "uri"; luaPattern = "^https:" };
664 scope = { type = "string" }; 665 scope = { type = "string" };
675 ["^client_name#"] = { description = "Localized version of 'client_name'"; type = "string" }; 676 ["^client_name#"] = { description = "Localized version of 'client_name'"; type = "string" };
676 ["^[a-z_]+_uri#"] = { type = "string"; format = "uri"; luaPattern = "^https:" }; 677 ["^[a-z_]+_uri#"] = { type = "string"; format = "uri"; luaPattern = "^https:" };
677 }; 678 };
678 } 679 }
679 680
681 local function redirect_uri_allowed(redirect_uri, client_uri, app_type)
682 local uri = url.parse(redirect_uri);
683 if app_type == "native" then
684 return uri.scheme == "http" and uri.host == "localhost" or uri.scheme ~= "https";
685 elseif app_type == "web" then
686 return uri.scheme == "https" and uri.host == client_uri.host;
687 end
688 end
689
680 function create_client(client_metadata) 690 function create_client(client_metadata)
681 if not schema.validate(registration_schema, client_metadata) then 691 if not schema.validate(registration_schema, client_metadata) then
682 return nil, oauth_error("invalid_request", "Failed schema validation."); 692 return nil, oauth_error("invalid_request", "Failed schema validation.");
683 end 693 end
684 694
693 if not client_uri or client_uri.scheme ~= "https" then 703 if not client_uri or client_uri.scheme ~= "https" then
694 return nil, oauth_error("invalid_request", "Missing, invalid or insecure client_uri"); 704 return nil, oauth_error("invalid_request", "Missing, invalid or insecure client_uri");
695 end 705 end
696 706
697 for _, redirect_uri in ipairs(client_metadata.redirect_uris) do 707 for _, redirect_uri in ipairs(client_metadata.redirect_uris) do
698 local components = url.parse(redirect_uri); 708 if not redirect_uri_allowed(redirect_uri, client_uri, client_metadata.application_type) then
699 if not components or not components.scheme then 709 return nil, oauth_error("invalid_request", "Invalid, insecure or inappropriate redirect URI.");
700 return nil, oauth_error("invalid_request", "Invalid redirect URI.");
701 elseif components.scheme == "http" and components.host ~= "localhost" then
702 return nil, oauth_error("invalid_request", "Insecure redirect URI forbidden (except http://localhost)");
703 elseif components.scheme == "https" and components.host ~= client_uri.host then
704 return nil, oauth_error("invalid_request", "Redirects must use the same hostname as client_uri");
705 end 710 end
706 end 711 end
707 712
708 for field, prop_schema in pairs(registration_schema.properties) do 713 for field, prop_schema in pairs(registration_schema.properties) do
709 if field ~= "client_uri" and prop_schema.format == "uri" and client_metadata[field] then 714 if field ~= "client_uri" and prop_schema.format == "uri" and client_metadata[field] then