comparison mod_http_oauth2/mod_http_oauth2.lua @ 5257:b2120fb4a279

mod_http_oauth2: Implement and return ID Token in authorization code flow Is this OIDC?
author Kim Alvefur <zash@zash.se>
date Thu, 16 Mar 2023 19:28:44 +0100
parents 44f7edd4f845
children 9629971e307f
comparison
equal deleted inserted replaced
5256:44f7edd4f845 5257:b2120fb4a279
150 -- client needs to be revoked 150 -- client needs to be revoked
151 local function client_subset(client) 151 local function client_subset(client)
152 return { name = client.client_name; uri = client.client_uri }; 152 return { name = client.client_name; uri = client.client_uri };
153 end 153 end
154 154
155 local function new_access_token(token_jid, role, scope, ttl, client) 155 local function new_access_token(token_jid, role, scope, ttl, client, id_token)
156 local token_data = {}; 156 local token_data = {};
157 if client then 157 if client then
158 token_data.oauth2_client = client_subset(client); 158 token_data.oauth2_client = client_subset(client);
159 end 159 end
160 if next(token_data) == nil then 160 if next(token_data) == nil then
164 return { 164 return {
165 token_type = "bearer"; 165 token_type = "bearer";
166 access_token = token; 166 access_token = token;
167 expires_in = ttl; 167 expires_in = ttl;
168 scope = scope; 168 scope = scope;
169 id_token = id_token;
169 -- TODO: include refresh_token when implemented 170 -- TODO: include refresh_token when implemented
170 }; 171 };
171 end 172 end
172 173
173 local function get_redirect_uri(client, query_redirect_uri) -- record client, string : string 174 local function get_redirect_uri(client, query_redirect_uri) -- record client, string : string
202 return oauth_error("invalid_grant", "incorrect credentials"); 203 return oauth_error("invalid_grant", "incorrect credentials");
203 end 204 end
204 205
205 local granted_jid = jid.join(request_username, request_host, request_resource); 206 local granted_jid = jid.join(request_username, request_host, request_resource);
206 local granted_scopes, granted_role = filter_scopes(request_username, params.scope); 207 local granted_scopes, granted_role = filter_scopes(request_username, params.scope);
207 return json.encode(new_access_token(granted_jid, granted_role, granted_scopes, nil)); 208 return json.encode(new_access_token(granted_jid, granted_role, granted_scopes, nil, nil));
208 end 209 end
209 210
210 function response_type_handlers.code(client, params, granted_jid) 211 function response_type_handlers.code(client, params, granted_jid, id_token)
211 local request_username, request_host = jid.split(granted_jid); 212 local request_username, request_host = jid.split(granted_jid);
212 if not request_host or request_host ~= module.host then 213 if not request_host or request_host ~= module.host then
213 return oauth_error("invalid_request", "invalid JID"); 214 return oauth_error("invalid_request", "invalid JID");
214 end 215 end
215 local granted_scopes, granted_role = filter_scopes(request_username, params.scope); 216 local granted_scopes, granted_role = filter_scopes(request_username, params.scope);
218 local ok = codes:set(params.client_id .. "#" .. code, { 219 local ok = codes:set(params.client_id .. "#" .. code, {
219 expires = os.time() + 600; 220 expires = os.time() + 600;
220 granted_jid = granted_jid; 221 granted_jid = granted_jid;
221 granted_scopes = granted_scopes; 222 granted_scopes = granted_scopes;
222 granted_role = granted_role; 223 granted_role = granted_role;
224 id_token = id_token;
223 }); 225 });
224 if not ok then 226 if not ok then
225 return {status_code = 429}; 227 return {status_code = 429};
226 end 228 end
227 229
266 local request_username, request_host = jid.split(granted_jid); 268 local request_username, request_host = jid.split(granted_jid);
267 if not request_host or request_host ~= module.host then 269 if not request_host or request_host ~= module.host then
268 return oauth_error("invalid_request", "invalid JID"); 270 return oauth_error("invalid_request", "invalid JID");
269 end 271 end
270 local granted_scopes, granted_role = filter_scopes(request_username, params.scope); 272 local granted_scopes, granted_role = filter_scopes(request_username, params.scope);
271 local token_info = new_access_token(granted_jid, granted_role, granted_scopes, nil, client); 273 local token_info = new_access_token(granted_jid, granted_role, granted_scopes, nil, client, nil);
272 274
273 local redirect = url.parse(get_redirect_uri(client, params.redirect_uri)); 275 local redirect = url.parse(get_redirect_uri(client, params.redirect_uri));
274 token_info.state = params.state; 276 token_info.state = params.state;
275 redirect.fragment = http.formencode(token_info); 277 redirect.fragment = http.formencode(token_info);
276 278
315 if not code or type(code) ~= "table" or code_expired(code) then 317 if not code or type(code) ~= "table" or code_expired(code) then
316 module:log("debug", "authorization_code invalid or expired: %q", code); 318 module:log("debug", "authorization_code invalid or expired: %q", code);
317 return oauth_error("invalid_client", "incorrect credentials"); 319 return oauth_error("invalid_client", "incorrect credentials");
318 end 320 end
319 321
320 return json.encode(new_access_token(code.granted_jid, code.granted_role, code.granted_scopes, nil, client)); 322 return json.encode(new_access_token(code.granted_jid, code.granted_role, code.granted_scopes, nil, client, code.id_token));
321 end 323 end
322 324
323 -- Used to issue/verify short-lived tokens for the authorization process below 325 -- Used to issue/verify short-lived tokens for the authorization process below
324 local new_user_token, verify_user_token = jwt.init("HS256", random.bytes(32), nil, { default_ttl = 600 }); 326 local new_user_token, verify_user_token = jwt.init("HS256", random.bytes(32), nil, { default_ttl = 600 });
325 327
547 elseif not auth_state.consent then 549 elseif not auth_state.consent then
548 -- Notify client of rejection 550 -- Notify client of rejection
549 return error_response(request, oauth_error("access_denied")); 551 return error_response(request, oauth_error("access_denied"));
550 end 552 end
551 553
554 local user_jid = jid.join(auth_state.user.username, module.host);
555 local client_secret = make_secret(params.client_id);
556 local id_token_signer = jwt.new_signer("HS256", client_secret);
557 local id_token = id_token_signer({
558 iss = get_issuer();
559 sub = url.build({ scheme = "xmpp"; path = user_jid });
560 aud = params.client_id;
561 nonce = params.nonce;
562 });
552 local response_type = params.response_type; 563 local response_type = params.response_type;
553 local response_handler = response_type_handlers[response_type]; 564 local response_handler = response_type_handlers[response_type];
554 if not response_handler then 565 if not response_handler then
555 return error_response(request, oauth_error("unsupported_response_type")); 566 return error_response(request, oauth_error("unsupported_response_type"));
556 end 567 end
557 return response_handler(client, params, jid.join(auth_state.user.username, module.host)); 568 return response_handler(client, params, user_jid, id_token);
558 end 569 end
559 570
560 local function handle_revocation_request(event) 571 local function handle_revocation_request(event)
561 local request, response = event.request, event.response; 572 local request, response = event.request, event.response;
562 if not request.headers.authorization then 573 if not request.headers.authorization then