Software /
code /
prosody-modules
Comparison
mod_http_oauth2/mod_http_oauth2.lua @ 5554:90449babaa48
mod_http_oauth2: Make allowed locales configurable
Explicit > Implicit
Instead of allowing anything after #, allow only the explicitly
configured locales to be used.
Default to empty list because using these is not supported yet.
This potentially limits the size of the client_id, which is already
quite large. Nothing prevents clients from registering a whole
client_id per locale, which would not require translation support on
this side.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sat, 17 Jun 2023 19:03:32 +0200 |
parent | 5553:67152838afbc |
child | 5559:d7fb8b266663 |
comparison
equal
deleted
inserted
replaced
5553:67152838afbc | 5554:90449babaa48 |
---|---|
57 end | 57 end |
58 local data = assert(f:read("*a")); | 58 local data = assert(f:read("*a")); |
59 assert(f:close()); | 59 assert(f:close()); |
60 return data; | 60 return data; |
61 end | 61 end |
62 | |
63 local allowed_locales = module:get_option_array("allowed_oauth2_locales", {}); | |
64 -- TODO Allow translations or per-locale templates somehow. | |
62 | 65 |
63 local template_path = module:get_option_path("oauth2_template_path", "html"); | 66 local template_path = module:get_option_path("oauth2_template_path", "html"); |
64 local templates = { | 67 local templates = { |
65 login = read_file(template_path, "login.html", true); | 68 login = read_file(template_path, "login.html", true); |
66 consent = read_file(template_path, "consent.html", true); | 69 consent = read_file(template_path, "consent.html", true); |
934 jwks_uri = { type = "string"; format = "uri"; pattern = "^https:" }; | 937 jwks_uri = { type = "string"; format = "uri"; pattern = "^https:" }; |
935 jwks = { type = "object"; description = "JSON Web Key Set, RFC 7517" }; | 938 jwks = { type = "object"; description = "JSON Web Key Set, RFC 7517" }; |
936 software_id = { type = "string"; format = "uuid" }; | 939 software_id = { type = "string"; format = "uuid" }; |
937 software_version = { type = "string" }; | 940 software_version = { type = "string" }; |
938 }; | 941 }; |
939 luaPatternProperties = { | |
940 -- Localized versions of descriptive properties and URIs | |
941 ["^client_name#"] = { description = "Localized version of 'client_name'"; type = "string" }; | |
942 ["^[a-z_]+_uri#"] = { type = "string"; format = "uri" }; | |
943 }; | |
944 } | 942 } |
943 | |
944 -- Limit per-locale fields to allowed locales, partly to keep size of client_id | |
945 -- down, partly because we don't yet use them for anything. | |
946 -- Only relevant for user-visible strings and URIs. | |
947 if allowed_locales[1] then | |
948 local props = registration_schema.properties; | |
949 for _, locale in ipairs(allowed_locales) do | |
950 props["client_name#" .. locale] = props["client_name"]; | |
951 props["client_uri#" .. locale] = props["client_uri"]; | |
952 props["logo_uri#" .. locale] = props["logo_uri"]; | |
953 props["tos_uri#" .. locale] = props["tos_uri"]; | |
954 props["policy_uri#" .. locale] = props["policy_uri"]; | |
955 end | |
956 end | |
945 | 957 |
946 local function redirect_uri_allowed(redirect_uri, client_uri, app_type) | 958 local function redirect_uri_allowed(redirect_uri, client_uri, app_type) |
947 local uri = url.parse(redirect_uri); | 959 local uri = url.parse(redirect_uri); |
948 if not uri.scheme then | 960 if not uri.scheme then |
949 return false; -- no relative URLs | 961 return false; -- no relative URLs |
979 end | 991 end |
980 | 992 |
981 for field, prop_schema in pairs(registration_schema.properties) do | 993 for field, prop_schema in pairs(registration_schema.properties) do |
982 if field ~= "client_uri" and prop_schema.format == "uri" and client_metadata[field] then | 994 if field ~= "client_uri" and prop_schema.format == "uri" and client_metadata[field] then |
983 if not redirect_uri_allowed(client_metadata[field], client_uri, "web") then | 995 if not redirect_uri_allowed(client_metadata[field], client_uri, "web") then |
984 return nil, oauth_error("invalid_client_metadata", "Invalid, insecure or inappropriate informative URI"); | |
985 end | |
986 end | |
987 end | |
988 | |
989 for k, v in pairs(client_metadata) do | |
990 local base_k = k:match"^([^#]+)#" or k; | |
991 if not registration_schema.properties[base_k] or k:find"^client_uri#" then | |
992 -- Ignore and strip unknown extra properties | |
993 client_metadata[k] = nil; | |
994 elseif k:find"_uri#" then | |
995 -- Localized URIs should be secure too | |
996 if not redirect_uri_allowed(v, client_uri, "web") then | |
997 return nil, oauth_error("invalid_client_metadata", "Invalid, insecure or inappropriate informative URI"); | 996 return nil, oauth_error("invalid_client_metadata", "Invalid, insecure or inappropriate informative URI"); |
998 end | 997 end |
999 end | 998 end |
1000 end | 999 end |
1001 | 1000 |
1202 code = "authorization_code"; | 1201 code = "authorization_code"; |
1203 }); | 1202 }); |
1204 response_modes_supported = array(it.keys(response_type_handlers)):map(tmap { token = "fragment"; code = "query" }); | 1203 response_modes_supported = array(it.keys(response_type_handlers)):map(tmap { token = "fragment"; code = "query" }); |
1205 authorization_response_iss_parameter_supported = true; | 1204 authorization_response_iss_parameter_supported = true; |
1206 service_documentation = module:get_option_string("oauth2_service_documentation", "https://modules.prosody.im/mod_http_oauth2.html"); | 1205 service_documentation = module:get_option_string("oauth2_service_documentation", "https://modules.prosody.im/mod_http_oauth2.html"); |
1206 ui_locales_supported = allowed_locales[1] and allowed_locales; | |
1207 | 1207 |
1208 -- OpenID | 1208 -- OpenID |
1209 userinfo_endpoint = handle_register_request and module:http_url() .. "/userinfo" or nil; | 1209 userinfo_endpoint = handle_register_request and module:http_url() .. "/userinfo" or nil; |
1210 jwks_uri = nil; -- REQUIRED in OpenID Discovery but not in OAuth 2.0 Metadata | 1210 jwks_uri = nil; -- REQUIRED in OpenID Discovery but not in OAuth 2.0 Metadata |
1211 id_token_signing_alg_values_supported = { "HS256" }; -- The algorithm RS256 MUST be included, but we use HS256 and client_secret as shared key. | 1211 id_token_signing_alg_values_supported = { "HS256" }; -- The algorithm RS256 MUST be included, but we use HS256 and client_secret as shared key. |