Mercurial > prosody-modules
annotate mod_http_oauth2/mod_http_oauth2.lua @ 5395:82207f936f1f
mod_inotify_reload: Update to use FD watching method
This removes the need to present a fake socket interface, simplifying
everything.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sun, 30 Apr 2023 20:34:36 +0200 |
parents | 434ee49b04de |
children | ac7c5669e5f5 |
rev | line source |
---|---|
4263
d3af5f94d6df
mod_http_oauth2: Improve storage of client secret
Kim Alvefur <zash@zash.se>
parents:
4260
diff
changeset
|
1 local hashes = require "util.hashes"; |
4271
9623b99bb8d2
mod_http_oauth2: Keep authorization codes in memory instead of storage
Kim Alvefur <zash@zash.se>
parents:
4270
diff
changeset
|
2 local cache = require "util.cache"; |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
3 local http = require "util.http"; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
4 local jid = require "util.jid"; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
5 local json = require "util.json"; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
6 local usermanager = require "core.usermanager"; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
7 local errors = require "util.error"; |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
8 local url = require "socket.url"; |
5243
d5dc8edb2695
mod_http_oauth2: Use more compact IDs
Kim Alvefur <zash@zash.se>
parents:
5242
diff
changeset
|
9 local id = require "util.id"; |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
10 local encodings = require "util.encodings"; |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
11 local base64 = encodings.base64; |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
12 local random = require "util.random"; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
13 local schema = require "util.jsonschema"; |
5209
942f8a2f722d
mod_http_oauth2: Allow non-HTTPS on localhost URLs
Matthew Wild <mwild1@gmail.com>
parents:
5208
diff
changeset
|
14 local set = require "util.set"; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
15 local jwt = require"util.jwt"; |
5203
c60cff787d6a
mod_http_oauth2: Return actually enabled response types in discovery
Kim Alvefur <zash@zash.se>
parents:
5202
diff
changeset
|
16 local it = require "util.iterators"; |
c60cff787d6a
mod_http_oauth2: Return actually enabled response types in discovery
Kim Alvefur <zash@zash.se>
parents:
5202
diff
changeset
|
17 local array = require "util.array"; |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
18 local st = require "util.stanza"; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
19 |
5383
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
20 local function b64url(s) |
5392
c0a6f39caf47
mod_http_oauth2: Fix missing base64 part of base64url (Thanks KeyCloak)
Kim Alvefur <zash@zash.se>
parents:
5391
diff
changeset
|
21 return (base64.encode(s):gsub("[+/=]", { ["+"] = "-", ["/"] = "_", ["="] = "" })) |
5383
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
22 end |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
23 |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
24 local function read_file(base_path, fn, required) |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
25 local f, err = io.open(base_path .. "/" .. fn); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
26 if not f then |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
27 module:log(required and "error" or "debug", "Unable to load template file: %s", err); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
28 if required then |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
29 return error("Failed to load templates"); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
30 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
31 return nil; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
32 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
33 local data = assert(f:read("*a")); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
34 assert(f:close()); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
35 return data; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
36 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
37 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
38 local template_path = module:get_option_path("oauth2_template_path", "html"); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
39 local templates = { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
40 login = read_file(template_path, "login.html", true); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
41 consent = read_file(template_path, "consent.html", true); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
42 error = read_file(template_path, "error.html", true); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
43 css = read_file(template_path, "style.css"); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
44 js = read_file(template_path, "script.js"); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
45 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
46 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
47 local site_name = module:get_option_string("site_name", module.host); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
48 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
49 local _render_html = require"util.interpolation".new("%b{}", st.xml_escape); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
50 local function render_page(template, data, sensitive) |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
51 data = data or {}; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
52 data.site_name = site_name; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
53 local resp = { |
5218
1f4b768c831a
mod_http_oauth2: Correct field name for HTTP response status code
Kim Alvefur <zash@zash.se>
parents:
5217
diff
changeset
|
54 status_code = 200; |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
55 headers = { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
56 ["Content-Type"] = "text/html; charset=utf-8"; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
57 ["Content-Security-Policy"] = "default-src 'self'"; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
58 ["X-Frame-Options"] = "DENY"; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
59 ["Cache-Control"] = (sensitive and "no-store" or "no-cache")..", private"; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
60 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
61 body = _render_html(template, data); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
62 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
63 return resp; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
64 end |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
65 |
3915
80dffbbd056b
mod_rest, mod_http_oauth2: Switch from mod_authtokens to mod_tokenauth per Prosody bf81523e2ff4
Matthew Wild <mwild1@gmail.com>
parents:
3908
diff
changeset
|
66 local tokens = module:depends("tokenauth"); |
3908
8ac5d9933106
mod_http_oauth2: Implement real tokens using mod_authtokens
Matthew Wild <mwild1@gmail.com>
parents:
3903
diff
changeset
|
67 |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
68 local default_access_ttl = module:get_option_number("oauth2_access_token_ttl", 86400); |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
69 local default_refresh_ttl = module:get_option_number("oauth2_refresh_token_ttl", nil); |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
70 |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
71 -- Used to derive client_secret from client_id, set to enable stateless dynamic registration. |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
72 local registration_key = module:get_option_string("oauth2_registration_key"); |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
73 local registration_algo = module:get_option_string("oauth2_registration_algorithm", "HS256"); |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
74 local registration_options = module:get_option("oauth2_registration_options", { default_ttl = 60 * 60 * 24 * 90 }); |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
75 |
5383
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
76 local pkce_required = module:get_option_boolean("oauth2_require_code_challenge", false); |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
77 |
5199
f48628dc83f1
mod_http_oauth2: Separate client_secret verification key from JWT key
Kim Alvefur <zash@zash.se>
parents:
5198
diff
changeset
|
78 local verification_key; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
79 local jwt_sign, jwt_verify; |
5196
6b63af56c8ac
mod_http_oauth2: Remove error message
Kim Alvefur <zash@zash.se>
parents:
5195
diff
changeset
|
80 if registration_key then |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
81 -- Tie it to the host if global |
5199
f48628dc83f1
mod_http_oauth2: Separate client_secret verification key from JWT key
Kim Alvefur <zash@zash.se>
parents:
5198
diff
changeset
|
82 verification_key = hashes.hmac_sha256(registration_key, module.host); |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
83 jwt_sign, jwt_verify = jwt.init(registration_algo, registration_key, registration_key, registration_options); |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
84 end |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
85 |
5254
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
86 local function parse_scopes(scope_string) |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
87 return array(scope_string:gmatch("%S+")); |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
88 end |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
89 |
5375
8b7d97f0ae8a
mod_http_oauth2: Fix to include "openid" scope in discovery metadata
Kim Alvefur <zash@zash.se>
parents:
5367
diff
changeset
|
90 local openid_claims = set.new({ "openid", "profile"; "email"; "address"; "phone" }); |
5337
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
91 |
5256
44f7edd4f845
mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents:
5255
diff
changeset
|
92 local function filter_scopes(username, requested_scope_string) |
5254
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
93 local selected_role, granted_scopes = nil, array(); |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
94 |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
95 if requested_scope_string then -- Specific role(s) requested |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
96 local requested_scopes = parse_scopes(requested_scope_string); |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
97 for _, scope in ipairs(requested_scopes) do |
5375
8b7d97f0ae8a
mod_http_oauth2: Fix to include "openid" scope in discovery metadata
Kim Alvefur <zash@zash.se>
parents:
5367
diff
changeset
|
98 if openid_claims:contains(scope) then |
5255
001c8fdc91a4
mod_http_oauth2: Add support for the "openid" scope
Kim Alvefur <zash@zash.se>
parents:
5254
diff
changeset
|
99 granted_scopes:push(scope); |
001c8fdc91a4
mod_http_oauth2: Add support for the "openid" scope
Kim Alvefur <zash@zash.se>
parents:
5254
diff
changeset
|
100 end |
5254
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
101 if selected_role == nil and usermanager.user_can_assume_role(username, module.host, scope) then |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
102 selected_role = scope; |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
103 end |
4998
5ab134b7e510
mod_http_oauth2: Updates for Prosody's new role API (backwards-compatible)
Matthew Wild <mwild1@gmail.com>
parents:
4670
diff
changeset
|
104 end |
5ab134b7e510
mod_http_oauth2: Updates for Prosody's new role API (backwards-compatible)
Matthew Wild <mwild1@gmail.com>
parents:
4670
diff
changeset
|
105 end |
5ab134b7e510
mod_http_oauth2: Updates for Prosody's new role API (backwards-compatible)
Matthew Wild <mwild1@gmail.com>
parents:
4670
diff
changeset
|
106 |
5254
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
107 if not selected_role then |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
108 -- By default use the users' default role |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
109 selected_role = usermanager.get_user_role(username, module.host).name; |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
110 end |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
111 granted_scopes:push(selected_role); |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
112 |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
113 return granted_scopes:concat(" "), selected_role; |
4340
7cd3b7ec59e9
mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents:
4276
diff
changeset
|
114 end |
7cd3b7ec59e9
mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents:
4276
diff
changeset
|
115 |
5213
dc0f502c12f1
mod_http_oauth2: Fix authorization code logic
Kim Alvefur <zash@zash.se>
parents:
5210
diff
changeset
|
116 local function code_expires_in(code) --> number, seconds until code expires |
dc0f502c12f1
mod_http_oauth2: Fix authorization code logic
Kim Alvefur <zash@zash.se>
parents:
5210
diff
changeset
|
117 return os.difftime(code.expires, os.time()); |
4669
d3434fd151b5
mod_http_oauth2: Optimize cleanup timer
Kim Alvefur <zash@zash.se>
parents:
4370
diff
changeset
|
118 end |
d3434fd151b5
mod_http_oauth2: Optimize cleanup timer
Kim Alvefur <zash@zash.se>
parents:
4370
diff
changeset
|
119 |
5213
dc0f502c12f1
mod_http_oauth2: Fix authorization code logic
Kim Alvefur <zash@zash.se>
parents:
5210
diff
changeset
|
120 local function code_expired(code) --> boolean, true: has expired, false: still valid |
dc0f502c12f1
mod_http_oauth2: Fix authorization code logic
Kim Alvefur <zash@zash.se>
parents:
5210
diff
changeset
|
121 return code_expires_in(code) < 0; |
4269
143515d0b212
mod_http_oauth2: Factor out authorization code validity decision
Kim Alvefur <zash@zash.se>
parents:
4265
diff
changeset
|
122 end |
143515d0b212
mod_http_oauth2: Factor out authorization code validity decision
Kim Alvefur <zash@zash.se>
parents:
4265
diff
changeset
|
123 |
4271
9623b99bb8d2
mod_http_oauth2: Keep authorization codes in memory instead of storage
Kim Alvefur <zash@zash.se>
parents:
4270
diff
changeset
|
124 local codes = cache.new(10000, function (_, code) |
9623b99bb8d2
mod_http_oauth2: Keep authorization codes in memory instead of storage
Kim Alvefur <zash@zash.se>
parents:
4270
diff
changeset
|
125 return code_expired(code) |
9623b99bb8d2
mod_http_oauth2: Keep authorization codes in memory instead of storage
Kim Alvefur <zash@zash.se>
parents:
4270
diff
changeset
|
126 end); |
9623b99bb8d2
mod_http_oauth2: Keep authorization codes in memory instead of storage
Kim Alvefur <zash@zash.se>
parents:
4270
diff
changeset
|
127 |
5213
dc0f502c12f1
mod_http_oauth2: Fix authorization code logic
Kim Alvefur <zash@zash.se>
parents:
5210
diff
changeset
|
128 -- Periodically clear out unredeemed codes. Does not need to be exact, expired |
dc0f502c12f1
mod_http_oauth2: Fix authorization code logic
Kim Alvefur <zash@zash.se>
parents:
5210
diff
changeset
|
129 -- codes are rejected if tried. Mostly just to keep memory usage in check. |
5354
39d59d857bfb
mod_http_oauth2: Use new mod_cron API for periodic cleanup
Kim Alvefur <zash@zash.se>
parents:
5341
diff
changeset
|
130 module:hourly("Clear expired authorization codes", function() |
4272
91b951fb3018
mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents:
4271
diff
changeset
|
131 local k, code = codes:tail(); |
91b951fb3018
mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents:
4271
diff
changeset
|
132 while code and code_expired(code) do |
91b951fb3018
mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents:
4271
diff
changeset
|
133 codes:set(k, nil); |
91b951fb3018
mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents:
4271
diff
changeset
|
134 k, code = codes:tail(); |
91b951fb3018
mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents:
4271
diff
changeset
|
135 end |
91b951fb3018
mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents:
4271
diff
changeset
|
136 end) |
91b951fb3018
mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents:
4271
diff
changeset
|
137 |
5207
c72e3b0914e8
mod_http_oauth: Factor out issuer URL calculation to a helper function
Matthew Wild <mwild1@gmail.com>
parents:
5206
diff
changeset
|
138 local function get_issuer() |
c72e3b0914e8
mod_http_oauth: Factor out issuer URL calculation to a helper function
Matthew Wild <mwild1@gmail.com>
parents:
5206
diff
changeset
|
139 return (module:http_url(nil, "/"):gsub("/$", "")); |
c72e3b0914e8
mod_http_oauth: Factor out issuer URL calculation to a helper function
Matthew Wild <mwild1@gmail.com>
parents:
5206
diff
changeset
|
140 end |
c72e3b0914e8
mod_http_oauth: Factor out issuer URL calculation to a helper function
Matthew Wild <mwild1@gmail.com>
parents:
5206
diff
changeset
|
141 |
5209
942f8a2f722d
mod_http_oauth2: Allow non-HTTPS on localhost URLs
Matthew Wild <mwild1@gmail.com>
parents:
5208
diff
changeset
|
142 local loopbacks = set.new({ "localhost", "127.0.0.1", "::1" }); |
942f8a2f722d
mod_http_oauth2: Allow non-HTTPS on localhost URLs
Matthew Wild <mwild1@gmail.com>
parents:
5208
diff
changeset
|
143 local function is_secure_redirect(uri) |
942f8a2f722d
mod_http_oauth2: Allow non-HTTPS on localhost URLs
Matthew Wild <mwild1@gmail.com>
parents:
5208
diff
changeset
|
144 local u = url.parse(uri); |
942f8a2f722d
mod_http_oauth2: Allow non-HTTPS on localhost URLs
Matthew Wild <mwild1@gmail.com>
parents:
5208
diff
changeset
|
145 return u.scheme ~= "http" or loopbacks:contains(u.host); |
942f8a2f722d
mod_http_oauth2: Allow non-HTTPS on localhost URLs
Matthew Wild <mwild1@gmail.com>
parents:
5208
diff
changeset
|
146 end |
942f8a2f722d
mod_http_oauth2: Allow non-HTTPS on localhost URLs
Matthew Wild <mwild1@gmail.com>
parents:
5208
diff
changeset
|
147 |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
148 local function oauth_error(err_name, err_desc) |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
149 return errors.new({ |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
150 type = "modify"; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
151 condition = "bad-request"; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
152 code = err_name == "invalid_client" and 401 or 400; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
153 text = err_desc and (err_name..": "..err_desc) or err_name; |
4276
ec33b3b1136c
mod_http_oauth2: Fix passing OAuth-specific error details
Kim Alvefur <zash@zash.se>
parents:
4272
diff
changeset
|
154 extra = { oauth2_response = { error = err_name, error_description = err_desc } }; |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
155 }); |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
156 end |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
157 |
5248
b8b2bf0c1b4b
mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents:
5247
diff
changeset
|
158 -- client_id / client_metadata are pretty large, filter out a subset of |
b8b2bf0c1b4b
mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents:
5247
diff
changeset
|
159 -- properties that are deemed useful e.g. in case tokens issued to a certain |
b8b2bf0c1b4b
mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents:
5247
diff
changeset
|
160 -- client needs to be revoked |
b8b2bf0c1b4b
mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents:
5247
diff
changeset
|
161 local function client_subset(client) |
5378
6155c46d9eea
mod_http_oauth2: Record OAuth software id and version attached to tokens
Kim Alvefur <zash@zash.se>
parents:
5377
diff
changeset
|
162 return { name = client.client_name; uri = client.client_uri; id = client.software_id; version = client.software_version }; |
5248
b8b2bf0c1b4b
mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents:
5247
diff
changeset
|
163 end |
b8b2bf0c1b4b
mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents:
5247
diff
changeset
|
164 |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
165 local function new_access_token(token_jid, role, scope_string, client, id_token, refresh_token_info) |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
166 local token_data = { oauth2_scopes = scope_string, oauth2_client = nil }; |
5248
b8b2bf0c1b4b
mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents:
5247
diff
changeset
|
167 if client then |
5254
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
168 token_data.oauth2_client = client_subset(client); |
5248
b8b2bf0c1b4b
mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents:
5247
diff
changeset
|
169 end |
5254
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
170 if next(token_data) == nil then |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
171 token_data = nil; |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
172 end |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
173 |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
174 local refresh_token; |
5280
eb482defd9b0
mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents:
5279
diff
changeset
|
175 local grant = refresh_token_info and refresh_token_info.grant; |
eb482defd9b0
mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents:
5279
diff
changeset
|
176 if not grant then |
eb482defd9b0
mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents:
5279
diff
changeset
|
177 -- No existing grant, create one |
eb482defd9b0
mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents:
5279
diff
changeset
|
178 grant = tokens.create_grant(token_jid, token_jid, default_refresh_ttl, token_data); |
eb482defd9b0
mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents:
5279
diff
changeset
|
179 -- Create refresh token for the grant if desired |
eb482defd9b0
mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents:
5279
diff
changeset
|
180 refresh_token = refresh_token_info ~= false and tokens.create_token(token_jid, grant, nil, nil, "oauth2-refresh"); |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
181 else |
5280
eb482defd9b0
mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents:
5279
diff
changeset
|
182 -- Grant exists, reuse existing refresh token |
eb482defd9b0
mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents:
5279
diff
changeset
|
183 refresh_token = refresh_token_info.token; |
5341
dcb93ffe64ae
mod_http_oauth2: Fix error due to reference loop when using refresh token
Kim Alvefur <zash@zash.se>
parents:
5340
diff
changeset
|
184 |
dcb93ffe64ae
mod_http_oauth2: Fix error due to reference loop when using refresh token
Kim Alvefur <zash@zash.se>
parents:
5340
diff
changeset
|
185 refresh_token_info.grant = nil; -- Prevent reference loop |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
186 end |
5280
eb482defd9b0
mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents:
5279
diff
changeset
|
187 |
eb482defd9b0
mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents:
5279
diff
changeset
|
188 local access_token, access_token_info = tokens.create_token(token_jid, grant, role, default_access_ttl, "oauth2"); |
eb482defd9b0
mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents:
5279
diff
changeset
|
189 |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
190 local expires_at = access_token_info.expires; |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
191 return { |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
192 token_type = "bearer"; |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
193 access_token = access_token; |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
194 expires_in = expires_at and (expires_at - os.time()) or nil; |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
195 scope = scope_string; |
5257
b2120fb4a279
mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents:
5256
diff
changeset
|
196 id_token = id_token; |
5280
eb482defd9b0
mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents:
5279
diff
changeset
|
197 refresh_token = refresh_token or nil; |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
198 }; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
199 end |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
200 |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
201 local function get_redirect_uri(client, query_redirect_uri) -- record client, string : string |
5219
25e824f64fd3
mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents:
5218
diff
changeset
|
202 if not query_redirect_uri then |
25e824f64fd3
mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents:
5218
diff
changeset
|
203 if #client.redirect_uris ~= 1 then |
25e824f64fd3
mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents:
5218
diff
changeset
|
204 -- Client registered multiple URIs, it needs specify which one to use |
25e824f64fd3
mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents:
5218
diff
changeset
|
205 return; |
25e824f64fd3
mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents:
5218
diff
changeset
|
206 end |
25e824f64fd3
mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents:
5218
diff
changeset
|
207 -- When only a single URI is registered, that's the default |
25e824f64fd3
mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents:
5218
diff
changeset
|
208 return client.redirect_uris[1]; |
25e824f64fd3
mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents:
5218
diff
changeset
|
209 end |
25e824f64fd3
mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents:
5218
diff
changeset
|
210 -- Verify the client-provided URI matches one previously registered |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
211 for _, redirect_uri in ipairs(client.redirect_uris) do |
5219
25e824f64fd3
mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents:
5218
diff
changeset
|
212 if query_redirect_uri == redirect_uri then |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
213 return redirect_uri |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
214 end |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
215 end |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
216 end |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
217 |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
218 local grant_type_handlers = {}; |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
219 local response_type_handlers = {}; |
5383
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
220 local verifier_transforms = {}; |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
221 |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
222 function grant_type_handlers.password(params) |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
223 local request_jid = assert(params.username, oauth_error("invalid_request", "missing 'username' (JID)")); |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
224 local request_password = assert(params.password, oauth_error("invalid_request", "missing 'password'")); |
3919
8ed261a08a9c
mod_http_oauth2: Allow creation of full JID tokens
Kim Alvefur <zash@zash.se>
parents:
3918
diff
changeset
|
225 local request_username, request_host, request_resource = jid.prepped_split(request_jid); |
4340
7cd3b7ec59e9
mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents:
4276
diff
changeset
|
226 |
3908
8ac5d9933106
mod_http_oauth2: Implement real tokens using mod_authtokens
Matthew Wild <mwild1@gmail.com>
parents:
3903
diff
changeset
|
227 if not (request_username and request_host) or request_host ~= module.host then |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
228 return oauth_error("invalid_request", "invalid JID"); |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
229 end |
4340
7cd3b7ec59e9
mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents:
4276
diff
changeset
|
230 if not usermanager.test_password(request_username, request_host, request_password) then |
7cd3b7ec59e9
mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents:
4276
diff
changeset
|
231 return oauth_error("invalid_grant", "incorrect credentials"); |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
232 end |
4340
7cd3b7ec59e9
mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents:
4276
diff
changeset
|
233 |
7cd3b7ec59e9
mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents:
4276
diff
changeset
|
234 local granted_jid = jid.join(request_username, request_host, request_resource); |
5256
44f7edd4f845
mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents:
5255
diff
changeset
|
235 local granted_scopes, granted_role = filter_scopes(request_username, params.scope); |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
236 return json.encode(new_access_token(granted_jid, granted_role, granted_scopes, nil)); |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
237 end |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
238 |
5257
b2120fb4a279
mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents:
5256
diff
changeset
|
239 function response_type_handlers.code(client, params, granted_jid, id_token) |
5191
f5a58cbe86e4
mod_http_oauth2: Derive scope from correct user details
Kim Alvefur <zash@zash.se>
parents:
5190
diff
changeset
|
240 local request_username, request_host = jid.split(granted_jid); |
5256
44f7edd4f845
mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents:
5255
diff
changeset
|
241 if not request_host or request_host ~= module.host then |
44f7edd4f845
mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents:
5255
diff
changeset
|
242 return oauth_error("invalid_request", "invalid JID"); |
44f7edd4f845
mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents:
5255
diff
changeset
|
243 end |
44f7edd4f845
mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents:
5255
diff
changeset
|
244 local granted_scopes, granted_role = filter_scopes(request_username, params.scope); |
4340
7cd3b7ec59e9
mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents:
4276
diff
changeset
|
245 |
5383
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
246 if pkce_required and not params.code_challenge then |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
247 return oauth_error("invalid_request", "PKCE required"); |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
248 end |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
249 |
5243
d5dc8edb2695
mod_http_oauth2: Use more compact IDs
Kim Alvefur <zash@zash.se>
parents:
5242
diff
changeset
|
250 local code = id.medium(); |
4670
1b81b7269858
mod_http_oauth2: Gracefully handle cache write failure
Kim Alvefur <zash@zash.se>
parents:
4669
diff
changeset
|
251 local ok = codes:set(params.client_id .. "#" .. code, { |
5213
dc0f502c12f1
mod_http_oauth2: Fix authorization code logic
Kim Alvefur <zash@zash.se>
parents:
5210
diff
changeset
|
252 expires = os.time() + 600; |
4340
7cd3b7ec59e9
mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents:
4276
diff
changeset
|
253 granted_jid = granted_jid; |
7cd3b7ec59e9
mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents:
4276
diff
changeset
|
254 granted_scopes = granted_scopes; |
5254
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
255 granted_role = granted_role; |
5383
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
256 challenge = params.code_challenge; |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
257 challenge_method = params.code_challenge_method; |
5257
b2120fb4a279
mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents:
5256
diff
changeset
|
258 id_token = id_token; |
4670
1b81b7269858
mod_http_oauth2: Gracefully handle cache write failure
Kim Alvefur <zash@zash.se>
parents:
4669
diff
changeset
|
259 }); |
1b81b7269858
mod_http_oauth2: Gracefully handle cache write failure
Kim Alvefur <zash@zash.se>
parents:
4669
diff
changeset
|
260 if not ok then |
1b81b7269858
mod_http_oauth2: Gracefully handle cache write failure
Kim Alvefur <zash@zash.se>
parents:
4669
diff
changeset
|
261 return {status_code = 429}; |
1b81b7269858
mod_http_oauth2: Gracefully handle cache write failure
Kim Alvefur <zash@zash.se>
parents:
4669
diff
changeset
|
262 end |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
263 |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
264 local redirect_uri = get_redirect_uri(client, params.redirect_uri); |
5188
7c531137a553
mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents:
5187
diff
changeset
|
265 if redirect_uri == "urn:ietf:wg:oauth:2.0:oob" then |
7c531137a553
mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents:
5187
diff
changeset
|
266 -- TODO some nicer template page |
5206
31c62df82aa8
mod_http_oauth2: Clarify comment referencing mod_http_errors (thanks MattJ)
Kim Alvefur <zash@zash.se>
parents:
5205
diff
changeset
|
267 -- mod_http_errors will set content-type to text/html if it catches this |
31c62df82aa8
mod_http_oauth2: Clarify comment referencing mod_http_errors (thanks MattJ)
Kim Alvefur <zash@zash.se>
parents:
5205
diff
changeset
|
268 -- event, if not text/plain is kept for the fallback text. |
5188
7c531137a553
mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents:
5187
diff
changeset
|
269 local response = { status_code = 200; headers = { content_type = "text/plain" } } |
7c531137a553
mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents:
5187
diff
changeset
|
270 response.body = module:context("*"):fire_event("http-message", { |
7c531137a553
mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents:
5187
diff
changeset
|
271 response = response; |
7c531137a553
mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents:
5187
diff
changeset
|
272 title = "Your authorization code"; |
5195
b4932915e773
mod_http_oauth2: Mention name of client when giving out OOB authorization code
Kim Alvefur <zash@zash.se>
parents:
5194
diff
changeset
|
273 message = "Here's your authorization code, copy and paste it into " .. (client.client_name or "your client"); |
5188
7c531137a553
mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents:
5187
diff
changeset
|
274 extra = code; |
7c531137a553
mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents:
5187
diff
changeset
|
275 }) or ("Here's your authorization code:\n%s\n"):format(code); |
5190
1733f184e2bb
mod_http_oauth2: Fix to actually return OOB response
Kim Alvefur <zash@zash.se>
parents:
5189
diff
changeset
|
276 return response; |
5219
25e824f64fd3
mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents:
5218
diff
changeset
|
277 elseif not redirect_uri then |
5247
dc27b997e969
mod_http_oauth2: Invoke mod_http_errors to render error on invalid redirect
Kim Alvefur <zash@zash.se>
parents:
5246
diff
changeset
|
278 return 400; |
5188
7c531137a553
mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents:
5187
diff
changeset
|
279 end |
7c531137a553
mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents:
5187
diff
changeset
|
280 |
7c531137a553
mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents:
5187
diff
changeset
|
281 local redirect = url.parse(redirect_uri); |
7c531137a553
mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents:
5187
diff
changeset
|
282 |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
283 local query = http.formdecode(redirect.query or ""); |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
284 if type(query) ~= "table" then query = {}; end |
5192
03aa9baa9ac3
mod_http_oauth2: Add support for 'iss' authz response parameter (RFC 9207)
Matthew Wild <mwild1@gmail.com>
parents:
5191
diff
changeset
|
285 table.insert(query, { name = "code", value = code }); |
5207
c72e3b0914e8
mod_http_oauth: Factor out issuer URL calculation to a helper function
Matthew Wild <mwild1@gmail.com>
parents:
5206
diff
changeset
|
286 table.insert(query, { name = "iss", value = get_issuer() }); |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
287 if params.state then |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
288 table.insert(query, { name = "state", value = params.state }); |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
289 end |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
290 redirect.query = http.formencode(query); |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
291 |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
292 return { |
5210
898575a0c6f3
mod_http_oauth2: Switch to '303 See Other' redirects
Matthew Wild <mwild1@gmail.com>
parents:
5209
diff
changeset
|
293 status_code = 303; |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
294 headers = { |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
295 location = url.build(redirect); |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
296 }; |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
297 } |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
298 end |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
299 |
5186
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
300 -- Implicit flow |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
301 function response_type_handlers.token(client, params, granted_jid) |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
302 local request_username, request_host = jid.split(granted_jid); |
5256
44f7edd4f845
mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents:
5255
diff
changeset
|
303 if not request_host or request_host ~= module.host then |
44f7edd4f845
mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents:
5255
diff
changeset
|
304 return oauth_error("invalid_request", "invalid JID"); |
44f7edd4f845
mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents:
5255
diff
changeset
|
305 end |
44f7edd4f845
mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents:
5255
diff
changeset
|
306 local granted_scopes, granted_role = filter_scopes(request_username, params.scope); |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
307 local token_info = new_access_token(granted_jid, granted_role, granted_scopes, client, nil); |
5186
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
308 |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
309 local redirect = url.parse(get_redirect_uri(client, params.redirect_uri)); |
5186
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
310 token_info.state = params.state; |
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
311 redirect.fragment = http.formencode(token_info); |
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
312 |
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
313 return { |
5210
898575a0c6f3
mod_http_oauth2: Switch to '303 See Other' redirects
Matthew Wild <mwild1@gmail.com>
parents:
5209
diff
changeset
|
314 status_code = 303; |
5186
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
315 headers = { |
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
316 location = url.build(redirect); |
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
317 }; |
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
318 } |
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
319 end |
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
320 |
5262
e73f364b5624
mod_http_oauth2: Rename oauth client credential related functions
Kim Alvefur <zash@zash.se>
parents:
5259
diff
changeset
|
321 local function make_client_secret(client_id) --> client_secret |
5199
f48628dc83f1
mod_http_oauth2: Separate client_secret verification key from JWT key
Kim Alvefur <zash@zash.se>
parents:
5198
diff
changeset
|
322 return hashes.hmac_sha256(verification_key, client_id, true); |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
323 end |
4263
d3af5f94d6df
mod_http_oauth2: Improve storage of client secret
Kim Alvefur <zash@zash.se>
parents:
4260
diff
changeset
|
324 |
5262
e73f364b5624
mod_http_oauth2: Rename oauth client credential related functions
Kim Alvefur <zash@zash.se>
parents:
5259
diff
changeset
|
325 local function verify_client_secret(client_id, client_secret) |
e73f364b5624
mod_http_oauth2: Rename oauth client credential related functions
Kim Alvefur <zash@zash.se>
parents:
5259
diff
changeset
|
326 return hashes.equals(make_client_secret(client_id), client_secret); |
4263
d3af5f94d6df
mod_http_oauth2: Improve storage of client secret
Kim Alvefur <zash@zash.se>
parents:
4260
diff
changeset
|
327 end |
d3af5f94d6df
mod_http_oauth2: Improve storage of client secret
Kim Alvefur <zash@zash.se>
parents:
4260
diff
changeset
|
328 |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
329 function grant_type_handlers.authorization_code(params) |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
330 if not params.client_id then return oauth_error("invalid_request", "missing 'client_id'"); end |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
331 if not params.client_secret then return oauth_error("invalid_request", "missing 'client_secret'"); end |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
332 if not params.code then return oauth_error("invalid_request", "missing 'code'"); end |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
333 if params.scope and params.scope ~= "" then |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
334 return oauth_error("invalid_scope", "unknown scope requested"); |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
335 end |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
336 |
5252
85f0c6c1c24f
mod_http_oauth2: Fix attempt to index a boolean value
Kim Alvefur <zash@zash.se>
parents:
5248
diff
changeset
|
337 local client_ok, client = jwt_verify(params.client_id); |
85f0c6c1c24f
mod_http_oauth2: Fix attempt to index a boolean value
Kim Alvefur <zash@zash.se>
parents:
5248
diff
changeset
|
338 if not client_ok then |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
339 return oauth_error("invalid_client", "incorrect credentials"); |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
340 end |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
341 |
5262
e73f364b5624
mod_http_oauth2: Rename oauth client credential related functions
Kim Alvefur <zash@zash.se>
parents:
5259
diff
changeset
|
342 if not verify_client_secret(params.client_id, params.client_secret) then |
4260
c539334dd01a
mod_http_oauth2: Rescope oauth client config into users' storage
Kim Alvefur <zash@zash.se>
parents:
4259
diff
changeset
|
343 module:log("debug", "client_secret mismatch"); |
c539334dd01a
mod_http_oauth2: Rescope oauth client config into users' storage
Kim Alvefur <zash@zash.se>
parents:
4259
diff
changeset
|
344 return oauth_error("invalid_client", "incorrect credentials"); |
c539334dd01a
mod_http_oauth2: Rescope oauth client config into users' storage
Kim Alvefur <zash@zash.se>
parents:
4259
diff
changeset
|
345 end |
4271
9623b99bb8d2
mod_http_oauth2: Keep authorization codes in memory instead of storage
Kim Alvefur <zash@zash.se>
parents:
4270
diff
changeset
|
346 local code, err = codes:get(params.client_id .. "#" .. params.code); |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
347 if err then error(err); end |
5214
d5492bc861f6
mod_http_oauth2: Remove authorization codes after use
Kim Alvefur <zash@zash.se>
parents:
5213
diff
changeset
|
348 -- MUST NOT use the authorization code more than once, so remove it to |
d5492bc861f6
mod_http_oauth2: Remove authorization codes after use
Kim Alvefur <zash@zash.se>
parents:
5213
diff
changeset
|
349 -- prevent a second attempted use |
d5492bc861f6
mod_http_oauth2: Remove authorization codes after use
Kim Alvefur <zash@zash.se>
parents:
5213
diff
changeset
|
350 codes:set(params.client_id .. "#" .. params.code, nil); |
4269
143515d0b212
mod_http_oauth2: Factor out authorization code validity decision
Kim Alvefur <zash@zash.se>
parents:
4265
diff
changeset
|
351 if not code or type(code) ~= "table" or code_expired(code) then |
4260
c539334dd01a
mod_http_oauth2: Rescope oauth client config into users' storage
Kim Alvefur <zash@zash.se>
parents:
4259
diff
changeset
|
352 module:log("debug", "authorization_code invalid or expired: %q", code); |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
353 return oauth_error("invalid_client", "incorrect credentials"); |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
354 end |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
355 |
5383
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
356 -- TODO Decide if the code should be removed or not when PKCE fails |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
357 local transform = verifier_transforms[code.challenge_method or "plain"]; |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
358 if not transform then |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
359 return oauth_error("invalid_request", "unknown challenge transform method"); |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
360 elseif transform(params.code_verifier) ~= code.challenge then |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
361 return oauth_error("invalid_grant", "incorrect credentials"); |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
362 end |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
363 |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
364 return json.encode(new_access_token(code.granted_jid, code.granted_role, code.granted_scopes, client, code.id_token)); |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
365 end |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
366 |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
367 function grant_type_handlers.refresh_token(params) |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
368 if not params.client_id then return oauth_error("invalid_request", "missing 'client_id'"); end |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
369 if not params.client_secret then return oauth_error("invalid_request", "missing 'client_secret'"); end |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
370 if not params.refresh_token then return oauth_error("invalid_request", "missing 'refresh_token'"); end |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
371 |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
372 local client_ok, client = jwt_verify(params.client_id); |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
373 if not client_ok then |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
374 return oauth_error("invalid_client", "incorrect credentials"); |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
375 end |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
376 |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
377 if not verify_client_secret(params.client_id, params.client_secret) then |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
378 module:log("debug", "client_secret mismatch"); |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
379 return oauth_error("invalid_client", "incorrect credentials"); |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
380 end |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
381 |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
382 local refresh_token_info = tokens.get_token_info(params.refresh_token); |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
383 if not refresh_token_info or refresh_token_info.purpose ~= "oauth2-refresh" then |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
384 return oauth_error("invalid_grant", "invalid refresh token"); |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
385 end |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
386 |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
387 -- new_access_token() requires the actual token |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
388 refresh_token_info.token = params.refresh_token; |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
389 |
5280
eb482defd9b0
mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents:
5279
diff
changeset
|
390 return json.encode(new_access_token( |
5340
cd195283127f
mod_http_oauth2: Fix table index error when using refresh token
Kim Alvefur <zash@zash.se>
parents:
5337
diff
changeset
|
391 refresh_token_info.jid, refresh_token_info.role, refresh_token_info.grant.data.oauth2_scopes, client, nil, refresh_token_info |
5280
eb482defd9b0
mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents:
5279
diff
changeset
|
392 )); |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
393 end |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
394 |
5383
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
395 -- RFC 7636 Proof Key for Code Exchange by OAuth Public Clients |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
396 |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
397 function verifier_transforms.plain(code_verifier) |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
398 -- code_challenge = code_verifier |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
399 return code_verifier; |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
400 end |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
401 |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
402 function verifier_transforms.S256(code_verifier) |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
403 -- code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier))) |
5391
4aedce4fb95d
mod_http_oauth2: Fix accidental uppercase in invocation of hash function
Kim Alvefur <zash@zash.se>
parents:
5390
diff
changeset
|
404 return code_verifier and b64url(hashes.sha256(code_verifier)); |
5383
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
405 end |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
406 |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
407 -- Used to issue/verify short-lived tokens for the authorization process below |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
408 local new_user_token, verify_user_token = jwt.init("HS256", random.bytes(32), nil, { default_ttl = 600 }); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
409 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
410 -- From the given request, figure out if the user is authenticated and has granted consent yet |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
411 -- As this requires multiple steps (seek credentials, seek consent), we have a lot of state to |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
412 -- carry around across requests. We also need to protect against CSRF and session mix-up attacks |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
413 -- (e.g. the user may have multiple concurrent flows in progress, session cookies aren't unique |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
414 -- to one of them). |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
415 -- Our strategy here is to preserve the original query string (containing the authz request), and |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
416 -- encode the rest of the flow in form POSTs. |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
417 local function get_auth_state(request) |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
418 local form = request.method == "POST" |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
419 and request.body |
5276
67777cb7353d
mod_http_oauth2: Pedantic optimization
Kim Alvefur <zash@zash.se>
parents:
5273
diff
changeset
|
420 and request.body ~= "" |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
421 and request.headers.content_type == "application/x-www-form-urlencoded" |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
422 and http.formdecode(request.body); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
423 |
5277
a1055024b94e
mod_http_oauth2: Stricten check of urlencoded form data
Kim Alvefur <zash@zash.se>
parents:
5276
diff
changeset
|
424 if type(form) ~= "table" then return {}; end |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
425 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
426 if not form.user_token then |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
427 -- First step: login |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
428 local username = encodings.stringprep.nodeprep(form.username); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
429 local password = encodings.stringprep.saslprep(form.password); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
430 if not (username and password) or not usermanager.test_password(username, module.host, password) then |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
431 return { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
432 error = "Invalid username/password"; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
433 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
434 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
435 return { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
436 user = { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
437 username = username; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
438 host = module.host; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
439 token = new_user_token({ username = username, host = module.host }); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
440 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
441 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
442 elseif form.user_token and form.consent then |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
443 -- Second step: consent |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
444 local ok, user = verify_user_token(form.user_token); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
445 if not ok then |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
446 return { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
447 error = user == "token-expired" and "Session expired - try again" or nil; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
448 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
449 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
450 |
5271
3a1df3adad0c
mod_http_oauth2: Allow user to decide which requested scopes to grant
Kim Alvefur <zash@zash.se>
parents:
5268
diff
changeset
|
451 local scope = array():append(form):filter(function(field) |
3a1df3adad0c
mod_http_oauth2: Allow user to decide which requested scopes to grant
Kim Alvefur <zash@zash.se>
parents:
5268
diff
changeset
|
452 return field.name == "scope"; |
3a1df3adad0c
mod_http_oauth2: Allow user to decide which requested scopes to grant
Kim Alvefur <zash@zash.se>
parents:
5268
diff
changeset
|
453 end):pluck("value"):concat(" "); |
3a1df3adad0c
mod_http_oauth2: Allow user to decide which requested scopes to grant
Kim Alvefur <zash@zash.se>
parents:
5268
diff
changeset
|
454 |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
455 user.token = form.user_token; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
456 return { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
457 user = user; |
5271
3a1df3adad0c
mod_http_oauth2: Allow user to decide which requested scopes to grant
Kim Alvefur <zash@zash.se>
parents:
5268
diff
changeset
|
458 scope = scope; |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
459 consent = form.consent == "granted"; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
460 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
461 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
462 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
463 return {}; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
464 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
465 |
5222
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
466 local function get_request_credentials(request) |
5224
cd5cf4cc6304
mod_http_oauth2: Fail early when no authorization header present
Matthew Wild <mwild1@gmail.com>
parents:
5223
diff
changeset
|
467 if not request.headers.authorization then return; end |
cd5cf4cc6304
mod_http_oauth2: Fail early when no authorization header present
Matthew Wild <mwild1@gmail.com>
parents:
5223
diff
changeset
|
468 |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
469 local auth_type, auth_data = string.match(request.headers.authorization, "^(%S+)%s(.+)$"); |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
470 |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
471 if auth_type == "Basic" then |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
472 local creds = base64.decode(auth_data); |
5222
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
473 if not creds then return; end |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
474 local username, password = string.match(creds, "^([^:]+):(.*)$"); |
5222
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
475 if not username then return; end |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
476 return { |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
477 type = "basic"; |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
478 username = username; |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
479 password = password; |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
480 }; |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
481 elseif auth_type == "Bearer" then |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
482 return { |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
483 type = "bearer"; |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
484 bearer_token = auth_data; |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
485 }; |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
486 end |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
487 |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
488 return nil; |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
489 end |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
490 |
3920
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
491 if module:get_host_type() == "component" then |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
492 local component_secret = assert(module:get_option_string("component_secret"), "'component_secret' is a required setting when loaded on a Component"); |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
493 |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
494 function grant_type_handlers.password(params) |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
495 local request_jid = assert(params.username, oauth_error("invalid_request", "missing 'username' (JID)")); |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
496 local request_password = assert(params.password, oauth_error("invalid_request", "missing 'password'")); |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
497 local request_username, request_host, request_resource = jid.prepped_split(request_jid); |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
498 if params.scope then |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
499 return oauth_error("invalid_scope", "unknown scope requested"); |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
500 end |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
501 if not request_host or request_host ~= module.host then |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
502 return oauth_error("invalid_request", "invalid JID"); |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
503 end |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
504 if request_password == component_secret then |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
505 local granted_jid = jid.join(request_username, request_host, request_resource); |
5254
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
506 return json.encode(new_access_token(granted_jid, nil, nil, nil)); |
3920
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
507 end |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
508 return oauth_error("invalid_grant", "incorrect credentials"); |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
509 end |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
510 |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
511 -- TODO How would this make sense with components? |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
512 -- Have an admin authenticate maybe? |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
513 response_type_handlers.code = nil; |
5186
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
514 response_type_handlers.token = nil; |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
515 grant_type_handlers.authorization_code = nil; |
3920
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
516 end |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
517 |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
518 -- OAuth errors should be returned to the client if possible, i.e. by |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
519 -- appending the error information to the redirect_uri and sending the |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
520 -- redirect to the user-agent. In some cases we can't do this, e.g. if |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
521 -- the redirect_uri is missing or invalid. In those cases, we render an |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
522 -- error directly to the user-agent. |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
523 local function error_response(request, err) |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
524 local q = request.url.query and http.formdecode(request.url.query); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
525 local redirect_uri = q and q.redirect_uri; |
5217
6a27effb3ef0
mod_http_oauth2: Fix incorrect function name (thanks Zash/luacheck)
Matthew Wild <mwild1@gmail.com>
parents:
5214
diff
changeset
|
526 if not redirect_uri or not is_secure_redirect(redirect_uri) then |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
527 module:log("warn", "Missing or invalid redirect_uri <%s>, rendering error to user-agent", redirect_uri or ""); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
528 return render_page(templates.error, { error = err }); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
529 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
530 local redirect_query = url.parse(redirect_uri); |
5229
c24a622a7b85
mod_http_oauth2: Fix appending of query parts in error redirects
Kim Alvefur <zash@zash.se>
parents:
5228
diff
changeset
|
531 local sep = redirect_query.query and "&" or "?"; |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
532 redirect_uri = redirect_uri |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
533 .. sep .. http.formencode(err.extra.oauth2_response) |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
534 .. "&" .. http.formencode({ state = q.state, iss = get_issuer() }); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
535 module:log("warn", "Sending error response to client via redirect to %s", redirect_uri); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
536 return { |
5210
898575a0c6f3
mod_http_oauth2: Switch to '303 See Other' redirects
Matthew Wild <mwild1@gmail.com>
parents:
5209
diff
changeset
|
537 status_code = 303; |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
538 headers = { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
539 location = redirect_uri; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
540 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
541 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
542 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
543 |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
544 local allowed_grant_type_handlers = module:get_option_set("allowed_oauth2_grant_types", {"authorization_code", "password", "refresh_token"}) |
5187
6a3c1febd7be
mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents:
5186
diff
changeset
|
545 for handler_type in pairs(grant_type_handlers) do |
6a3c1febd7be
mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents:
5186
diff
changeset
|
546 if not allowed_grant_type_handlers:contains(handler_type) then |
5230
ac252db71027
mod_http_oauth2: Log flows enabled and disabled
Kim Alvefur <zash@zash.se>
parents:
5229
diff
changeset
|
547 module:log("debug", "Grant type %q disabled", handler_type); |
5187
6a3c1febd7be
mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents:
5186
diff
changeset
|
548 grant_type_handlers[handler_type] = nil; |
5230
ac252db71027
mod_http_oauth2: Log flows enabled and disabled
Kim Alvefur <zash@zash.se>
parents:
5229
diff
changeset
|
549 else |
ac252db71027
mod_http_oauth2: Log flows enabled and disabled
Kim Alvefur <zash@zash.se>
parents:
5229
diff
changeset
|
550 module:log("debug", "Grant type %q enabled", handler_type); |
5187
6a3c1febd7be
mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents:
5186
diff
changeset
|
551 end |
6a3c1febd7be
mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents:
5186
diff
changeset
|
552 end |
6a3c1febd7be
mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents:
5186
diff
changeset
|
553 |
6a3c1febd7be
mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents:
5186
diff
changeset
|
554 -- "token" aka implicit flow is considered insecure |
6a3c1febd7be
mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents:
5186
diff
changeset
|
555 local allowed_response_type_handlers = module:get_option_set("allowed_oauth2_response_types", {"code"}) |
5198
2e8a7a0f932d
mod_http_oauth2: Fix response type config
Kim Alvefur <zash@zash.se>
parents:
5196
diff
changeset
|
556 for handler_type in pairs(response_type_handlers) do |
2e8a7a0f932d
mod_http_oauth2: Fix response type config
Kim Alvefur <zash@zash.se>
parents:
5196
diff
changeset
|
557 if not allowed_response_type_handlers:contains(handler_type) then |
5230
ac252db71027
mod_http_oauth2: Log flows enabled and disabled
Kim Alvefur <zash@zash.se>
parents:
5229
diff
changeset
|
558 module:log("debug", "Response type %q disabled", handler_type); |
5231
bef543068077
mod_http_oauth2: Fix to disable disabled response handlers correctly
Kim Alvefur <zash@zash.se>
parents:
5230
diff
changeset
|
559 response_type_handlers[handler_type] = nil; |
5230
ac252db71027
mod_http_oauth2: Log flows enabled and disabled
Kim Alvefur <zash@zash.se>
parents:
5229
diff
changeset
|
560 else |
ac252db71027
mod_http_oauth2: Log flows enabled and disabled
Kim Alvefur <zash@zash.se>
parents:
5229
diff
changeset
|
561 module:log("debug", "Response type %q enabled", handler_type); |
5187
6a3c1febd7be
mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents:
5186
diff
changeset
|
562 end |
6a3c1febd7be
mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents:
5186
diff
changeset
|
563 end |
6a3c1febd7be
mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents:
5186
diff
changeset
|
564 |
5384
b40f29ec391a
mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents:
5383
diff
changeset
|
565 local allowed_challenge_methods = module:get_option_set("allowed_oauth2_code_challenge_methods", { "plain"; "S256" }) |
b40f29ec391a
mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents:
5383
diff
changeset
|
566 for handler_type in pairs(verifier_transforms) do |
b40f29ec391a
mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents:
5383
diff
changeset
|
567 if not allowed_challenge_methods:contains(handler_type) then |
b40f29ec391a
mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents:
5383
diff
changeset
|
568 module:log("debug", "Challenge method %q disabled", handler_type); |
b40f29ec391a
mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents:
5383
diff
changeset
|
569 verifier_transforms[handler_type] = nil; |
b40f29ec391a
mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents:
5383
diff
changeset
|
570 else |
b40f29ec391a
mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents:
5383
diff
changeset
|
571 module:log("debug", "Challenge method %q enabled", handler_type); |
b40f29ec391a
mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents:
5383
diff
changeset
|
572 end |
b40f29ec391a
mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents:
5383
diff
changeset
|
573 end |
b40f29ec391a
mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents:
5383
diff
changeset
|
574 |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
575 function handle_token_grant(event) |
5223
8b2a36847912
mod_http_oauth2: Support HTTP Basic auth on token endpoint
Matthew Wild <mwild1@gmail.com>
parents:
5222
diff
changeset
|
576 local credentials = get_request_credentials(event.request); |
8b2a36847912
mod_http_oauth2: Support HTTP Basic auth on token endpoint
Matthew Wild <mwild1@gmail.com>
parents:
5222
diff
changeset
|
577 |
3934
469408682152
mod_http_oauth2: Set content type on successful repsponses (fixes #1501)
Kim Alvefur <zash@zash.se>
parents:
3920
diff
changeset
|
578 event.response.headers.content_type = "application/json"; |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
579 local params = http.formdecode(event.request.body); |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
580 if not params then |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
581 return error_response(event.request, oauth_error("invalid_request")); |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
582 end |
5223
8b2a36847912
mod_http_oauth2: Support HTTP Basic auth on token endpoint
Matthew Wild <mwild1@gmail.com>
parents:
5222
diff
changeset
|
583 |
5225
3439eb37f23b
mod_http_oauth2: token endpoint: handle missing credentials
Matthew Wild <mwild1@gmail.com>
parents:
5224
diff
changeset
|
584 if credentials and credentials.type == "basic" then |
5385
544b92750a2a
mod_http_oauth2: Advertise supported token endpoint auth methods
Kim Alvefur <zash@zash.se>
parents:
5384
diff
changeset
|
585 -- client_secret_basic converted internally to client_secret_post |
5223
8b2a36847912
mod_http_oauth2: Support HTTP Basic auth on token endpoint
Matthew Wild <mwild1@gmail.com>
parents:
5222
diff
changeset
|
586 params.client_id = http.urldecode(credentials.username); |
8b2a36847912
mod_http_oauth2: Support HTTP Basic auth on token endpoint
Matthew Wild <mwild1@gmail.com>
parents:
5222
diff
changeset
|
587 params.client_secret = http.urldecode(credentials.password); |
8b2a36847912
mod_http_oauth2: Support HTTP Basic auth on token endpoint
Matthew Wild <mwild1@gmail.com>
parents:
5222
diff
changeset
|
588 end |
8b2a36847912
mod_http_oauth2: Support HTTP Basic auth on token endpoint
Matthew Wild <mwild1@gmail.com>
parents:
5222
diff
changeset
|
589 |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
590 local grant_type = params.grant_type |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
591 local grant_handler = grant_type_handlers[grant_type]; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
592 if not grant_handler then |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
593 return error_response(event.request, oauth_error("unsupported_grant_type")); |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
594 end |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
595 return grant_handler(params); |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
596 end |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
597 |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
598 local function handle_authorization_request(event) |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
599 local request = event.request; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
600 |
4258
cc712899becd
mod_http_oauth2: Unpack event object to improve readability
Kim Alvefur <zash@zash.se>
parents:
4257
diff
changeset
|
601 if not request.url.query then |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
602 return error_response(request, oauth_error("invalid_request")); |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
603 end |
4258
cc712899becd
mod_http_oauth2: Unpack event object to improve readability
Kim Alvefur <zash@zash.se>
parents:
4257
diff
changeset
|
604 local params = http.formdecode(request.url.query); |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
605 if not params then |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
606 return error_response(request, oauth_error("invalid_request")); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
607 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
608 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
609 if not params.client_id then return oauth_error("invalid_request", "missing 'client_id'"); end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
610 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
611 local ok, client = jwt_verify(params.client_id); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
612 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
613 if not ok then |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
614 return oauth_error("invalid_client", "incorrect credentials"); |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
615 end |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
616 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
617 local auth_state = get_auth_state(request); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
618 if not auth_state.user then |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
619 -- Render login page |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
620 return render_page(templates.login, { state = auth_state, client = client }); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
621 elseif auth_state.consent == nil then |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
622 -- Render consent page |
5273
40be37652d70
mod_http_oauth2: Fix traceback on missing 'scope' parameter
Kim Alvefur <zash@zash.se>
parents:
5271
diff
changeset
|
623 return render_page(templates.consent, { state = auth_state; client = client; scopes = parse_scopes(params.scope or "") }, true); |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
624 elseif not auth_state.consent then |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
625 -- Notify client of rejection |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
626 return error_response(request, oauth_error("access_denied")); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
627 end |
5271
3a1df3adad0c
mod_http_oauth2: Allow user to decide which requested scopes to grant
Kim Alvefur <zash@zash.se>
parents:
5268
diff
changeset
|
628 -- else auth_state.consent == true |
3a1df3adad0c
mod_http_oauth2: Allow user to decide which requested scopes to grant
Kim Alvefur <zash@zash.se>
parents:
5268
diff
changeset
|
629 |
3a1df3adad0c
mod_http_oauth2: Allow user to decide which requested scopes to grant
Kim Alvefur <zash@zash.se>
parents:
5268
diff
changeset
|
630 params.scope = auth_state.scope; |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
631 |
5257
b2120fb4a279
mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents:
5256
diff
changeset
|
632 local user_jid = jid.join(auth_state.user.username, module.host); |
5262
e73f364b5624
mod_http_oauth2: Rename oauth client credential related functions
Kim Alvefur <zash@zash.se>
parents:
5259
diff
changeset
|
633 local client_secret = make_client_secret(params.client_id); |
5257
b2120fb4a279
mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents:
5256
diff
changeset
|
634 local id_token_signer = jwt.new_signer("HS256", client_secret); |
b2120fb4a279
mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents:
5256
diff
changeset
|
635 local id_token = id_token_signer({ |
b2120fb4a279
mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents:
5256
diff
changeset
|
636 iss = get_issuer(); |
b2120fb4a279
mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents:
5256
diff
changeset
|
637 sub = url.build({ scheme = "xmpp"; path = user_jid }); |
b2120fb4a279
mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents:
5256
diff
changeset
|
638 aud = params.client_id; |
b2120fb4a279
mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents:
5256
diff
changeset
|
639 nonce = params.nonce; |
b2120fb4a279
mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents:
5256
diff
changeset
|
640 }); |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
641 local response_type = params.response_type; |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
642 local response_handler = response_type_handlers[response_type]; |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
643 if not response_handler then |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
644 return error_response(request, oauth_error("unsupported_response_type")); |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
645 end |
5257
b2120fb4a279
mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents:
5256
diff
changeset
|
646 return response_handler(client, params, user_jid, id_token); |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
647 end |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
648 |
4370
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
649 local function handle_revocation_request(event) |
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
650 local request, response = event.request, event.response; |
5265
f845c218e52c
mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents:
5264
diff
changeset
|
651 if request.headers.authorization then |
f845c218e52c
mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents:
5264
diff
changeset
|
652 local credentials = get_request_credentials(request); |
f845c218e52c
mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents:
5264
diff
changeset
|
653 if not credentials or credentials.type ~= "basic" then |
f845c218e52c
mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents:
5264
diff
changeset
|
654 response.headers.www_authenticate = string.format("Basic realm=%q", module.host.."/"..module.name); |
f845c218e52c
mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents:
5264
diff
changeset
|
655 return 401; |
f845c218e52c
mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents:
5264
diff
changeset
|
656 end |
f845c218e52c
mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents:
5264
diff
changeset
|
657 -- OAuth "client" credentials |
f845c218e52c
mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents:
5264
diff
changeset
|
658 if not verify_client_secret(credentials.username, credentials.password) then |
f845c218e52c
mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents:
5264
diff
changeset
|
659 return 401; |
f845c218e52c
mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents:
5264
diff
changeset
|
660 end |
4370
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
661 end |
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
662 |
5267
60e0bc35de33
mod_http_oauth2: Relax payload content type checking in revocation
Kim Alvefur <zash@zash.se>
parents:
5266
diff
changeset
|
663 local form_data = http.formdecode(event.request.body or ""); |
4370
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
664 if not form_data or not form_data.token then |
5267
60e0bc35de33
mod_http_oauth2: Relax payload content type checking in revocation
Kim Alvefur <zash@zash.se>
parents:
5266
diff
changeset
|
665 response.headers.accept = "application/x-www-form-urlencoded"; |
60e0bc35de33
mod_http_oauth2: Relax payload content type checking in revocation
Kim Alvefur <zash@zash.se>
parents:
5266
diff
changeset
|
666 return 415; |
4370
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
667 end |
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
668 local ok, err = tokens.revoke_token(form_data.token); |
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
669 if not ok then |
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
670 module:log("warn", "Unable to revoke token: %s", tostring(err)); |
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
671 return 500; |
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
672 end |
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
673 return 200; |
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
674 end |
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
675 |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
676 local registration_schema = { |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
677 type = "object"; |
5237
3354f943c1fa
mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents:
5236
diff
changeset
|
678 required = { |
3354f943c1fa
mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents:
5236
diff
changeset
|
679 -- These are shown to users in the template |
3354f943c1fa
mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents:
5236
diff
changeset
|
680 "client_name"; |
3354f943c1fa
mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents:
5236
diff
changeset
|
681 "client_uri"; |
3354f943c1fa
mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents:
5236
diff
changeset
|
682 -- We need at least one redirect URI for things to work |
3354f943c1fa
mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents:
5236
diff
changeset
|
683 "redirect_uris"; |
3354f943c1fa
mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents:
5236
diff
changeset
|
684 }; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
685 properties = { |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
686 redirect_uris = { type = "array"; minLength = 1; items = { type = "string"; format = "uri" } }; |
5377
ca477408f90b
mod_http_oauth2: Fix misplaced 'default' on wrong side of } in client registration schema
Kim Alvefur <zash@zash.se>
parents:
5375
diff
changeset
|
687 token_endpoint_auth_method = { |
ca477408f90b
mod_http_oauth2: Fix misplaced 'default' on wrong side of } in client registration schema
Kim Alvefur <zash@zash.se>
parents:
5375
diff
changeset
|
688 type = "string"; |
ca477408f90b
mod_http_oauth2: Fix misplaced 'default' on wrong side of } in client registration schema
Kim Alvefur <zash@zash.se>
parents:
5375
diff
changeset
|
689 enum = { "none"; "client_secret_post"; "client_secret_basic" }; |
ca477408f90b
mod_http_oauth2: Fix misplaced 'default' on wrong side of } in client registration schema
Kim Alvefur <zash@zash.se>
parents:
5375
diff
changeset
|
690 default = "client_secret_basic"; |
ca477408f90b
mod_http_oauth2: Fix misplaced 'default' on wrong side of } in client registration schema
Kim Alvefur <zash@zash.se>
parents:
5375
diff
changeset
|
691 }; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
692 grant_types = { |
5236
ff8623e2f9d9
mod_http_oauth2: Reorder client metadata validation schema
Kim Alvefur <zash@zash.se>
parents:
5231
diff
changeset
|
693 type = "array"; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
694 items = { |
5236
ff8623e2f9d9
mod_http_oauth2: Reorder client metadata validation schema
Kim Alvefur <zash@zash.se>
parents:
5231
diff
changeset
|
695 type = "string"; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
696 enum = { |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
697 "authorization_code"; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
698 "implicit"; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
699 "password"; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
700 "client_credentials"; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
701 "refresh_token"; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
702 "urn:ietf:params:oauth:grant-type:jwt-bearer"; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
703 "urn:ietf:params:oauth:grant-type:saml2-bearer"; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
704 }; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
705 }; |
5366
db4c66a1d24b
mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents:
5365
diff
changeset
|
706 default = { "authorization_code" }; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
707 }; |
5367
93d445b26063
mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents:
5366
diff
changeset
|
708 application_type = { type = "string"; enum = { "native"; "web" }; default = "web" }; |
5366
db4c66a1d24b
mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents:
5365
diff
changeset
|
709 response_types = { type = "array"; items = { type = "string"; enum = { "code"; "token" } }; default = { "code" } }; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
710 client_name = { type = "string" }; |
5359
230fc6a0c086
mod_http_oauth2: Use new Lua pattern schema properties
Kim Alvefur <zash@zash.se>
parents:
5358
diff
changeset
|
711 client_uri = { type = "string"; format = "uri"; luaPattern = "^https:" }; |
5364
0444953e3247
mod_http_oauth2: Normalize whitespace in client metadata schema
Kim Alvefur <zash@zash.se>
parents:
5359
diff
changeset
|
712 logo_uri = { type = "string"; format = "uri"; luaPattern = "^https:" }; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
713 scope = { type = "string" }; |
5389
d872a1cd8c1d
mod_http_oauth2: Specify that 'contacts' items are emails in client registration
Kim Alvefur <zash@zash.se>
parents:
5388
diff
changeset
|
714 contacts = { type = "array"; items = { type = "string"; format = "email" } }; |
5364
0444953e3247
mod_http_oauth2: Normalize whitespace in client metadata schema
Kim Alvefur <zash@zash.se>
parents:
5359
diff
changeset
|
715 tos_uri = { type = "string"; format = "uri"; luaPattern = "^https:" }; |
0444953e3247
mod_http_oauth2: Normalize whitespace in client metadata schema
Kim Alvefur <zash@zash.se>
parents:
5359
diff
changeset
|
716 policy_uri = { type = "string"; format = "uri"; luaPattern = "^https:" }; |
0444953e3247
mod_http_oauth2: Normalize whitespace in client metadata schema
Kim Alvefur <zash@zash.se>
parents:
5359
diff
changeset
|
717 jwks_uri = { type = "string"; format = "uri"; luaPattern = "^https:" }; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
718 jwks = { type = "object"; description = "JSON Web Key Set, RFC 7517" }; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
719 software_id = { type = "string"; format = "uuid" }; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
720 software_version = { type = "string" }; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
721 }; |
5365
698fef74ce53
mod_http_oauth2: Allow only l10n variants of name in client metadata
Kim Alvefur <zash@zash.se>
parents:
5364
diff
changeset
|
722 luaPatternProperties = { |
698fef74ce53
mod_http_oauth2: Allow only l10n variants of name in client metadata
Kim Alvefur <zash@zash.se>
parents:
5364
diff
changeset
|
723 -- Localized versions of descriptive properties and URIs |
698fef74ce53
mod_http_oauth2: Allow only l10n variants of name in client metadata
Kim Alvefur <zash@zash.se>
parents:
5364
diff
changeset
|
724 ["^client_name#"] = { description = "Localized version of 'client_name'"; type = "string" }; |
698fef74ce53
mod_http_oauth2: Allow only l10n variants of name in client metadata
Kim Alvefur <zash@zash.se>
parents:
5364
diff
changeset
|
725 ["^[a-z_]+_uri#"] = { type = "string"; format = "uri"; luaPattern = "^https:" }; |
698fef74ce53
mod_http_oauth2: Allow only l10n variants of name in client metadata
Kim Alvefur <zash@zash.se>
parents:
5364
diff
changeset
|
726 }; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
727 } |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
728 |
5367
93d445b26063
mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents:
5366
diff
changeset
|
729 local function redirect_uri_allowed(redirect_uri, client_uri, app_type) |
93d445b26063
mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents:
5366
diff
changeset
|
730 local uri = url.parse(redirect_uri); |
93d445b26063
mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents:
5366
diff
changeset
|
731 if app_type == "native" then |
5394
434ee49b04de
mod_http_oauth2: Allow loopback IP literals in redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5393
diff
changeset
|
732 return uri.scheme == "http" and loopbacks:contains(uri.host) or uri.scheme ~= "https"; |
5367
93d445b26063
mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents:
5366
diff
changeset
|
733 elseif app_type == "web" then |
93d445b26063
mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents:
5366
diff
changeset
|
734 return uri.scheme == "https" and uri.host == client_uri.host; |
93d445b26063
mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents:
5366
diff
changeset
|
735 end |
93d445b26063
mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents:
5366
diff
changeset
|
736 end |
93d445b26063
mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents:
5366
diff
changeset
|
737 |
5259
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
738 function create_client(client_metadata) |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
739 if not schema.validate(registration_schema, client_metadata) then |
5259
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
740 return nil, oauth_error("invalid_request", "Failed schema validation."); |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
741 end |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
742 |
5366
db4c66a1d24b
mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents:
5365
diff
changeset
|
743 -- Fill in default values |
db4c66a1d24b
mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents:
5365
diff
changeset
|
744 for propname, propspec in pairs(registration_schema.properties) do |
db4c66a1d24b
mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents:
5365
diff
changeset
|
745 if client_metadata[propname] == nil and type(propspec) == "table" and propspec.default ~= nil then |
db4c66a1d24b
mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents:
5365
diff
changeset
|
746 client_metadata[propname] = propspec.default; |
db4c66a1d24b
mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents:
5365
diff
changeset
|
747 end |
db4c66a1d24b
mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents:
5365
diff
changeset
|
748 end |
db4c66a1d24b
mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents:
5365
diff
changeset
|
749 |
5246
fd0d25b42cd9
mod_http_oauth2: Validate all URIs against client_uri in client registration
Kim Alvefur <zash@zash.se>
parents:
5245
diff
changeset
|
750 local client_uri = url.parse(client_metadata.client_uri); |
fd0d25b42cd9
mod_http_oauth2: Validate all URIs against client_uri in client registration
Kim Alvefur <zash@zash.se>
parents:
5245
diff
changeset
|
751 if not client_uri or client_uri.scheme ~= "https" then |
5259
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
752 return nil, oauth_error("invalid_request", "Missing, invalid or insecure client_uri"); |
5246
fd0d25b42cd9
mod_http_oauth2: Validate all URIs against client_uri in client registration
Kim Alvefur <zash@zash.se>
parents:
5245
diff
changeset
|
753 end |
fd0d25b42cd9
mod_http_oauth2: Validate all URIs against client_uri in client registration
Kim Alvefur <zash@zash.se>
parents:
5245
diff
changeset
|
754 |
5239
8620a635106e
mod_http_oauth2: Validate basic URI syntax of redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5237
diff
changeset
|
755 for _, redirect_uri in ipairs(client_metadata.redirect_uris) do |
5367
93d445b26063
mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents:
5366
diff
changeset
|
756 if not redirect_uri_allowed(redirect_uri, client_uri, client_metadata.application_type) then |
93d445b26063
mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents:
5366
diff
changeset
|
757 return nil, oauth_error("invalid_request", "Invalid, insecure or inappropriate redirect URI."); |
5242
4746609a6656
mod_http_oauth2: Validate that informative URLs match the redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5241
diff
changeset
|
758 end |
4746609a6656
mod_http_oauth2: Validate that informative URLs match the redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5241
diff
changeset
|
759 end |
4746609a6656
mod_http_oauth2: Validate that informative URLs match the redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5241
diff
changeset
|
760 |
5244
fa7bd721a3f6
mod_http_oauth2: Fix validation of informative URIs
Kim Alvefur <zash@zash.se>
parents:
5243
diff
changeset
|
761 for field, prop_schema in pairs(registration_schema.properties) do |
5246
fd0d25b42cd9
mod_http_oauth2: Validate all URIs against client_uri in client registration
Kim Alvefur <zash@zash.se>
parents:
5245
diff
changeset
|
762 if field ~= "client_uri" and prop_schema.format == "uri" and client_metadata[field] then |
5242
4746609a6656
mod_http_oauth2: Validate that informative URLs match the redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5241
diff
changeset
|
763 local components = url.parse(client_metadata[field]); |
4746609a6656
mod_http_oauth2: Validate that informative URLs match the redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5241
diff
changeset
|
764 if components.scheme ~= "https" then |
5259
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
765 return nil, oauth_error("invalid_request", "Insecure URI forbidden"); |
5242
4746609a6656
mod_http_oauth2: Validate that informative URLs match the redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5241
diff
changeset
|
766 end |
5246
fd0d25b42cd9
mod_http_oauth2: Validate all URIs against client_uri in client registration
Kim Alvefur <zash@zash.se>
parents:
5245
diff
changeset
|
767 if components.authority ~= client_uri.authority then |
5259
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
768 return nil, oauth_error("invalid_request", "Informative URIs must have the same hostname"); |
5242
4746609a6656
mod_http_oauth2: Validate that informative URLs match the redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5241
diff
changeset
|
769 end |
5239
8620a635106e
mod_http_oauth2: Validate basic URI syntax of redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5237
diff
changeset
|
770 end |
8620a635106e
mod_http_oauth2: Validate basic URI syntax of redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5237
diff
changeset
|
771 end |
8620a635106e
mod_http_oauth2: Validate basic URI syntax of redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5237
diff
changeset
|
772 |
5357
eda3b078ba2c
mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents:
5356
diff
changeset
|
773 -- Localized URIs should be secure too |
eda3b078ba2c
mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents:
5356
diff
changeset
|
774 for k, v in pairs(client_metadata) do |
eda3b078ba2c
mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents:
5356
diff
changeset
|
775 if k:find"_uri#" then |
eda3b078ba2c
mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents:
5356
diff
changeset
|
776 local uri = url.parse(v); |
eda3b078ba2c
mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents:
5356
diff
changeset
|
777 if not uri or uri.scheme ~= "https" then |
eda3b078ba2c
mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents:
5356
diff
changeset
|
778 return nil, oauth_error("invalid_request", "Missing, invalid or insecure "..k); |
eda3b078ba2c
mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents:
5356
diff
changeset
|
779 elseif uri.host ~= client_uri.host then |
eda3b078ba2c
mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents:
5356
diff
changeset
|
780 return nil, oauth_error("invalid_request", "All URIs must use the same hostname as client_uri"); |
eda3b078ba2c
mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents:
5356
diff
changeset
|
781 end |
eda3b078ba2c
mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents:
5356
diff
changeset
|
782 end |
eda3b078ba2c
mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents:
5356
diff
changeset
|
783 end |
eda3b078ba2c
mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents:
5356
diff
changeset
|
784 |
5243
d5dc8edb2695
mod_http_oauth2: Use more compact IDs
Kim Alvefur <zash@zash.se>
parents:
5242
diff
changeset
|
785 -- Ensure each signed client_id JWT is unique, short ID and issued at |
d5dc8edb2695
mod_http_oauth2: Use more compact IDs
Kim Alvefur <zash@zash.se>
parents:
5242
diff
changeset
|
786 -- timestamp should be sufficient to rule out brute force attacks |
d5dc8edb2695
mod_http_oauth2: Use more compact IDs
Kim Alvefur <zash@zash.se>
parents:
5242
diff
changeset
|
787 client_metadata.nonce = id.short(); |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
788 |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
789 -- Do we want to keep everything? |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
790 local client_id = jwt_sign(client_metadata); |
5262
e73f364b5624
mod_http_oauth2: Rename oauth client credential related functions
Kim Alvefur <zash@zash.se>
parents:
5259
diff
changeset
|
791 local client_secret = make_client_secret(client_id); |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
792 |
5221
22483cfce3ce
mod_http_oauth2: Reflect ALL attributes of the client registration
Matthew Wild <mwild1@gmail.com>
parents:
5219
diff
changeset
|
793 client_metadata.client_id = client_id; |
22483cfce3ce
mod_http_oauth2: Reflect ALL attributes of the client registration
Matthew Wild <mwild1@gmail.com>
parents:
5219
diff
changeset
|
794 client_metadata.client_secret = client_secret; |
22483cfce3ce
mod_http_oauth2: Reflect ALL attributes of the client registration
Matthew Wild <mwild1@gmail.com>
parents:
5219
diff
changeset
|
795 client_metadata.client_id_issued_at = os.time(); |
22483cfce3ce
mod_http_oauth2: Reflect ALL attributes of the client registration
Matthew Wild <mwild1@gmail.com>
parents:
5219
diff
changeset
|
796 client_metadata.client_secret_expires_at = 0; |
22483cfce3ce
mod_http_oauth2: Reflect ALL attributes of the client registration
Matthew Wild <mwild1@gmail.com>
parents:
5219
diff
changeset
|
797 |
5202
b81fd0d22c66
mod_http_oauth2: Calculate client secret expiry in registration response
Kim Alvefur <zash@zash.se>
parents:
5201
diff
changeset
|
798 if not registration_options.accept_expired then |
5221
22483cfce3ce
mod_http_oauth2: Reflect ALL attributes of the client registration
Matthew Wild <mwild1@gmail.com>
parents:
5219
diff
changeset
|
799 client_metadata.client_secret_expires_at = client_metadata.client_id_issued_at + (registration_options.default_ttl or 3600); |
5202
b81fd0d22c66
mod_http_oauth2: Calculate client secret expiry in registration response
Kim Alvefur <zash@zash.se>
parents:
5201
diff
changeset
|
800 end |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
801 |
5259
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
802 return client_metadata; |
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
803 end |
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
804 |
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
805 local function handle_register_request(event) |
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
806 local request = event.request; |
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
807 local client_metadata, err = json.decode(request.body); |
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
808 if err then |
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
809 return oauth_error("invalid_request", "Invalid JSON"); |
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
810 end |
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
811 |
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
812 local response, err = create_client(client_metadata); |
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
813 if err then return err end |
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
814 |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
815 return { |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
816 status_code = 201; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
817 headers = { content_type = "application/json" }; |
5259
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
818 body = json.encode(response); |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
819 }; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
820 end |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
821 |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
822 if not registration_key then |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
823 module:log("info", "No 'oauth2_registration_key', dynamic client registration disabled") |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
824 handle_authorization_request = nil |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
825 handle_register_request = nil |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
826 end |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
827 |
5228
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
828 local function handle_userinfo_request(event) |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
829 local request = event.request; |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
830 local credentials = get_request_credentials(request); |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
831 if not credentials or not credentials.bearer_token then |
5336
77ac04bd2f65
mod_http_oauth2: Add some debug logging for UserInfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5335
diff
changeset
|
832 module:log("debug", "Missing credentials for UserInfo endpoint: %q", credentials) |
5335
53c6f49dcbb8
mod_http_oauth2: Correct error code when missing credentials for userinfo
Kim Alvefur <zash@zash.se>
parents:
5280
diff
changeset
|
833 return 401; |
5228
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
834 end |
5336
77ac04bd2f65
mod_http_oauth2: Add some debug logging for UserInfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5335
diff
changeset
|
835 local token_info,err = tokens.get_token_info(credentials.bearer_token); |
5228
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
836 if not token_info then |
5336
77ac04bd2f65
mod_http_oauth2: Add some debug logging for UserInfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5335
diff
changeset
|
837 module:log("debug", "UserInfo query failed token validation: %s", err) |
5228
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
838 return 403; |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
839 end |
5337
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
840 local scopes = set.new() |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
841 if type(token_info.grant.data) == "table" and type(token_info.grant.data.oauth2_scopes) == "string" then |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
842 scopes:add_list(parse_scopes(token_info.grant.data.oauth2_scopes)); |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
843 else |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
844 module:log("debug", "token_info = %q", token_info) |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
845 end |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
846 |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
847 if not scopes:contains("openid") then |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
848 module:log("debug", "Missing the 'openid' scope in %q", scopes) |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
849 -- The 'openid' scope is required for access to this endpoint. |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
850 return 403; |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
851 end |
5228
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
852 |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
853 local user_info = { |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
854 iss = get_issuer(); |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
855 sub = url.build({ scheme = "xmpp"; path = token_info.jid }); |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
856 } |
5337
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
857 |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
858 local token_claims = set.intersection(openid_claims, scopes); |
5375
8b7d97f0ae8a
mod_http_oauth2: Fix to include "openid" scope in discovery metadata
Kim Alvefur <zash@zash.se>
parents:
5367
diff
changeset
|
859 token_claims:remove("openid"); -- that's "iss" and "sub" above |
5337
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
860 if not token_claims:empty() then |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
861 -- Another module can do that |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
862 module:fire_event("token/userinfo", { |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
863 token = token_info; |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
864 claims = token_claims; |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
865 username = jid.split(token_info.jid); |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
866 userinfo = user_info; |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
867 }); |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
868 end |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
869 |
5228
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
870 return { |
5258
9629971e307f
mod_http_oauth2: Fix userinfo status code off-by-one
Kim Alvefur <zash@zash.se>
parents:
5257
diff
changeset
|
871 status_code = 200; |
5228
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
872 headers = { content_type = "application/json" }; |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
873 body = json.encode(user_info); |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
874 }; |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
875 end |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
876 |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
877 module:depends("http"); |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
878 module:provides("http", { |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
879 route = { |
5382
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
880 -- OAuth 2.0 in 5 simple steps! |
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
881 -- This is the normal 'authorization_code' flow. |
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
882 |
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
883 -- Step 1. Create OAuth client |
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
884 ["POST /register"] = handle_register_request; |
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
885 |
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
886 -- Step 2. User-facing login and consent view |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
887 ["GET /authorize"] = handle_authorization_request; |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
888 ["POST /authorize"] = handle_authorization_request; |
5245
e22cae58141d
mod_http_oauth2: Organize HTTP routes with comments
Kim Alvefur <zash@zash.se>
parents:
5244
diff
changeset
|
889 |
5382
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
890 -- Step 3. User is redirected to the 'redirect_uri' along with an |
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
891 -- authorization code. In the insecure 'implicit' flow, the access token |
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
892 -- is delivered here. |
5245
e22cae58141d
mod_http_oauth2: Organize HTTP routes with comments
Kim Alvefur <zash@zash.se>
parents:
5244
diff
changeset
|
893 |
5382
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
894 -- Step 4. Retrieve access token using the code. |
5245
e22cae58141d
mod_http_oauth2: Organize HTTP routes with comments
Kim Alvefur <zash@zash.se>
parents:
5244
diff
changeset
|
895 ["POST /token"] = handle_token_grant; |
5382
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
896 |
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
897 -- Step 4 is later repeated using the refresh token to get new access tokens. |
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
898 |
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
899 -- Step 5. Revoke token (access or refresh) |
4370
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
900 ["POST /revoke"] = handle_revocation_request; |
5245
e22cae58141d
mod_http_oauth2: Organize HTTP routes with comments
Kim Alvefur <zash@zash.se>
parents:
5244
diff
changeset
|
901 |
e22cae58141d
mod_http_oauth2: Organize HTTP routes with comments
Kim Alvefur <zash@zash.se>
parents:
5244
diff
changeset
|
902 -- OpenID |
5228
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
903 ["GET /userinfo"] = handle_userinfo_request; |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
904 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
905 -- Optional static content for templates |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
906 ["GET /style.css"] = templates.css and { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
907 headers = { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
908 ["Content-Type"] = "text/css"; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
909 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
910 body = _render_html(templates.css, module:get_option("oauth2_template_style")); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
911 } or nil; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
912 ["GET /script.js"] = templates.js and { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
913 headers = { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
914 ["Content-Type"] = "text/javascript"; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
915 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
916 body = templates.js; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
917 } or nil; |
5393
9b9d612f9083
mod_http_oauth2: Add way to retrieve registration schema
Kim Alvefur <zash@zash.se>
parents:
5392
diff
changeset
|
918 |
9b9d612f9083
mod_http_oauth2: Add way to retrieve registration schema
Kim Alvefur <zash@zash.se>
parents:
5392
diff
changeset
|
919 -- Some convenient fallback handlers |
9b9d612f9083
mod_http_oauth2: Add way to retrieve registration schema
Kim Alvefur <zash@zash.se>
parents:
5392
diff
changeset
|
920 ["GET /register"] = { headers = { content_type = "application/schema+json" }; body = json.encode(registration_schema) }; |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
921 }; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
922 }); |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
923 |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
924 local http_server = require "net.http.server"; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
925 |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
926 module:hook_object_event(http_server, "http-error", function (event) |
4276
ec33b3b1136c
mod_http_oauth2: Fix passing OAuth-specific error details
Kim Alvefur <zash@zash.se>
parents:
4272
diff
changeset
|
927 local oauth2_response = event.error and event.error.extra and event.error.extra.oauth2_response; |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
928 if not oauth2_response then |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
929 return; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
930 end |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
931 event.response.headers.content_type = "application/json"; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
932 event.response.status_code = event.error.code or 400; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
933 return json.encode(oauth2_response); |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
934 end, 5); |
5189
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
935 |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
936 -- OIDC Discovery |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
937 |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
938 module:provides("http", { |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
939 name = "oauth2-discovery"; |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
940 default_path = "/.well-known/oauth-authorization-server"; |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
941 route = { |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
942 ["GET"] = { |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
943 headers = { content_type = "application/json" }; |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
944 body = json.encode { |
5263
381c62ef52aa
mod_http_oauth2: Group metadata section into OAuth and OpenID
Kim Alvefur <zash@zash.se>
parents:
5262
diff
changeset
|
945 -- RFC 8414: OAuth 2.0 Authorization Server Metadata |
5207
c72e3b0914e8
mod_http_oauth: Factor out issuer URL calculation to a helper function
Matthew Wild <mwild1@gmail.com>
parents:
5206
diff
changeset
|
946 issuer = get_issuer(); |
5200
afed7d5bd65c
mod_http_oauth2: Advertise endpoints that are enabled
Kim Alvefur <zash@zash.se>
parents:
5199
diff
changeset
|
947 authorization_endpoint = handle_authorization_request and module:http_url() .. "/authorize" or nil; |
afed7d5bd65c
mod_http_oauth2: Advertise endpoints that are enabled
Kim Alvefur <zash@zash.se>
parents:
5199
diff
changeset
|
948 token_endpoint = handle_token_grant and module:http_url() .. "/token" or nil; |
5189
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
949 jwks_uri = nil; -- TODO? |
5200
afed7d5bd65c
mod_http_oauth2: Advertise endpoints that are enabled
Kim Alvefur <zash@zash.se>
parents:
5199
diff
changeset
|
950 registration_endpoint = handle_register_request and module:http_url() .. "/register" or nil; |
5358
0905d348bd34
mod_http_oauth2: Include additional OpenID scopes in metadata
Kim Alvefur <zash@zash.se>
parents:
5357
diff
changeset
|
951 scopes_supported = usermanager.get_all_roles and array(it.keys(usermanager.get_all_roles(module.host))):append(array(openid_claims:items())); |
5203
c60cff787d6a
mod_http_oauth2: Return actually enabled response types in discovery
Kim Alvefur <zash@zash.se>
parents:
5202
diff
changeset
|
952 response_types_supported = array(it.keys(response_type_handlers)); |
5385
544b92750a2a
mod_http_oauth2: Advertise supported token endpoint auth methods
Kim Alvefur <zash@zash.se>
parents:
5384
diff
changeset
|
953 token_endpoint_auth_methods_supported = array({ "client_secret_post"; "client_secret_basic" }); |
5383
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
954 code_challenge_methods_supported = array(it.keys(verifier_transforms)); |
5192
03aa9baa9ac3
mod_http_oauth2: Add support for 'iss' authz response parameter (RFC 9207)
Matthew Wild <mwild1@gmail.com>
parents:
5191
diff
changeset
|
955 authorization_response_iss_parameter_supported = true; |
5263
381c62ef52aa
mod_http_oauth2: Group metadata section into OAuth and OpenID
Kim Alvefur <zash@zash.se>
parents:
5262
diff
changeset
|
956 |
381c62ef52aa
mod_http_oauth2: Group metadata section into OAuth and OpenID
Kim Alvefur <zash@zash.se>
parents:
5262
diff
changeset
|
957 -- OpenID |
381c62ef52aa
mod_http_oauth2: Group metadata section into OAuth and OpenID
Kim Alvefur <zash@zash.se>
parents:
5262
diff
changeset
|
958 userinfo_endpoint = handle_register_request and module:http_url() .. "/userinfo" or nil; |
5390
f2363e6d9a64
mod_http_oauth2: Advertise the currently supported id_token signing algorithm
Kim Alvefur <zash@zash.se>
parents:
5389
diff
changeset
|
959 id_token_signing_alg_values_supported = { "HS256" }; |
5189
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
960 }; |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
961 }; |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
962 }; |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
963 }); |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
964 |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
965 module:shared("tokenauth/oauthbearer_config").oidc_discovery_url = module:http_url("oauth2-discovery", "/.well-known/oauth-authorization-server"); |