comparison mod_http_oauth2/mod_http_oauth2.lua @ 5502:fd4d89a5b8db

mod_http_oauth2: Add provisions for dynamically adding simple scopes This lets additional modules define what scopes they might add to the userinfo endpoint, or other things.
author Kim Alvefur <zash@zash.se>
date Thu, 01 Jun 2023 18:16:13 +0200
parents 57ce8c4017e7
children ae007be8a6bd
comparison
equal deleted inserted replaced
5501:57ce8c4017e7 5502:fd4d89a5b8db
70 body = _render_html(template, data); 70 body = _render_html(template, data);
71 }; 71 };
72 return resp; 72 return resp;
73 end 73 end
74 74
75 local authorization_server_metadata = nil;
76
75 local tokens = module:depends("tokenauth"); 77 local tokens = module:depends("tokenauth");
76 78
77 local default_access_ttl = module:get_option_number("oauth2_access_token_ttl", 86400); 79 local default_access_ttl = module:get_option_number("oauth2_access_token_ttl", 86400);
78 local default_refresh_ttl = module:get_option_number("oauth2_refresh_token_ttl", nil); 80 local default_refresh_ttl = module:get_option_number("oauth2_refresh_token_ttl", nil);
79 81
103 -- string -> array 105 -- string -> array
104 local function parse_scopes(scope_string) 106 local function parse_scopes(scope_string)
105 return array(scope_string:gmatch("%S+")); 107 return array(scope_string:gmatch("%S+"));
106 end 108 end
107 109
108 local openid_claims = set.new({ "openid"; "profile"; "email"; "address"; "phone" }); 110 local openid_claims = set.new();
111 module:add_item("openid-claim", "openid");
112
113 module:handle_items("openid-claim", function(event)
114 authorization_server_metadata = nil;
115 openid_claims:add(event.item);
116 end, function()
117 authorization_server_metadata = nil;
118 openid_claims = set.new(module:get_host_items("openid-claim"));
119 end, true);
109 120
110 -- array -> array, array, array 121 -- array -> array, array, array
111 local function split_scopes(scope_list) 122 local function split_scopes(scope_list)
112 local claims, roles, unknown = array(), array(), array(); 123 local claims, roles, unknown = array(), array(), array();
113 local all_roles = usermanager.get_all_roles(module.host); 124 local all_roles = usermanager.get_all_roles(module.host);
1077 return json.encode(oauth2_response); 1088 return json.encode(oauth2_response);
1078 end, 5); 1089 end, 5);
1079 1090
1080 -- OIDC Discovery 1091 -- OIDC Discovery
1081 1092
1093 function get_authorization_server_metadata()
1094 if authorization_server_metadata then
1095 return authorization_server_metadata;
1096 end
1097 authorization_server_metadata = {
1098 -- RFC 8414: OAuth 2.0 Authorization Server Metadata
1099 issuer = get_issuer();
1100 authorization_endpoint = handle_authorization_request and module:http_url() .. "/authorize" or nil;
1101 token_endpoint = handle_token_grant and module:http_url() .. "/token" or nil;
1102 registration_endpoint = handle_register_request and module:http_url() .. "/register" or nil;
1103 scopes_supported = usermanager.get_all_roles
1104 and array(it.keys(usermanager.get_all_roles(module.host))):push("xmpp"):append(array(openid_claims:items()));
1105 response_types_supported = array(it.keys(response_type_handlers));
1106 token_endpoint_auth_methods_supported = array({ "client_secret_post"; "client_secret_basic" });
1107 op_policy_uri = module:get_option_string("oauth2_policy_url", nil);
1108 op_tos_uri = module:get_option_string("oauth2_terms_url", nil);
1109 revocation_endpoint = handle_revocation_request and module:http_url() .. "/revoke" or nil;
1110 revocation_endpoint_auth_methods_supported = array({ "client_secret_basic" });
1111 code_challenge_methods_supported = array(it.keys(verifier_transforms));
1112 grant_types_supported = array(it.keys(response_type_handlers)):map(tmap {
1113 token = "implicit";
1114 code = "authorization_code";
1115 });
1116 response_modes_supported = array(it.keys(response_type_handlers)):map(tmap { token = "fragment"; code = "query" });
1117 authorization_response_iss_parameter_supported = true;
1118 service_documentation = module:get_option_string("oauth2_service_documentation", "https://modules.prosody.im/mod_http_oauth2.html");
1119
1120 -- OpenID
1121 userinfo_endpoint = handle_register_request and module:http_url() .. "/userinfo" or nil;
1122 jwks_uri = nil; -- REQUIRED in OpenID Discovery but not in OAuth 2.0 Metadata
1123 id_token_signing_alg_values_supported = { "HS256" }; -- The algorithm RS256 MUST be included, but we use HS256 and client_secret as shared key.
1124 }
1125 return authorization_server_metadata;
1126 end
1127
1082 module:provides("http", { 1128 module:provides("http", {
1083 name = "oauth2-discovery"; 1129 name = "oauth2-discovery";
1084 default_path = "/.well-known/oauth-authorization-server"; 1130 default_path = "/.well-known/oauth-authorization-server";
1085 cors = { enabled = true }; 1131 cors = { enabled = true };
1086 route = { 1132 route = {
1087 ["GET"] = { 1133 ["GET"] = function()
1088 headers = { content_type = "application/json" }; 1134 return {
1089 body = json.encode { 1135 headers = { content_type = "application/json" };
1090 -- RFC 8414: OAuth 2.0 Authorization Server Metadata 1136 body = json.encode(get_authorization_server_metadata());
1091 issuer = get_issuer(); 1137 }
1092 authorization_endpoint = handle_authorization_request and module:http_url() .. "/authorize" or nil; 1138 end
1093 token_endpoint = handle_token_grant and module:http_url() .. "/token" or nil;
1094 registration_endpoint = handle_register_request and module:http_url() .. "/register" or nil;
1095 scopes_supported = usermanager.get_all_roles
1096 and array(it.keys(usermanager.get_all_roles(module.host))):push("xmpp"):append(array(openid_claims:items()));
1097 response_types_supported = array(it.keys(response_type_handlers));
1098 token_endpoint_auth_methods_supported = array({ "client_secret_post"; "client_secret_basic" });
1099 op_policy_uri = module:get_option_string("oauth2_policy_url", nil);
1100 op_tos_uri = module:get_option_string("oauth2_terms_url", nil);
1101 revocation_endpoint = handle_revocation_request and module:http_url() .. "/revoke" or nil;
1102 revocation_endpoint_auth_methods_supported = array({ "client_secret_basic" });
1103 code_challenge_methods_supported = array(it.keys(verifier_transforms));
1104 grant_types_supported = array(it.keys(response_type_handlers)):map(tmap { token = "implicit"; code = "authorization_code" });
1105 response_modes_supported = array(it.keys(response_type_handlers)):map(tmap { token = "fragment"; code = "query" });
1106 authorization_response_iss_parameter_supported = true;
1107 service_documentation = module:get_option_string("oauth2_service_documentation", "https://modules.prosody.im/mod_http_oauth2.html");
1108
1109 -- OpenID
1110 userinfo_endpoint = handle_register_request and module:http_url() .. "/userinfo" or nil;
1111 jwks_uri = nil; -- REQUIRED in OpenID Discovery but not in OAuth 2.0 Metadata
1112 id_token_signing_alg_values_supported = { "HS256" }; -- The algorithm RS256 MUST be included, but we use HS256 and client_secret as shared key.
1113 };
1114 };
1115 }; 1139 };
1116 }); 1140 });
1117 1141
1118 module:shared("tokenauth/oauthbearer_config").oidc_discovery_url = module:http_url("oauth2-discovery", "/.well-known/oauth-authorization-server"); 1142 module:shared("tokenauth/oauthbearer_config").oidc_discovery_url = module:http_url("oauth2-discovery", "/.well-known/oauth-authorization-server");