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