Mercurial > prosody-modules
annotate mod_http_oauth2/mod_http_oauth2.lua @ 5448:9d542e86e19a
mod_http_oauth2: Allow requesting a subset of scopes on token refresh
This enables clients to request access tokens with fewer permissions
than the grant they were given, reducing impact of token leak. Clients
could e.g. request access tokens with some privileges and immediately
revoke them after use, or other strategies.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Thu, 11 May 2023 21:40:09 +0200 |
parents | aa4828f040c5 |
children | 9c19a6b8e542 |
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 |
5400
71766a4a7322
mod_http_oauth2: Reduce line count of metadata construction
Kim Alvefur <zash@zash.se>
parents:
5399
diff
changeset
|
24 local function tmap(t) |
71766a4a7322
mod_http_oauth2: Reduce line count of metadata construction
Kim Alvefur <zash@zash.se>
parents:
5399
diff
changeset
|
25 return function(k) |
71766a4a7322
mod_http_oauth2: Reduce line count of metadata construction
Kim Alvefur <zash@zash.se>
parents:
5399
diff
changeset
|
26 return t[k]; |
71766a4a7322
mod_http_oauth2: Reduce line count of metadata construction
Kim Alvefur <zash@zash.se>
parents:
5399
diff
changeset
|
27 end |
71766a4a7322
mod_http_oauth2: Reduce line count of metadata construction
Kim Alvefur <zash@zash.se>
parents:
5399
diff
changeset
|
28 end |
71766a4a7322
mod_http_oauth2: Reduce line count of metadata construction
Kim Alvefur <zash@zash.se>
parents:
5399
diff
changeset
|
29 |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
30 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
|
31 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
|
32 if not f then |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
33 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
|
34 if required then |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
35 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
|
36 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
37 return nil; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
38 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
39 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
|
40 assert(f:close()); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
41 return data; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
42 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
43 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
44 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
|
45 local templates = { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
46 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
|
47 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
|
48 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
|
49 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
|
50 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
|
51 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
52 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
53 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
|
54 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
55 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
|
56 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
|
57 data = data or {}; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
58 data.site_name = site_name; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
59 local resp = { |
5218
1f4b768c831a
mod_http_oauth2: Correct field name for HTTP response status code
Kim Alvefur <zash@zash.se>
parents:
5217
diff
changeset
|
60 status_code = 200; |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
61 headers = { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
62 ["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
|
63 ["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
|
64 ["X-Frame-Options"] = "DENY"; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
65 ["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
|
66 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
67 body = _render_html(template, data); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
68 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
69 return resp; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
70 end |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
71 |
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
|
72 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
|
73 |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
74 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
|
75 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
|
76 |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
77 -- 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
|
78 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
|
79 local registration_algo = module:get_option_string("oauth2_registration_algorithm", "HS256"); |
5416
2393dbae51ed
mod_http_oauth2: Add option for specifying TTL of registered clients
Kim Alvefur <zash@zash.se>
parents:
5409
diff
changeset
|
80 local registration_ttl = module:get_option("oauth2_registration_ttl", nil); |
2393dbae51ed
mod_http_oauth2: Add option for specifying TTL of registered clients
Kim Alvefur <zash@zash.se>
parents:
5409
diff
changeset
|
81 local registration_options = module:get_option("oauth2_registration_options", |
2393dbae51ed
mod_http_oauth2: Add option for specifying TTL of registered clients
Kim Alvefur <zash@zash.se>
parents:
5409
diff
changeset
|
82 { default_ttl = registration_ttl; accept_expired = not registration_ttl }); |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
83 |
5383
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
84 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
|
85 |
5199
f48628dc83f1
mod_http_oauth2: Separate client_secret verification key from JWT key
Kim Alvefur <zash@zash.se>
parents:
5198
diff
changeset
|
86 local verification_key; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
87 local jwt_sign, jwt_verify; |
5196
6b63af56c8ac
mod_http_oauth2: Remove error message
Kim Alvefur <zash@zash.se>
parents:
5195
diff
changeset
|
88 if registration_key then |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
89 -- 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
|
90 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
|
91 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
|
92 end |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
93 |
5254
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
94 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
|
95 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
|
96 end |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
97 |
5375
8b7d97f0ae8a
mod_http_oauth2: Fix to include "openid" scope in discovery metadata
Kim Alvefur <zash@zash.se>
parents:
5367
diff
changeset
|
98 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
|
99 |
5417
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
100 local function split_scopes(scope_list) |
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
101 local claims, roles, unknown = array(), array(), array(); |
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
102 local all_roles = usermanager.get_all_roles(module.host); |
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
103 for _, scope in ipairs(scope_list) do |
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
104 if openid_claims:contains(scope) then |
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
105 claims:push(scope); |
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
106 elseif all_roles[scope] then |
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
107 roles:push(scope); |
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
108 else |
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
109 unknown:push(scope); |
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
110 end |
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
111 end |
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
112 return claims, roles, unknown; |
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
113 end |
5254
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
114 |
5417
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
115 local function can_assume_role(username, requested_role) |
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
116 return usermanager.user_can_assume_role(username, module.host, requested_role); |
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
117 end |
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
118 |
5427
d69c10327d6d
mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents:
5426
diff
changeset
|
119 local function role_assumable_by(username) |
d69c10327d6d
mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents:
5426
diff
changeset
|
120 return function(role) |
d69c10327d6d
mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents:
5426
diff
changeset
|
121 return can_assume_role(username, role); |
d69c10327d6d
mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents:
5426
diff
changeset
|
122 end |
d69c10327d6d
mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents:
5426
diff
changeset
|
123 end |
d69c10327d6d
mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents:
5426
diff
changeset
|
124 |
5426
f75d95f27da7
mod_http_oauth2: Add function for filtering roles
Kim Alvefur <zash@zash.se>
parents:
5425
diff
changeset
|
125 local function user_assumable_roles(username, requested_roles) |
5427
d69c10327d6d
mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents:
5426
diff
changeset
|
126 return array.filter(requested_roles, role_assumable_by(username)); |
5426
f75d95f27da7
mod_http_oauth2: Add function for filtering roles
Kim Alvefur <zash@zash.se>
parents:
5425
diff
changeset
|
127 end |
f75d95f27da7
mod_http_oauth2: Add function for filtering roles
Kim Alvefur <zash@zash.se>
parents:
5425
diff
changeset
|
128 |
5417
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
129 local function filter_scopes(username, requested_scope_string) |
5428
07e166b34c4c
mod_http_oauth2: Simplify code with the power of first class functions
Kim Alvefur <zash@zash.se>
parents:
5427
diff
changeset
|
130 local requested_scopes, requested_roles = split_scopes(parse_scopes(requested_scope_string or "")); |
5417
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
131 |
5428
07e166b34c4c
mod_http_oauth2: Simplify code with the power of first class functions
Kim Alvefur <zash@zash.se>
parents:
5427
diff
changeset
|
132 local granted_roles = user_assumable_roles(username, requested_roles); |
07e166b34c4c
mod_http_oauth2: Simplify code with the power of first class functions
Kim Alvefur <zash@zash.se>
parents:
5427
diff
changeset
|
133 local granted_scopes = requested_scopes + granted_roles; |
5417
3902082c42c4
mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents:
5416
diff
changeset
|
134 |
5428
07e166b34c4c
mod_http_oauth2: Simplify code with the power of first class functions
Kim Alvefur <zash@zash.se>
parents:
5427
diff
changeset
|
135 local selected_role = granted_roles[1]; |
5254
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
136 |
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
137 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
|
138 end |
7cd3b7ec59e9
mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents:
4276
diff
changeset
|
139 |
5213
dc0f502c12f1
mod_http_oauth2: Fix authorization code logic
Kim Alvefur <zash@zash.se>
parents:
5210
diff
changeset
|
140 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
|
141 return os.difftime(code.expires, os.time()); |
4669
d3434fd151b5
mod_http_oauth2: Optimize cleanup timer
Kim Alvefur <zash@zash.se>
parents:
4370
diff
changeset
|
142 end |
d3434fd151b5
mod_http_oauth2: Optimize cleanup timer
Kim Alvefur <zash@zash.se>
parents:
4370
diff
changeset
|
143 |
5213
dc0f502c12f1
mod_http_oauth2: Fix authorization code logic
Kim Alvefur <zash@zash.se>
parents:
5210
diff
changeset
|
144 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
|
145 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
|
146 end |
143515d0b212
mod_http_oauth2: Factor out authorization code validity decision
Kim Alvefur <zash@zash.se>
parents:
4265
diff
changeset
|
147 |
4271
9623b99bb8d2
mod_http_oauth2: Keep authorization codes in memory instead of storage
Kim Alvefur <zash@zash.se>
parents:
4270
diff
changeset
|
148 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
|
149 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
|
150 end); |
9623b99bb8d2
mod_http_oauth2: Keep authorization codes in memory instead of storage
Kim Alvefur <zash@zash.se>
parents:
4270
diff
changeset
|
151 |
5213
dc0f502c12f1
mod_http_oauth2: Fix authorization code logic
Kim Alvefur <zash@zash.se>
parents:
5210
diff
changeset
|
152 -- 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
|
153 -- 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
|
154 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
|
155 local k, code = codes:tail(); |
91b951fb3018
mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents:
4271
diff
changeset
|
156 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
|
157 codes:set(k, nil); |
91b951fb3018
mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents:
4271
diff
changeset
|
158 k, code = codes:tail(); |
91b951fb3018
mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents:
4271
diff
changeset
|
159 end |
91b951fb3018
mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents:
4271
diff
changeset
|
160 end) |
91b951fb3018
mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents:
4271
diff
changeset
|
161 |
5207
c72e3b0914e8
mod_http_oauth: Factor out issuer URL calculation to a helper function
Matthew Wild <mwild1@gmail.com>
parents:
5206
diff
changeset
|
162 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
|
163 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
|
164 end |
c72e3b0914e8
mod_http_oauth: Factor out issuer URL calculation to a helper function
Matthew Wild <mwild1@gmail.com>
parents:
5206
diff
changeset
|
165 |
5209
942f8a2f722d
mod_http_oauth2: Allow non-HTTPS on localhost URLs
Matthew Wild <mwild1@gmail.com>
parents:
5208
diff
changeset
|
166 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
|
167 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
|
168 local u = url.parse(uri); |
942f8a2f722d
mod_http_oauth2: Allow non-HTTPS on localhost URLs
Matthew Wild <mwild1@gmail.com>
parents:
5208
diff
changeset
|
169 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
|
170 end |
942f8a2f722d
mod_http_oauth2: Allow non-HTTPS on localhost URLs
Matthew Wild <mwild1@gmail.com>
parents:
5208
diff
changeset
|
171 |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
172 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
|
173 return errors.new({ |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
174 type = "modify"; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
175 condition = "bad-request"; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
176 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
|
177 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
|
178 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
|
179 }); |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
180 end |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
181 |
5248
b8b2bf0c1b4b
mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents:
5247
diff
changeset
|
182 -- 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
|
183 -- 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
|
184 -- 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
|
185 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
|
186 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
|
187 end |
b8b2bf0c1b4b
mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents:
5247
diff
changeset
|
188 |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
189 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
|
190 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
|
191 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
|
192 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
|
193 end |
5254
b0ccdd12a70d
mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents:
5252
diff
changeset
|
194 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
|
195 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
|
196 end |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
197 |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
198 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
|
199 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
|
200 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
|
201 -- 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
|
202 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
|
203 -- 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
|
204 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
|
205 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
|
206 -- 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
|
207 refresh_token = refresh_token_info.token; |
5445
74fdf4a7cca1
mod_http_oauth2: Fix unintentional persistence
Kim Alvefur <zash@zash.se>
parents:
5429
diff
changeset
|
208 refresh_token_info.token = nil; -- Prevent persistence of *secret* 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
|
209 |
dcb93ffe64ae
mod_http_oauth2: Fix error due to reference loop when using refresh token
Kim Alvefur <zash@zash.se>
parents:
5340
diff
changeset
|
210 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
|
211 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
|
212 |
eb482defd9b0
mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents:
5279
diff
changeset
|
213 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
|
214 |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
215 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
|
216 return { |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
217 token_type = "bearer"; |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
218 access_token = access_token; |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
219 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
|
220 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
|
221 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
|
222 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
|
223 }; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
224 end |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
225 |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
226 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
|
227 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
|
228 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
|
229 -- 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
|
230 return; |
25e824f64fd3
mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents:
5218
diff
changeset
|
231 end |
25e824f64fd3
mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents:
5218
diff
changeset
|
232 -- 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
|
233 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
|
234 end |
25e824f64fd3
mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents:
5218
diff
changeset
|
235 -- 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
|
236 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
|
237 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
|
238 return redirect_uri |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
239 end |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
240 end |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
241 end |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
242 |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
243 local grant_type_handlers = {}; |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
244 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
|
245 local verifier_transforms = {}; |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
246 |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
247 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
|
248 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
|
249 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
|
250 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
|
251 |
3908
8ac5d9933106
mod_http_oauth2: Implement real tokens using mod_authtokens
Matthew Wild <mwild1@gmail.com>
parents:
3903
diff
changeset
|
252 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
|
253 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
|
254 end |
4340
7cd3b7ec59e9
mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents:
4276
diff
changeset
|
255 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
|
256 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
|
257 end |
4340
7cd3b7ec59e9
mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents:
4276
diff
changeset
|
258 |
7cd3b7ec59e9
mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents:
4276
diff
changeset
|
259 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
|
260 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
|
261 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
|
262 end |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
263 |
5257
b2120fb4a279
mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents:
5256
diff
changeset
|
264 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
|
265 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
|
266 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
|
267 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
|
268 end |
44f7edd4f845
mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents:
5255
diff
changeset
|
269 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
|
270 |
5383
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
271 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
|
272 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
|
273 end |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
274 |
5243
d5dc8edb2695
mod_http_oauth2: Use more compact IDs
Kim Alvefur <zash@zash.se>
parents:
5242
diff
changeset
|
275 local code = id.medium(); |
4670
1b81b7269858
mod_http_oauth2: Gracefully handle cache write failure
Kim Alvefur <zash@zash.se>
parents:
4669
diff
changeset
|
276 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
|
277 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
|
278 granted_jid = granted_jid; |
7cd3b7ec59e9
mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents:
4276
diff
changeset
|
279 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
|
280 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
|
281 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
|
282 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
|
283 id_token = id_token; |
4670
1b81b7269858
mod_http_oauth2: Gracefully handle cache write failure
Kim Alvefur <zash@zash.se>
parents:
4669
diff
changeset
|
284 }); |
1b81b7269858
mod_http_oauth2: Gracefully handle cache write failure
Kim Alvefur <zash@zash.se>
parents:
4669
diff
changeset
|
285 if not ok then |
1b81b7269858
mod_http_oauth2: Gracefully handle cache write failure
Kim Alvefur <zash@zash.se>
parents:
4669
diff
changeset
|
286 return {status_code = 429}; |
1b81b7269858
mod_http_oauth2: Gracefully handle cache write failure
Kim Alvefur <zash@zash.se>
parents:
4669
diff
changeset
|
287 end |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
288 |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
289 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
|
290 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
|
291 -- 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
|
292 -- 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
|
293 -- 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
|
294 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
|
295 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
|
296 response = response; |
7c531137a553
mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents:
5187
diff
changeset
|
297 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
|
298 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
|
299 extra = code; |
7c531137a553
mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents:
5187
diff
changeset
|
300 }) 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
|
301 return response; |
5219
25e824f64fd3
mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents:
5218
diff
changeset
|
302 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
|
303 return 400; |
5188
7c531137a553
mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents:
5187
diff
changeset
|
304 end |
7c531137a553
mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents:
5187
diff
changeset
|
305 |
7c531137a553
mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents:
5187
diff
changeset
|
306 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
|
307 |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
308 local query = http.formdecode(redirect.query or ""); |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
309 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
|
310 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
|
311 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
|
312 if params.state then |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
313 table.insert(query, { name = "state", value = params.state }); |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
314 end |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
315 redirect.query = http.formencode(query); |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
316 |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
317 return { |
5210
898575a0c6f3
mod_http_oauth2: Switch to '303 See Other' redirects
Matthew Wild <mwild1@gmail.com>
parents:
5209
diff
changeset
|
318 status_code = 303; |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
319 headers = { |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
320 location = url.build(redirect); |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
321 }; |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
322 } |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
323 end |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
324 |
5186
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
325 -- Implicit flow |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
326 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
|
327 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
|
328 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
|
329 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
|
330 end |
44f7edd4f845
mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents:
5255
diff
changeset
|
331 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
|
332 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
|
333 |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
334 local redirect = url.parse(get_redirect_uri(client, params.redirect_uri)); |
5420
aa068449b0b6
mod_http_oauth2: Bail out of implicit flow on invalid or missing redirect
Kim Alvefur <zash@zash.se>
parents:
5419
diff
changeset
|
335 if not redirect then return 400; end |
5186
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
336 token_info.state = params.state; |
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
337 redirect.fragment = http.formencode(token_info); |
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
338 |
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
339 return { |
5210
898575a0c6f3
mod_http_oauth2: Switch to '303 See Other' redirects
Matthew Wild <mwild1@gmail.com>
parents:
5209
diff
changeset
|
340 status_code = 303; |
5186
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
341 headers = { |
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
342 location = url.build(redirect); |
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
343 }; |
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
344 } |
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
345 end |
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
346 |
5262
e73f364b5624
mod_http_oauth2: Rename oauth client credential related functions
Kim Alvefur <zash@zash.se>
parents:
5259
diff
changeset
|
347 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
|
348 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
|
349 end |
4263
d3af5f94d6df
mod_http_oauth2: Improve storage of client secret
Kim Alvefur <zash@zash.se>
parents:
4260
diff
changeset
|
350 |
5262
e73f364b5624
mod_http_oauth2: Rename oauth client credential related functions
Kim Alvefur <zash@zash.se>
parents:
5259
diff
changeset
|
351 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
|
352 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
|
353 end |
d3af5f94d6df
mod_http_oauth2: Improve storage of client secret
Kim Alvefur <zash@zash.se>
parents:
4260
diff
changeset
|
354 |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
355 function grant_type_handlers.authorization_code(params) |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
356 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
|
357 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
|
358 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
|
359 if params.scope and params.scope ~= "" then |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
360 return oauth_error("invalid_scope", "unknown scope requested"); |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
361 end |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
362 |
5252
85f0c6c1c24f
mod_http_oauth2: Fix attempt to index a boolean value
Kim Alvefur <zash@zash.se>
parents:
5248
diff
changeset
|
363 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
|
364 if not client_ok then |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
365 return oauth_error("invalid_client", "incorrect credentials"); |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
366 end |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
367 |
5262
e73f364b5624
mod_http_oauth2: Rename oauth client credential related functions
Kim Alvefur <zash@zash.se>
parents:
5259
diff
changeset
|
368 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
|
369 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
|
370 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
|
371 end |
4271
9623b99bb8d2
mod_http_oauth2: Keep authorization codes in memory instead of storage
Kim Alvefur <zash@zash.se>
parents:
4270
diff
changeset
|
372 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
|
373 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
|
374 -- 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
|
375 -- prevent a second attempted use |
d5492bc861f6
mod_http_oauth2: Remove authorization codes after use
Kim Alvefur <zash@zash.se>
parents:
5213
diff
changeset
|
376 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
|
377 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
|
378 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
|
379 return oauth_error("invalid_client", "incorrect credentials"); |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
380 end |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
381 |
5383
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
382 -- 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
|
383 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
|
384 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
|
385 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
|
386 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
|
387 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
|
388 end |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
389 |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
390 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
|
391 end |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
392 |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
393 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
|
394 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
|
395 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
|
396 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
|
397 |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
398 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
|
399 if not client_ok then |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
400 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
|
401 end |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
402 |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
403 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
|
404 module:log("debug", "client_secret mismatch"); |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
405 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
|
406 end |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
407 |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
408 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
|
409 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
|
410 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
|
411 end |
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
412 |
5446
dd7bddc87f98
mod_http_oauth2: Fix inclusion of role in refreshed access tokens
Kim Alvefur <zash@zash.se>
parents:
5445
diff
changeset
|
413 local refresh_scopes = refresh_token_info.grant.data.oauth2_scopes; |
5448
9d542e86e19a
mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents:
5447
diff
changeset
|
414 |
9d542e86e19a
mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents:
5447
diff
changeset
|
415 if params.scope then |
9d542e86e19a
mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents:
5447
diff
changeset
|
416 local granted_scopes = set.new(parse_scopes(refresh_scopes)); |
9d542e86e19a
mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents:
5447
diff
changeset
|
417 local requested_scopes = parse_scopes(params.scope); |
9d542e86e19a
mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents:
5447
diff
changeset
|
418 refresh_scopes = array.filter(requested_scopes, function(scope) |
9d542e86e19a
mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents:
5447
diff
changeset
|
419 return granted_scopes:contains(scope); |
9d542e86e19a
mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents:
5447
diff
changeset
|
420 end):concat(" "); |
9d542e86e19a
mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents:
5447
diff
changeset
|
421 end |
9d542e86e19a
mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents:
5447
diff
changeset
|
422 |
9d542e86e19a
mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents:
5447
diff
changeset
|
423 local username = jid.split(refresh_token_info.jid); |
5446
dd7bddc87f98
mod_http_oauth2: Fix inclusion of role in refreshed access tokens
Kim Alvefur <zash@zash.se>
parents:
5445
diff
changeset
|
424 local new_scopes, role = filter_scopes(username, refresh_scopes); |
dd7bddc87f98
mod_http_oauth2: Fix inclusion of role in refreshed access tokens
Kim Alvefur <zash@zash.se>
parents:
5445
diff
changeset
|
425 |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
426 -- 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
|
427 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
|
428 |
5448
9d542e86e19a
mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents:
5447
diff
changeset
|
429 return json.encode(new_access_token(refresh_token_info.jid, role, new_scopes, client, nil, refresh_token_info)); |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
430 end |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
431 |
5383
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
432 -- 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
|
433 |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
434 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
|
435 -- 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
|
436 return code_verifier; |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
437 end |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
438 |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
439 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
|
440 -- 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
|
441 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
|
442 end |
df11a2cbc7b7
mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents:
5382
diff
changeset
|
443 |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
444 -- 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
|
445 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
|
446 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
447 -- 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
|
448 -- 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
|
449 -- 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
|
450 -- (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
|
451 -- to one of them). |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
452 -- 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
|
453 -- 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
|
454 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
|
455 local form = request.method == "POST" |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
456 and request.body |
5276
67777cb7353d
mod_http_oauth2: Pedantic optimization
Kim Alvefur <zash@zash.se>
parents:
5273
diff
changeset
|
457 and request.body ~= "" |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
458 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
|
459 and http.formdecode(request.body); |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
460 |
5277
a1055024b94e
mod_http_oauth2: Stricten check of urlencoded form data
Kim Alvefur <zash@zash.se>
parents:
5276
diff
changeset
|
461 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
|
462 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
463 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
|
464 -- First step: login |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
465 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
|
466 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
|
467 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
|
468 return { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
469 error = "Invalid username/password"; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
470 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
471 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
472 return { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
473 user = { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
474 username = username; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
475 host = module.host; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
476 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
|
477 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
478 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
479 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
|
480 -- Second step: consent |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
481 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
|
482 if not ok then |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
483 return { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
484 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
|
485 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
486 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
487 |
5447
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
488 local scopes = array():append(form):filter(function(field) |
5424
b45d9a81b3da
mod_http_oauth2: Revert role selector, going to try something else
Kim Alvefur <zash@zash.se>
parents:
5423
diff
changeset
|
489 return field.name == "scope"; |
5447
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
490 end):pluck("value"); |
5271
3a1df3adad0c
mod_http_oauth2: Allow user to decide which requested scopes to grant
Kim Alvefur <zash@zash.se>
parents:
5268
diff
changeset
|
491 |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
492 user.token = form.user_token; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
493 return { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
494 user = user; |
5447
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
495 scopes = scopes; |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
496 consent = form.consent == "granted"; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
497 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
498 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
499 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
500 return {}; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
501 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
502 |
5222
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
503 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
|
504 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
|
505 |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
506 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
|
507 |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
508 if auth_type == "Basic" then |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
509 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
|
510 if not creds then return; end |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
511 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
|
512 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
|
513 return { |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
514 type = "basic"; |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
515 username = username; |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
516 password = password; |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
517 }; |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
518 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
|
519 return { |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
520 type = "bearer"; |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
521 bearer_token = auth_data; |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
522 }; |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
523 end |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
524 |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
525 return nil; |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
526 end |
578a72982bb2
mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents:
5221
diff
changeset
|
527 |
3920
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
528 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
|
529 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
|
530 |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
531 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
|
532 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
|
533 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
|
534 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
|
535 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
|
536 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
|
537 end |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
538 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
|
539 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
|
540 end |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
541 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
|
542 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
|
543 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
|
544 end |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
545 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
|
546 end |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
547 |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
548 -- TODO How would this make sense with components? |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
549 -- Have an admin authenticate maybe? |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
550 response_type_handlers.code = nil; |
5186
fa3059e653fa
mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents:
5185
diff
changeset
|
551 response_type_handlers.token = nil; |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
552 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
|
553 end |
cf92e3b30c18
mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents:
3919
diff
changeset
|
554 |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
555 -- 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
|
556 -- 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
|
557 -- 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
|
558 -- 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
|
559 -- 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
|
560 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
|
561 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
|
562 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
|
563 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
|
564 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
|
565 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
|
566 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
567 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
|
568 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
|
569 redirect_uri = redirect_uri |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
570 .. 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
|
571 .. "&" .. 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
|
572 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
|
573 return { |
5210
898575a0c6f3
mod_http_oauth2: Switch to '303 See Other' redirects
Matthew Wild <mwild1@gmail.com>
parents:
5209
diff
changeset
|
574 status_code = 303; |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
575 headers = { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
576 location = redirect_uri; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
577 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
578 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
579 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
580 |
5279
2b858cccac8f
mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents:
5278
diff
changeset
|
581 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
|
582 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
|
583 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
|
584 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
|
585 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
|
586 else |
ac252db71027
mod_http_oauth2: Log flows enabled and disabled
Kim Alvefur <zash@zash.se>
parents:
5229
diff
changeset
|
587 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
|
588 end |
6a3c1febd7be
mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents:
5186
diff
changeset
|
589 end |
6a3c1febd7be
mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents:
5186
diff
changeset
|
590 |
6a3c1febd7be
mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents:
5186
diff
changeset
|
591 -- "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
|
592 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
|
593 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
|
594 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
|
595 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
|
596 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
|
597 else |
ac252db71027
mod_http_oauth2: Log flows enabled and disabled
Kim Alvefur <zash@zash.se>
parents:
5229
diff
changeset
|
598 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
|
599 end |
6a3c1febd7be
mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents:
5186
diff
changeset
|
600 end |
6a3c1febd7be
mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents:
5186
diff
changeset
|
601 |
5384
b40f29ec391a
mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents:
5383
diff
changeset
|
602 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
|
603 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
|
604 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
|
605 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
|
606 verifier_transforms[handler_type] = nil; |
b40f29ec391a
mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents:
5383
diff
changeset
|
607 else |
b40f29ec391a
mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents:
5383
diff
changeset
|
608 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
|
609 end |
b40f29ec391a
mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents:
5383
diff
changeset
|
610 end |
b40f29ec391a
mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents:
5383
diff
changeset
|
611 |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
612 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
|
613 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
|
614 |
3934
469408682152
mod_http_oauth2: Set content type on successful repsponses (fixes #1501)
Kim Alvefur <zash@zash.se>
parents:
3920
diff
changeset
|
615 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
|
616 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
|
617 if not params then |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
618 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
|
619 end |
5223
8b2a36847912
mod_http_oauth2: Support HTTP Basic auth on token endpoint
Matthew Wild <mwild1@gmail.com>
parents:
5222
diff
changeset
|
620 |
5225
3439eb37f23b
mod_http_oauth2: token endpoint: handle missing credentials
Matthew Wild <mwild1@gmail.com>
parents:
5224
diff
changeset
|
621 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
|
622 -- 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
|
623 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
|
624 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
|
625 end |
8b2a36847912
mod_http_oauth2: Support HTTP Basic auth on token endpoint
Matthew Wild <mwild1@gmail.com>
parents:
5222
diff
changeset
|
626 |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
627 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
|
628 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
|
629 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
|
630 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
|
631 end |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
632 return grant_handler(params); |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
633 end |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
634 |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
635 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
|
636 local request = event.request; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
637 |
4258
cc712899becd
mod_http_oauth2: Unpack event object to improve readability
Kim Alvefur <zash@zash.se>
parents:
4257
diff
changeset
|
638 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
|
639 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
|
640 end |
4258
cc712899becd
mod_http_oauth2: Unpack event object to improve readability
Kim Alvefur <zash@zash.se>
parents:
4257
diff
changeset
|
641 local params = http.formdecode(request.url.query); |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
642 if not params then |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
643 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
|
644 end |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
645 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
646 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
|
647 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
648 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
|
649 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
650 if not ok then |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
651 return oauth_error("invalid_client", "incorrect credentials"); |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
652 end |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
653 |
5405
c7a5caad28ef
mod_http_oauth2: Enforce response type encoded in client_id
Kim Alvefur <zash@zash.se>
parents:
5404
diff
changeset
|
654 local client_response_types = set.new(array(client.response_types or { "code" })); |
c7a5caad28ef
mod_http_oauth2: Enforce response type encoded in client_id
Kim Alvefur <zash@zash.se>
parents:
5404
diff
changeset
|
655 client_response_types = set.intersection(client_response_types, allowed_response_type_handlers); |
c7a5caad28ef
mod_http_oauth2: Enforce response type encoded in client_id
Kim Alvefur <zash@zash.se>
parents:
5404
diff
changeset
|
656 if not client_response_types:contains(params.response_type) then |
c7a5caad28ef
mod_http_oauth2: Enforce response type encoded in client_id
Kim Alvefur <zash@zash.se>
parents:
5404
diff
changeset
|
657 return oauth_error("invalid_client", "response_type not allowed"); |
c7a5caad28ef
mod_http_oauth2: Enforce response type encoded in client_id
Kim Alvefur <zash@zash.se>
parents:
5404
diff
changeset
|
658 end |
c7a5caad28ef
mod_http_oauth2: Enforce response type encoded in client_id
Kim Alvefur <zash@zash.se>
parents:
5404
diff
changeset
|
659 |
5447
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
660 local requested_scopes = parse_scopes(params.scope or ""); |
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
661 if client.scope then |
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
662 local client_scopes = set.new(parse_scopes(client.scope)); |
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
663 requested_scopes:filter(function(scope) |
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
664 return client_scopes:contains(scope); |
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
665 end); |
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
666 end |
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
667 |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
668 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
|
669 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
|
670 -- Render login page |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
671 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
|
672 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
|
673 -- Render consent page |
5447
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
674 local scopes, roles = split_scopes(requested_scopes); |
5429
0bbeee8ba8b5
mod_http_oauth2: Strip unknown scopes from consent page
Kim Alvefur <zash@zash.se>
parents:
5428
diff
changeset
|
675 return render_page(templates.consent, { state = auth_state; client = client; scopes = scopes+roles }, true); |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
676 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
|
677 -- Notify client of rejection |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
678 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
|
679 end |
5271
3a1df3adad0c
mod_http_oauth2: Allow user to decide which requested scopes to grant
Kim Alvefur <zash@zash.se>
parents:
5268
diff
changeset
|
680 -- 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
|
681 |
5447
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
682 local granted_scopes = auth_state.scopes |
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
683 if client.scope then |
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
684 local client_scopes = set.new(parse_scopes(client.scope)); |
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
685 granted_scopes:filter(function(scope) |
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
686 return client_scopes:contains(scope); |
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
687 end); |
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
688 end |
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
689 |
aa4828f040c5
mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents:
5446
diff
changeset
|
690 params.scope = granted_scopes:concat(" "); |
5208
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
691 |
5257
b2120fb4a279
mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents:
5256
diff
changeset
|
692 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
|
693 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
|
694 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
|
695 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
|
696 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
|
697 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
|
698 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
|
699 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
|
700 }); |
4256
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
701 local response_type = params.response_type; |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
702 local response_handler = response_type_handlers[response_type]; |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
703 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
|
704 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
|
705 end |
5257
b2120fb4a279
mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents:
5256
diff
changeset
|
706 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
|
707 end |
c4b9d4ba839b
mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents:
4237
diff
changeset
|
708 |
4370
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
709 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
|
710 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
|
711 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
|
712 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
|
713 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
|
714 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
|
715 return 401; |
f845c218e52c
mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents:
5264
diff
changeset
|
716 end |
f845c218e52c
mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents:
5264
diff
changeset
|
717 -- OAuth "client" credentials |
f845c218e52c
mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents:
5264
diff
changeset
|
718 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
|
719 return 401; |
f845c218e52c
mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents:
5264
diff
changeset
|
720 end |
4370
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
721 end |
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
722 |
5267
60e0bc35de33
mod_http_oauth2: Relax payload content type checking in revocation
Kim Alvefur <zash@zash.se>
parents:
5266
diff
changeset
|
723 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
|
724 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
|
725 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
|
726 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
|
727 end |
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
728 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
|
729 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
|
730 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
|
731 return 500; |
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
732 end |
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
733 return 200; |
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
734 end |
dee6b5098278
mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents:
4340
diff
changeset
|
735 |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
736 local registration_schema = { |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
737 type = "object"; |
5237
3354f943c1fa
mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents:
5236
diff
changeset
|
738 required = { |
3354f943c1fa
mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents:
5236
diff
changeset
|
739 -- 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
|
740 "client_name"; |
3354f943c1fa
mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents:
5236
diff
changeset
|
741 "client_uri"; |
3354f943c1fa
mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents:
5236
diff
changeset
|
742 -- 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
|
743 "redirect_uris"; |
3354f943c1fa
mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents:
5236
diff
changeset
|
744 }; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
745 properties = { |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
746 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
|
747 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
|
748 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
|
749 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
|
750 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
|
751 }; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
752 grant_types = { |
5236
ff8623e2f9d9
mod_http_oauth2: Reorder client metadata validation schema
Kim Alvefur <zash@zash.se>
parents:
5231
diff
changeset
|
753 type = "array"; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
754 items = { |
5236
ff8623e2f9d9
mod_http_oauth2: Reorder client metadata validation schema
Kim Alvefur <zash@zash.se>
parents:
5231
diff
changeset
|
755 type = "string"; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
756 enum = { |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
757 "authorization_code"; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
758 "implicit"; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
759 "password"; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
760 "client_credentials"; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
761 "refresh_token"; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
762 "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
|
763 "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
|
764 }; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
765 }; |
5366
db4c66a1d24b
mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents:
5365
diff
changeset
|
766 default = { "authorization_code" }; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
767 }; |
5367
93d445b26063
mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents:
5366
diff
changeset
|
768 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
|
769 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
|
770 client_name = { type = "string" }; |
5359
230fc6a0c086
mod_http_oauth2: Use new Lua pattern schema properties
Kim Alvefur <zash@zash.se>
parents:
5358
diff
changeset
|
771 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
|
772 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
|
773 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
|
774 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
|
775 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
|
776 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
|
777 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
|
778 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
|
779 software_id = { type = "string"; format = "uuid" }; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
780 software_version = { type = "string" }; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
781 }; |
5365
698fef74ce53
mod_http_oauth2: Allow only l10n variants of name in client metadata
Kim Alvefur <zash@zash.se>
parents:
5364
diff
changeset
|
782 luaPatternProperties = { |
698fef74ce53
mod_http_oauth2: Allow only l10n variants of name in client metadata
Kim Alvefur <zash@zash.se>
parents:
5364
diff
changeset
|
783 -- 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
|
784 ["^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
|
785 ["^[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
|
786 }; |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
787 } |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
788 |
5367
93d445b26063
mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents:
5366
diff
changeset
|
789 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
|
790 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
|
791 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
|
792 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
|
793 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
|
794 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
|
795 end |
93d445b26063
mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents:
5366
diff
changeset
|
796 end |
93d445b26063
mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents:
5366
diff
changeset
|
797 |
5259
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
798 function create_client(client_metadata) |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
799 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
|
800 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
|
801 end |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
802 |
5366
db4c66a1d24b
mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents:
5365
diff
changeset
|
803 -- Fill in default values |
db4c66a1d24b
mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents:
5365
diff
changeset
|
804 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
|
805 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
|
806 client_metadata[propname] = propspec.default; |
db4c66a1d24b
mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents:
5365
diff
changeset
|
807 end |
db4c66a1d24b
mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents:
5365
diff
changeset
|
808 end |
db4c66a1d24b
mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents:
5365
diff
changeset
|
809 |
5246
fd0d25b42cd9
mod_http_oauth2: Validate all URIs against client_uri in client registration
Kim Alvefur <zash@zash.se>
parents:
5245
diff
changeset
|
810 local client_uri = url.parse(client_metadata.client_uri); |
5401
c8d04ac200fc
mod_http_oauth2: Reject loopback URIs as client_uri
Kim Alvefur <zash@zash.se>
parents:
5400
diff
changeset
|
811 if not client_uri or client_uri.scheme ~= "https" or loopbacks:contains(client_uri.host) then |
5402
fbf3ede7541b
mod_http_oauth2: More appropriate error conditions in client validation
Kim Alvefur <zash@zash.se>
parents:
5401
diff
changeset
|
812 return nil, oauth_error("invalid_client_metadata", "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
|
813 end |
fd0d25b42cd9
mod_http_oauth2: Validate all URIs against client_uri in client registration
Kim Alvefur <zash@zash.se>
parents:
5245
diff
changeset
|
814 |
5239
8620a635106e
mod_http_oauth2: Validate basic URI syntax of redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5237
diff
changeset
|
815 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
|
816 if not redirect_uri_allowed(redirect_uri, client_uri, client_metadata.application_type) then |
5402
fbf3ede7541b
mod_http_oauth2: More appropriate error conditions in client validation
Kim Alvefur <zash@zash.se>
parents:
5401
diff
changeset
|
817 return nil, oauth_error("invalid_redirect_uri", "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
|
818 end |
4746609a6656
mod_http_oauth2: Validate that informative URLs match the redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5241
diff
changeset
|
819 end |
4746609a6656
mod_http_oauth2: Validate that informative URLs match the redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5241
diff
changeset
|
820 |
5244
fa7bd721a3f6
mod_http_oauth2: Fix validation of informative URIs
Kim Alvefur <zash@zash.se>
parents:
5243
diff
changeset
|
821 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
|
822 if field ~= "client_uri" and prop_schema.format == "uri" and client_metadata[field] then |
5403
c574aaaa4d57
mod_http_oauth2: Simplify validation of various URIs
Kim Alvefur <zash@zash.se>
parents:
5402
diff
changeset
|
823 if not redirect_uri_allowed(client_metadata[field], client_uri, "web") then |
c574aaaa4d57
mod_http_oauth2: Simplify validation of various URIs
Kim Alvefur <zash@zash.se>
parents:
5402
diff
changeset
|
824 return nil, oauth_error("invalid_client_metadata", "Invalid, insecure or inappropriate informative URI"); |
5242
4746609a6656
mod_http_oauth2: Validate that informative URLs match the redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5241
diff
changeset
|
825 end |
5239
8620a635106e
mod_http_oauth2: Validate basic URI syntax of redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5237
diff
changeset
|
826 end |
8620a635106e
mod_http_oauth2: Validate basic URI syntax of redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5237
diff
changeset
|
827 end |
8620a635106e
mod_http_oauth2: Validate basic URI syntax of redirect URIs
Kim Alvefur <zash@zash.se>
parents:
5237
diff
changeset
|
828 |
5357
eda3b078ba2c
mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents:
5356
diff
changeset
|
829 for k, v in pairs(client_metadata) do |
5404
1087f697c3f3
mod_http_oauth2: Strip unknown extra fields from client registration
Kim Alvefur <zash@zash.se>
parents:
5403
diff
changeset
|
830 local base_k = k:match"^([^#]+)#" or k; |
1087f697c3f3
mod_http_oauth2: Strip unknown extra fields from client registration
Kim Alvefur <zash@zash.se>
parents:
5403
diff
changeset
|
831 if not registration_schema.properties[base_k] or k:find"^client_uri#" then |
1087f697c3f3
mod_http_oauth2: Strip unknown extra fields from client registration
Kim Alvefur <zash@zash.se>
parents:
5403
diff
changeset
|
832 -- Ignore and strip unknown extra properties |
1087f697c3f3
mod_http_oauth2: Strip unknown extra fields from client registration
Kim Alvefur <zash@zash.se>
parents:
5403
diff
changeset
|
833 client_metadata[k] = nil; |
1087f697c3f3
mod_http_oauth2: Strip unknown extra fields from client registration
Kim Alvefur <zash@zash.se>
parents:
5403
diff
changeset
|
834 elseif k:find"_uri#" then |
1087f697c3f3
mod_http_oauth2: Strip unknown extra fields from client registration
Kim Alvefur <zash@zash.se>
parents:
5403
diff
changeset
|
835 -- Localized URIs should be secure too |
5403
c574aaaa4d57
mod_http_oauth2: Simplify validation of various URIs
Kim Alvefur <zash@zash.se>
parents:
5402
diff
changeset
|
836 if not redirect_uri_allowed(v, client_uri, "web") then |
c574aaaa4d57
mod_http_oauth2: Simplify validation of various URIs
Kim Alvefur <zash@zash.se>
parents:
5402
diff
changeset
|
837 return nil, oauth_error("invalid_client_metadata", "Invalid, insecure or inappropriate informative URI"); |
5357
eda3b078ba2c
mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents:
5356
diff
changeset
|
838 end |
eda3b078ba2c
mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents:
5356
diff
changeset
|
839 end |
eda3b078ba2c
mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents:
5356
diff
changeset
|
840 end |
eda3b078ba2c
mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents:
5356
diff
changeset
|
841 |
5406
b86d80e21c60
mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents:
5405
diff
changeset
|
842 local grant_types = set.new(client_metadata.grant_types); |
b86d80e21c60
mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents:
5405
diff
changeset
|
843 local response_types = set.new(client_metadata.response_types); |
b86d80e21c60
mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents:
5405
diff
changeset
|
844 |
b86d80e21c60
mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents:
5405
diff
changeset
|
845 if grant_types:contains("authorization_code") and not response_types:contains("code") then |
b86d80e21c60
mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents:
5405
diff
changeset
|
846 return nil, oauth_error("invalid_client_metadata", "Inconsistency between 'grant_types' and 'response_types'"); |
b86d80e21c60
mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents:
5405
diff
changeset
|
847 elseif grant_types:contains("implicit") and not response_types:contains("token") then |
b86d80e21c60
mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents:
5405
diff
changeset
|
848 return nil, oauth_error("invalid_client_metadata", "Inconsistency between 'grant_types' and 'response_types'"); |
b86d80e21c60
mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents:
5405
diff
changeset
|
849 end |
b86d80e21c60
mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents:
5405
diff
changeset
|
850 |
b86d80e21c60
mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents:
5405
diff
changeset
|
851 if set.intersection(grant_types, allowed_grant_type_handlers):empty() then |
b86d80e21c60
mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents:
5405
diff
changeset
|
852 return nil, oauth_error("invalid_client_metadata", "No allowed 'grant_types' specified"); |
b86d80e21c60
mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents:
5405
diff
changeset
|
853 elseif set.intersection(response_types, allowed_response_type_handlers):empty() then |
b86d80e21c60
mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents:
5405
diff
changeset
|
854 return nil, oauth_error("invalid_client_metadata", "No allowed 'response_types' specified"); |
b86d80e21c60
mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents:
5405
diff
changeset
|
855 end |
b86d80e21c60
mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents:
5405
diff
changeset
|
856 |
5243
d5dc8edb2695
mod_http_oauth2: Use more compact IDs
Kim Alvefur <zash@zash.se>
parents:
5242
diff
changeset
|
857 -- 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
|
858 -- 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
|
859 client_metadata.nonce = id.short(); |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
860 |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
861 -- Do we want to keep everything? |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
862 local client_id = jwt_sign(client_metadata); |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
863 |
5221
22483cfce3ce
mod_http_oauth2: Reflect ALL attributes of the client registration
Matthew Wild <mwild1@gmail.com>
parents:
5219
diff
changeset
|
864 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
|
865 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
|
866 |
5407
149634647b48
mod_http_oauth2: Don't issue client_secret when not using authentication
Kim Alvefur <zash@zash.se>
parents:
5406
diff
changeset
|
867 if client_metadata.token_endpoint_auth_method ~= "none" then |
149634647b48
mod_http_oauth2: Don't issue client_secret when not using authentication
Kim Alvefur <zash@zash.se>
parents:
5406
diff
changeset
|
868 local client_secret = make_client_secret(client_id); |
149634647b48
mod_http_oauth2: Don't issue client_secret when not using authentication
Kim Alvefur <zash@zash.se>
parents:
5406
diff
changeset
|
869 client_metadata.client_secret = client_secret; |
149634647b48
mod_http_oauth2: Don't issue client_secret when not using authentication
Kim Alvefur <zash@zash.se>
parents:
5406
diff
changeset
|
870 client_metadata.client_secret_expires_at = 0; |
149634647b48
mod_http_oauth2: Don't issue client_secret when not using authentication
Kim Alvefur <zash@zash.se>
parents:
5406
diff
changeset
|
871 |
149634647b48
mod_http_oauth2: Don't issue client_secret when not using authentication
Kim Alvefur <zash@zash.se>
parents:
5406
diff
changeset
|
872 if not registration_options.accept_expired then |
149634647b48
mod_http_oauth2: Don't issue client_secret when not using authentication
Kim Alvefur <zash@zash.se>
parents:
5406
diff
changeset
|
873 client_metadata.client_secret_expires_at = client_metadata.client_id_issued_at + (registration_options.default_ttl or 3600); |
149634647b48
mod_http_oauth2: Don't issue client_secret when not using authentication
Kim Alvefur <zash@zash.se>
parents:
5406
diff
changeset
|
874 end |
5202
b81fd0d22c66
mod_http_oauth2: Calculate client secret expiry in registration response
Kim Alvefur <zash@zash.se>
parents:
5201
diff
changeset
|
875 end |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
876 |
5259
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
877 return client_metadata; |
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
878 end |
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
879 |
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
880 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
|
881 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
|
882 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
|
883 if err then |
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
884 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
|
885 end |
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
886 |
8fba651b10ef
mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents:
5258
diff
changeset
|
887 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
|
888 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
|
889 |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
890 return { |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
891 status_code = 201; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
892 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
|
893 body = json.encode(response); |
5193
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
894 }; |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
895 end |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
896 |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
897 if not registration_key then |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
898 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
|
899 handle_authorization_request = nil |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
900 handle_register_request = nil |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
901 end |
2bb29ece216b
mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents:
5192
diff
changeset
|
902 |
5228
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
903 local function handle_userinfo_request(event) |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
904 local request = event.request; |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
905 local credentials = get_request_credentials(request); |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
906 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
|
907 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
|
908 return 401; |
5228
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
909 end |
5336
77ac04bd2f65
mod_http_oauth2: Add some debug logging for UserInfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5335
diff
changeset
|
910 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
|
911 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
|
912 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
|
913 return 403; |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
914 end |
5337
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
915 local scopes = set.new() |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
916 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
|
917 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
|
918 else |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
919 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
|
920 end |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
921 |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
922 if not scopes:contains("openid") then |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
923 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
|
924 -- 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
|
925 return 403; |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
926 end |
5228
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
927 |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
928 local user_info = { |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
929 iss = get_issuer(); |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
930 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
|
931 } |
5337
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
932 |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
933 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
|
934 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
|
935 if not token_claims:empty() then |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
936 -- Another module can do that |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
937 module:fire_event("token/userinfo", { |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
938 token = token_info; |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
939 claims = token_claims; |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
940 username = jid.split(token_info.jid); |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
941 userinfo = user_info; |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
942 }); |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
943 end |
8d8e85d6dc91
mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents:
5336
diff
changeset
|
944 |
5228
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
945 return { |
5258
9629971e307f
mod_http_oauth2: Fix userinfo status code off-by-one
Kim Alvefur <zash@zash.se>
parents:
5257
diff
changeset
|
946 status_code = 200; |
5228
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
947 headers = { content_type = "application/json" }; |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
948 body = json.encode(user_info); |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
949 }; |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
950 end |
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
951 |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
952 module:depends("http"); |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
953 module:provides("http", { |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
954 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
|
955 -- 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
|
956 -- 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
|
957 |
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
958 -- 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
|
959 ["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
|
960 |
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
961 -- 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
|
962 ["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
|
963 ["POST /authorize"] = handle_authorization_request; |
5245
e22cae58141d
mod_http_oauth2: Organize HTTP routes with comments
Kim Alvefur <zash@zash.se>
parents:
5244
diff
changeset
|
964 |
5382
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
965 -- 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
|
966 -- 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
|
967 -- is delivered here. |
5245
e22cae58141d
mod_http_oauth2: Organize HTTP routes with comments
Kim Alvefur <zash@zash.se>
parents:
5244
diff
changeset
|
968 |
5382
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
969 -- 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
|
970 ["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
|
971 |
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
972 -- 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
|
973 |
12498c0d705f
mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents:
5378
diff
changeset
|
974 -- 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
|
975 ["POST /revoke"] = handle_revocation_request; |
5245
e22cae58141d
mod_http_oauth2: Organize HTTP routes with comments
Kim Alvefur <zash@zash.se>
parents:
5244
diff
changeset
|
976 |
e22cae58141d
mod_http_oauth2: Organize HTTP routes with comments
Kim Alvefur <zash@zash.se>
parents:
5244
diff
changeset
|
977 -- OpenID |
5228
77cd01af06a9
mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents:
5225
diff
changeset
|
978 ["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
|
979 |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
980 -- Optional static content for templates |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
981 ["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
|
982 headers = { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
983 ["Content-Type"] = "text/css"; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
984 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
985 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
|
986 } or nil; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
987 ["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
|
988 headers = { |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
989 ["Content-Type"] = "text/javascript"; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
990 }; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
991 body = templates.js; |
aaa64c647e12
mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents:
5207
diff
changeset
|
992 } or nil; |
5393
9b9d612f9083
mod_http_oauth2: Add way to retrieve registration schema
Kim Alvefur <zash@zash.se>
parents:
5392
diff
changeset
|
993 |
9b9d612f9083
mod_http_oauth2: Add way to retrieve registration schema
Kim Alvefur <zash@zash.se>
parents:
5392
diff
changeset
|
994 -- Some convenient fallback handlers |
9b9d612f9083
mod_http_oauth2: Add way to retrieve registration schema
Kim Alvefur <zash@zash.se>
parents:
5392
diff
changeset
|
995 ["GET /register"] = { headers = { content_type = "application/schema+json" }; body = json.encode(registration_schema) }; |
5396
ac7c5669e5f5
mod_http_oauth2: Return status 405 for GET to endpoints without GET handler
Kim Alvefur <zash@zash.se>
parents:
5394
diff
changeset
|
996 ["GET /token"] = function() return 405; end; |
ac7c5669e5f5
mod_http_oauth2: Return status 405 for GET to endpoints without GET handler
Kim Alvefur <zash@zash.se>
parents:
5394
diff
changeset
|
997 ["GET /revoke"] = function() return 405; end; |
3903
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
998 }; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
999 }); |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
1000 |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
1001 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
|
1002 |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
1003 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
|
1004 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
|
1005 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
|
1006 return; |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
1007 end |
cfeb93b80621
mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff
changeset
|
1008 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
|
1009 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
|
1010 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
|
1011 end, 5); |
5189
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
1012 |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
1013 -- OIDC Discovery |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
1014 |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
1015 module:provides("http", { |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
1016 name = "oauth2-discovery"; |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
1017 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
|
1018 route = { |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
1019 ["GET"] = { |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
1020 headers = { content_type = "application/json" }; |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
1021 body = json.encode { |
5263
381c62ef52aa
mod_http_oauth2: Group metadata section into OAuth and OpenID
Kim Alvefur <zash@zash.se>
parents:
5262
diff
changeset
|
1022 -- 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
|
1023 issuer = get_issuer(); |
5200
afed7d5bd65c
mod_http_oauth2: Advertise endpoints that are enabled
Kim Alvefur <zash@zash.se>
parents:
5199
diff
changeset
|
1024 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
|
1025 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
|
1026 jwks_uri = nil; -- TODO? |
5200
afed7d5bd65c
mod_http_oauth2: Advertise endpoints that are enabled
Kim Alvefur <zash@zash.se>
parents:
5199
diff
changeset
|
1027 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
|
1028 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
|
1029 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
|
1030 token_endpoint_auth_methods_supported = array({ "client_secret_post"; "client_secret_basic" }); |
5408
3989c57cc551
mod_http_oauth2: Allow configuring links to policy and terms in metadata
Kim Alvefur <zash@zash.se>
parents:
5407
diff
changeset
|
1031 op_policy_uri = module:get_option_string("oauth2_policy_url", nil); |
3989c57cc551
mod_http_oauth2: Allow configuring links to policy and terms in metadata
Kim Alvefur <zash@zash.se>
parents:
5407
diff
changeset
|
1032 op_tos_uri = module:get_option_string("oauth2_terms_url", nil); |
5397
18b57e91b5e5
mod_http_oauth2: Advertise revocation endpoint in metadata
Kim Alvefur <zash@zash.se>
parents:
5396
diff
changeset
|
1033 revocation_endpoint = handle_revocation_request and module:http_url() .. "/revoke" or nil; |
18b57e91b5e5
mod_http_oauth2: Advertise revocation endpoint in metadata
Kim Alvefur <zash@zash.se>
parents:
5396
diff
changeset
|
1034 revocation_endpoint_auth_methods_supported = array({ "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
|
1035 code_challenge_methods_supported = array(it.keys(verifier_transforms)); |
5400
71766a4a7322
mod_http_oauth2: Reduce line count of metadata construction
Kim Alvefur <zash@zash.se>
parents:
5399
diff
changeset
|
1036 grant_types_supported = array(it.keys(response_type_handlers)):map(tmap { token = "implicit"; code = "authorization_code" }); |
71766a4a7322
mod_http_oauth2: Reduce line count of metadata construction
Kim Alvefur <zash@zash.se>
parents:
5399
diff
changeset
|
1037 response_modes_supported = array(it.keys(response_type_handlers)):map(tmap { token = "fragment"; code = "query" }); |
5192
03aa9baa9ac3
mod_http_oauth2: Add support for 'iss' authz response parameter (RFC 9207)
Matthew Wild <mwild1@gmail.com>
parents:
5191
diff
changeset
|
1038 authorization_response_iss_parameter_supported = true; |
5409
993f28798c75
mod_http_oauth2: Add service documentation URL to metadata
Kim Alvefur <zash@zash.se>
parents:
5408
diff
changeset
|
1039 service_documentation = module:get_option_string("oauth2_service_documentation", "https://modules.prosody.im/mod_http_oauth2.html"); |
5263
381c62ef52aa
mod_http_oauth2: Group metadata section into OAuth and OpenID
Kim Alvefur <zash@zash.se>
parents:
5262
diff
changeset
|
1040 |
381c62ef52aa
mod_http_oauth2: Group metadata section into OAuth and OpenID
Kim Alvefur <zash@zash.se>
parents:
5262
diff
changeset
|
1041 -- OpenID |
381c62ef52aa
mod_http_oauth2: Group metadata section into OAuth and OpenID
Kim Alvefur <zash@zash.se>
parents:
5262
diff
changeset
|
1042 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
|
1043 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
|
1044 }; |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
1045 }; |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
1046 }; |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
1047 }); |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
1048 |
4ee8eb1134a8
mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents:
5188
diff
changeset
|
1049 module:shared("tokenauth/oauthbearer_config").oidc_discovery_url = module:http_url("oauth2-discovery", "/.well-known/oauth-authorization-server"); |