annotate mod_http_oauth2/mod_http_oauth2.lua @ 5479:30e2722c9fa3

mod_http_oauth2: Disable Referrer via header Prevents the various parameters from potentially ending up in logs, as well as reduces the size of requests.
author Kim Alvefur <zash@zash.se>
date Thu, 18 May 2023 14:47:54 +0200
parents af105c7a24b2
children 5108f63e762b
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
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 = {
5470
40c990159006 mod_http_oauth2: Use error status code when rendering error page
Kim Alvefur <zash@zash.se>
parents: 5469
diff changeset
60 status_code = data.error and data.error.code or 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'";
5479
30e2722c9fa3 mod_http_oauth2: Disable Referrer via header
Kim Alvefur <zash@zash.se>
parents: 5478
diff changeset
64 ["Referrer-Policy"] = "no-referrer";
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
65 ["X-Frame-Options"] = "DENY";
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
66 ["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
67 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
68 body = _render_html(template, data);
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
69 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
70 return resp;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
71 end
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
72
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
73 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
74
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
75 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
76 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
77
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
78 -- 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
79 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
80 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
81 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
82 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
83 { 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
84
5383
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
85 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
86
5199
f48628dc83f1 mod_http_oauth2: Separate client_secret verification key from JWT key
Kim Alvefur <zash@zash.se>
parents: 5198
diff changeset
87 local verification_key;
5459
260a859be86a mod_http_oauth2: Rename variables to improve clarity
Kim Alvefur <zash@zash.se>
parents: 5458
diff changeset
88 local sign_client, verify_client;
5196
6b63af56c8ac mod_http_oauth2: Remove error message
Kim Alvefur <zash@zash.se>
parents: 5195
diff changeset
89 if registration_key then
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
90 -- 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
91 verification_key = hashes.hmac_sha256(registration_key, module.host);
5459
260a859be86a mod_http_oauth2: Rename variables to improve clarity
Kim Alvefur <zash@zash.se>
parents: 5458
diff changeset
92 sign_client, verify_client = jwt.init(registration_algo, registration_key, registration_key, registration_options);
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
93 end
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
94
5449
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
95 -- scope : string | array | set
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
96 --
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
97 -- at each step, allow the same or a subset of scopes
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
98 -- (all ( client ( grant ( token ) ) ))
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
99 -- preserve order since it determines role if more than one granted
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
100
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
101 -- string -> array
5254
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
102 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
103 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
104 end
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
105
5467
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
106 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
107
5449
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
108 -- array -> array, array, array
5417
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
109 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
110 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
111 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
112 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
113 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
114 claims:push(scope);
5467
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
115 elseif scope == "xmpp" or all_roles[scope] then
5417
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
116 roles:push(scope);
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
117 else
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
118 unknown:push(scope);
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
119 end
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
120 end
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
121 return claims, roles, unknown;
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
122 end
5254
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
123
5417
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
124 local function can_assume_role(username, requested_role)
5467
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
125 return requested_role == "xmpp" or usermanager.user_can_assume_role(username, module.host, requested_role);
5417
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
126 end
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
127
5449
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
128 -- function (string) : function(string) : boolean
5427
d69c10327d6d mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents: 5426
diff changeset
129 local function role_assumable_by(username)
d69c10327d6d mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents: 5426
diff changeset
130 return function(role)
d69c10327d6d mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents: 5426
diff changeset
131 return can_assume_role(username, role);
d69c10327d6d mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents: 5426
diff changeset
132 end
d69c10327d6d mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents: 5426
diff changeset
133 end
d69c10327d6d mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents: 5426
diff changeset
134
5449
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
135 -- string, array --> array
5426
f75d95f27da7 mod_http_oauth2: Add function for filtering roles
Kim Alvefur <zash@zash.se>
parents: 5425
diff changeset
136 local function user_assumable_roles(username, requested_roles)
5427
d69c10327d6d mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents: 5426
diff changeset
137 return array.filter(requested_roles, role_assumable_by(username));
5426
f75d95f27da7 mod_http_oauth2: Add function for filtering roles
Kim Alvefur <zash@zash.se>
parents: 5425
diff changeset
138 end
f75d95f27da7 mod_http_oauth2: Add function for filtering roles
Kim Alvefur <zash@zash.se>
parents: 5425
diff changeset
139
5449
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
140 -- string, string|nil --> string, string
5417
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
141 local function filter_scopes(username, requested_scope_string)
5428
07e166b34c4c mod_http_oauth2: Simplify code with the power of first class functions
Kim Alvefur <zash@zash.se>
parents: 5427
diff changeset
142 local requested_scopes, requested_roles = split_scopes(parse_scopes(requested_scope_string or ""));
5417
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
143
5428
07e166b34c4c mod_http_oauth2: Simplify code with the power of first class functions
Kim Alvefur <zash@zash.se>
parents: 5427
diff changeset
144 local granted_roles = user_assumable_roles(username, requested_roles);
07e166b34c4c mod_http_oauth2: Simplify code with the power of first class functions
Kim Alvefur <zash@zash.se>
parents: 5427
diff changeset
145 local granted_scopes = requested_scopes + granted_roles;
5417
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
146
5428
07e166b34c4c mod_http_oauth2: Simplify code with the power of first class functions
Kim Alvefur <zash@zash.se>
parents: 5427
diff changeset
147 local selected_role = granted_roles[1];
5254
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
148
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
149 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
150 end
7cd3b7ec59e9 mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents: 4276
diff changeset
151
5213
dc0f502c12f1 mod_http_oauth2: Fix authorization code logic
Kim Alvefur <zash@zash.se>
parents: 5210
diff changeset
152 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
153 return os.difftime(code.expires, os.time());
4669
d3434fd151b5 mod_http_oauth2: Optimize cleanup timer
Kim Alvefur <zash@zash.se>
parents: 4370
diff changeset
154 end
d3434fd151b5 mod_http_oauth2: Optimize cleanup timer
Kim Alvefur <zash@zash.se>
parents: 4370
diff changeset
155
5213
dc0f502c12f1 mod_http_oauth2: Fix authorization code logic
Kim Alvefur <zash@zash.se>
parents: 5210
diff changeset
156 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
157 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
158 end
143515d0b212 mod_http_oauth2: Factor out authorization code validity decision
Kim Alvefur <zash@zash.se>
parents: 4265
diff changeset
159
4271
9623b99bb8d2 mod_http_oauth2: Keep authorization codes in memory instead of storage
Kim Alvefur <zash@zash.se>
parents: 4270
diff changeset
160 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
161 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
162 end);
9623b99bb8d2 mod_http_oauth2: Keep authorization codes in memory instead of storage
Kim Alvefur <zash@zash.se>
parents: 4270
diff changeset
163
5213
dc0f502c12f1 mod_http_oauth2: Fix authorization code logic
Kim Alvefur <zash@zash.se>
parents: 5210
diff changeset
164 -- 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
165 -- 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
166 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
167 local k, code = codes:tail();
91b951fb3018 mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents: 4271
diff changeset
168 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
169 codes:set(k, nil);
91b951fb3018 mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents: 4271
diff changeset
170 k, code = codes:tail();
91b951fb3018 mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents: 4271
diff changeset
171 end
91b951fb3018 mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents: 4271
diff changeset
172 end)
91b951fb3018 mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents: 4271
diff changeset
173
5207
c72e3b0914e8 mod_http_oauth: Factor out issuer URL calculation to a helper function
Matthew Wild <mwild1@gmail.com>
parents: 5206
diff changeset
174 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
175 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
176 end
c72e3b0914e8 mod_http_oauth: Factor out issuer URL calculation to a helper function
Matthew Wild <mwild1@gmail.com>
parents: 5206
diff changeset
177
5458
813fe4f76286 mod_http_oauth2: Do minimal validation of private-use URI schemes
Kim Alvefur <zash@zash.se>
parents: 5457
diff changeset
178 -- Non-standard special redirect URI that has the AS show the authorization
813fe4f76286 mod_http_oauth2: Do minimal validation of private-use URI schemes
Kim Alvefur <zash@zash.se>
parents: 5457
diff changeset
179 -- code to the user for them to copy-paste into the client, which can then
813fe4f76286 mod_http_oauth2: Do minimal validation of private-use URI schemes
Kim Alvefur <zash@zash.se>
parents: 5457
diff changeset
180 -- continue as if it received it via redirect.
813fe4f76286 mod_http_oauth2: Do minimal validation of private-use URI schemes
Kim Alvefur <zash@zash.se>
parents: 5457
diff changeset
181 local oob_uri = "urn:ietf:wg:oauth:2.0:oob";
813fe4f76286 mod_http_oauth2: Do minimal validation of private-use URI schemes
Kim Alvefur <zash@zash.se>
parents: 5457
diff changeset
182
5209
942f8a2f722d mod_http_oauth2: Allow non-HTTPS on localhost URLs
Matthew Wild <mwild1@gmail.com>
parents: 5208
diff changeset
183 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
184
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
185 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
186 return errors.new({
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
187 type = "modify";
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
188 condition = "bad-request";
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
189 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
190 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
191 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
192 });
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
193 end
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
194
5248
b8b2bf0c1b4b mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents: 5247
diff changeset
195 -- 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
196 -- 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
197 -- 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
198 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
199 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
200 end
b8b2bf0c1b4b mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents: 5247
diff changeset
201
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
202 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
203 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
204 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
205 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
206 end
5254
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
207 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
208 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
209 end
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
210
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
211 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
212 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
213 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
214 -- 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
215 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
216 -- 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
217 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
218 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
219 -- 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
220 refresh_token = refresh_token_info.token;
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
221 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
222
5467
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
223 if role == "xmpp" then
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
224 -- Special scope meaning the users default role.
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
225 local user_default_role = usermanager.get_user_role(jid.node(token_jid), module.host);
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
226 role = user_default_role and user_default_role.name;
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
227 end
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
228
5451
6705f2a09702 mod_http_oauth2: Reference grant by id instead of value
Kim Alvefur <zash@zash.se>
parents: 5450
diff changeset
229 local access_token, access_token_info = tokens.create_token(token_jid, grant.id, role, default_access_ttl, "oauth2");
5280
eb482defd9b0 mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents: 5279
diff changeset
230
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
231 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
232 return {
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
233 token_type = "bearer";
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
234 access_token = access_token;
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
235 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
236 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
237 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
238 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
239 };
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
240 end
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
241
5461
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
242 local function normalize_loopback(uri)
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
243 local u = url.parse(uri);
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
244 if u.scheme == "http" and loopbacks:contains(u.host) then
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
245 u.authority = nil;
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
246 u.host = "::1";
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
247 u.port = nil;
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
248 return url.build(u);
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
249 end
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
250 -- else, not a valid loopback uri
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
251 end
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
252
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
253 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
254 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
255 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
256 -- 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
257 return;
25e824f64fd3 mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents: 5218
diff changeset
258 end
25e824f64fd3 mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents: 5218
diff changeset
259 -- 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
260 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
261 end
25e824f64fd3 mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents: 5218
diff changeset
262 -- 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
263 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
264 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
265 return redirect_uri
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
266 end
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
267 end
5461
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
268 -- The authorization server MUST allow any port to be specified at the time
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
269 -- of the request for loopback IP redirect URIs, to accommodate clients that
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
270 -- obtain an available ephemeral port from the operating system at the time
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
271 -- of the request.
5460
c0d62c1b4424 mod_http_oauth2: Add FIXME about loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5459
diff changeset
272 -- https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-08.html#section-8.4.2
5461
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
273 local loopback_redirect_uri = normalize_loopback(query_redirect_uri);
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
274 if loopback_redirect_uri then
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
275 for _, redirect_uri in ipairs(client.redirect_uris) do
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
276 if loopback_redirect_uri == normalize_loopback(redirect_uri) then
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
277 return query_redirect_uri;
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
278 end
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
279 end
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
280 end
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
281 end
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
282
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
283 local grant_type_handlers = {};
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
284 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
285 local verifier_transforms = {};
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
286
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
287 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
288 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
289 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
290 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
291
3908
8ac5d9933106 mod_http_oauth2: Implement real tokens using mod_authtokens
Matthew Wild <mwild1@gmail.com>
parents: 3903
diff changeset
292 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
293 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
294 end
4340
7cd3b7ec59e9 mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents: 4276
diff changeset
295 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
296 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
297 end
4340
7cd3b7ec59e9 mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents: 4276
diff changeset
298
7cd3b7ec59e9 mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents: 4276
diff changeset
299 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
300 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
301 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
302 end
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
303
5257
b2120fb4a279 mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents: 5256
diff changeset
304 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
305 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
306 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
307 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
308 end
44f7edd4f845 mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents: 5255
diff changeset
309 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
310
5383
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
311 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
312 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
313 end
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
314
5243
d5dc8edb2695 mod_http_oauth2: Use more compact IDs
Kim Alvefur <zash@zash.se>
parents: 5242
diff changeset
315 local code = id.medium();
4670
1b81b7269858 mod_http_oauth2: Gracefully handle cache write failure
Kim Alvefur <zash@zash.se>
parents: 4669
diff changeset
316 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
317 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
318 granted_jid = granted_jid;
7cd3b7ec59e9 mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents: 4276
diff changeset
319 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
320 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
321 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
322 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
323 id_token = id_token;
4670
1b81b7269858 mod_http_oauth2: Gracefully handle cache write failure
Kim Alvefur <zash@zash.se>
parents: 4669
diff changeset
324 });
1b81b7269858 mod_http_oauth2: Gracefully handle cache write failure
Kim Alvefur <zash@zash.se>
parents: 4669
diff changeset
325 if not ok then
5476
575f52b15f5a mod_http_oauth2: Return OAuth error for authz code store error
Kim Alvefur <zash@zash.se>
parents: 5475
diff changeset
326 return oauth_error("temporarily_unavailable");
4670
1b81b7269858 mod_http_oauth2: Gracefully handle cache write failure
Kim Alvefur <zash@zash.se>
parents: 4669
diff changeset
327 end
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
328
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
329 local redirect_uri = get_redirect_uri(client, params.redirect_uri);
5458
813fe4f76286 mod_http_oauth2: Do minimal validation of private-use URI schemes
Kim Alvefur <zash@zash.se>
parents: 5457
diff changeset
330 if redirect_uri == oob_uri then
5188
7c531137a553 mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents: 5187
diff changeset
331 -- 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
332 -- 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
333 -- 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
334 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
335 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
336 response = response;
7c531137a553 mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents: 5187
diff changeset
337 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
338 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
339 extra = code;
7c531137a553 mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents: 5187
diff changeset
340 }) 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
341 return response;
5219
25e824f64fd3 mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents: 5218
diff changeset
342 elseif not redirect_uri then
5462
f6d8830a83fe mod_http_oauth2: Return proper OAuth error for invalid redirect URI
Kim Alvefur <zash@zash.se>
parents: 5461
diff changeset
343 return oauth_error("invalid_redirect_uri");
5188
7c531137a553 mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents: 5187
diff changeset
344 end
7c531137a553 mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents: 5187
diff changeset
345
7c531137a553 mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents: 5187
diff changeset
346 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
347
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
348 local query = http.formdecode(redirect.query or "");
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
349 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
350 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
351 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
352 if params.state then
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
353 table.insert(query, { name = "state", value = params.state });
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
354 end
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
355 redirect.query = http.formencode(query);
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
356
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
357 return {
5210
898575a0c6f3 mod_http_oauth2: Switch to '303 See Other' redirects
Matthew Wild <mwild1@gmail.com>
parents: 5209
diff changeset
358 status_code = 303;
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
359 headers = {
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
360 location = url.build(redirect);
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
361 };
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
362 }
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
363 end
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
364
5186
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
365 -- Implicit flow
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
366 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
367 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
368 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
369 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
370 end
44f7edd4f845 mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents: 5255
diff changeset
371 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
372 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
373
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
374 local redirect = url.parse(get_redirect_uri(client, params.redirect_uri));
5463
dacde53467f3 mod_http_oauth2: Proper OAuth error for invalid redirect URI in implicit flow too
Kim Alvefur <zash@zash.se>
parents: 5462
diff changeset
375 if not redirect then return oauth_error("invalid_redirect_uri"); end
5186
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
376 token_info.state = params.state;
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
377 redirect.fragment = http.formencode(token_info);
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
378
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
379 return {
5210
898575a0c6f3 mod_http_oauth2: Switch to '303 See Other' redirects
Matthew Wild <mwild1@gmail.com>
parents: 5209
diff changeset
380 status_code = 303;
5186
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
381 headers = {
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
382 location = url.build(redirect);
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
383 };
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
384 }
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
385 end
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
386
5262
e73f364b5624 mod_http_oauth2: Rename oauth client credential related functions
Kim Alvefur <zash@zash.se>
parents: 5259
diff changeset
387 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
388 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
389 end
4263
d3af5f94d6df mod_http_oauth2: Improve storage of client secret
Kim Alvefur <zash@zash.se>
parents: 4260
diff changeset
390
5262
e73f364b5624 mod_http_oauth2: Rename oauth client credential related functions
Kim Alvefur <zash@zash.se>
parents: 5259
diff changeset
391 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
392 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
393 end
d3af5f94d6df mod_http_oauth2: Improve storage of client secret
Kim Alvefur <zash@zash.se>
parents: 4260
diff changeset
394
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
395 function grant_type_handlers.authorization_code(params)
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
396 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
397 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
398 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
399 if params.scope and params.scope ~= "" then
5450
d2594bbf7c36 mod_http_oauth2: Scope FIXMEs
Kim Alvefur <zash@zash.se>
parents: 5449
diff changeset
400 -- FIXME allow a subset of granted scopes
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
401 return oauth_error("invalid_scope", "unknown scope requested");
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
402 end
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
403
5459
260a859be86a mod_http_oauth2: Rename variables to improve clarity
Kim Alvefur <zash@zash.se>
parents: 5458
diff changeset
404 local client_ok, client = verify_client(params.client_id);
5252
85f0c6c1c24f mod_http_oauth2: Fix attempt to index a boolean value
Kim Alvefur <zash@zash.se>
parents: 5248
diff changeset
405 if not client_ok then
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
406 return oauth_error("invalid_client", "incorrect credentials");
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
407 end
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
408
5262
e73f364b5624 mod_http_oauth2: Rename oauth client credential related functions
Kim Alvefur <zash@zash.se>
parents: 5259
diff changeset
409 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
410 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
411 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
412 end
4271
9623b99bb8d2 mod_http_oauth2: Keep authorization codes in memory instead of storage
Kim Alvefur <zash@zash.se>
parents: 4270
diff changeset
413 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
414 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
415 -- 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
416 -- prevent a second attempted use
d5492bc861f6 mod_http_oauth2: Remove authorization codes after use
Kim Alvefur <zash@zash.se>
parents: 5213
diff changeset
417 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
418 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
419 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
420 return oauth_error("invalid_client", "incorrect credentials");
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
421 end
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
422
5383
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
423 -- 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
424 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
425 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
426 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
427 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
428 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
429 end
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
430
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
431 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
432 end
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
433
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
434 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
435 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
436 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
437 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
438
5459
260a859be86a mod_http_oauth2: Rename variables to improve clarity
Kim Alvefur <zash@zash.se>
parents: 5458
diff changeset
439 local client_ok, client = verify_client(params.client_id);
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
440 if not client_ok then
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
441 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
442 end
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
443
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
444 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
445 module:log("debug", "client_secret mismatch");
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
446 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
447 end
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
448
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
449 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
450 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
451 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
452 end
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
453
5446
dd7bddc87f98 mod_http_oauth2: Fix inclusion of role in refreshed access tokens
Kim Alvefur <zash@zash.se>
parents: 5445
diff changeset
454 local refresh_scopes = refresh_token_info.grant.data.oauth2_scopes;
5448
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
455
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
456 if params.scope then
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
457 local granted_scopes = set.new(parse_scopes(refresh_scopes));
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
458 local requested_scopes = parse_scopes(params.scope);
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
459 refresh_scopes = array.filter(requested_scopes, function(scope)
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
460 return granted_scopes:contains(scope);
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
461 end):concat(" ");
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
462 end
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
463
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
464 local username = jid.split(refresh_token_info.jid);
5446
dd7bddc87f98 mod_http_oauth2: Fix inclusion of role in refreshed access tokens
Kim Alvefur <zash@zash.se>
parents: 5445
diff changeset
465 local new_scopes, role = filter_scopes(username, refresh_scopes);
dd7bddc87f98 mod_http_oauth2: Fix inclusion of role in refreshed access tokens
Kim Alvefur <zash@zash.se>
parents: 5445
diff changeset
466
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
467 -- 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
468 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
469
5448
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
470 return json.encode(new_access_token(refresh_token_info.jid, role, new_scopes, client, nil, refresh_token_info));
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
471 end
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
472
5383
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
473 -- 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
474
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
475 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
476 -- 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
477 return code_verifier;
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
478 end
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
479
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
480 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
481 -- 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
482 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
483 end
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
484
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
485 -- 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
486 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
487
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
488 -- 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
489 -- 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
490 -- 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
491 -- (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
492 -- to one of them).
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
493 -- 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
494 -- 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
495 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
496 local form = request.method == "POST"
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
497 and request.body
5276
67777cb7353d mod_http_oauth2: Pedantic optimization
Kim Alvefur <zash@zash.se>
parents: 5273
diff changeset
498 and request.body ~= ""
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
499 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
500 and http.formdecode(request.body);
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
501
5277
a1055024b94e mod_http_oauth2: Stricten check of urlencoded form data
Kim Alvefur <zash@zash.se>
parents: 5276
diff changeset
502 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
503
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
504 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
505 -- First step: login
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
506 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
507 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
508 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
509 return {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
510 error = "Invalid username/password";
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
511 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
512 end
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
513 return {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
514 user = {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
515 username = username;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
516 host = module.host;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
517 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
518 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
519 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
520 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
521 -- Second step: consent
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
522 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
523 if not ok then
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
524 return {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
525 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
526 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
527 end
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
528
5447
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
529 local scopes = array():append(form):filter(function(field)
5424
b45d9a81b3da mod_http_oauth2: Revert role selector, going to try something else
Kim Alvefur <zash@zash.se>
parents: 5423
diff changeset
530 return field.name == "scope";
5447
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
531 end):pluck("value");
5271
3a1df3adad0c mod_http_oauth2: Allow user to decide which requested scopes to grant
Kim Alvefur <zash@zash.se>
parents: 5268
diff changeset
532
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
533 user.token = form.user_token;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
534 return {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
535 user = user;
5447
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
536 scopes = scopes;
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
537 consent = form.consent == "granted";
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
538 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
539 end
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
540
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
541 return {};
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
542 end
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
543
5222
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
544 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
545 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
546
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
547 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
548
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
549 if auth_type == "Basic" then
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
550 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
551 if not creds then return; end
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
552 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
553 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
554 return {
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
555 type = "basic";
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
556 username = username;
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
557 password = password;
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
558 };
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
559 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
560 return {
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
561 type = "bearer";
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
562 bearer_token = auth_data;
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
563 };
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
564 end
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
565
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
566 return nil;
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
567 end
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
568
3920
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
569 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
570 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
571
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
572 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
573 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
574 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
575 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
576 if params.scope then
5450
d2594bbf7c36 mod_http_oauth2: Scope FIXMEs
Kim Alvefur <zash@zash.se>
parents: 5449
diff changeset
577 -- TODO shouldn't we support scopes / roles here?
3920
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
578 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
579 end
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
580 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
581 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
582 end
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
583 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
584 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
585 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
586 end
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
587 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
588 end
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
589
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
590 -- TODO How would this make sense with components?
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
591 -- Have an admin authenticate maybe?
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
592 response_type_handlers.code = nil;
5186
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
593 response_type_handlers.token = nil;
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
594 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
595 end
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
596
5472
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
597 local function render_error(err)
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
598 return render_page(templates.error, { error = err });
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
599 end
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
600
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
601 -- 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
602 -- 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
603 -- 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
604 -- 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
605 -- error directly to the user-agent.
5477
5986e0edd7a3 mod_http_oauth2: Use validated redirect URI when returning errors to client
Kim Alvefur <zash@zash.se>
parents: 5476
diff changeset
606 local function error_response(request, redirect_uri, err)
5478
af105c7a24b2 mod_http_oauth2: Always render errors as HTML for OOB redirect URI
Kim Alvefur <zash@zash.se>
parents: 5477
diff changeset
607 if not redirect_uri or redirect_uri == oob_uri then
5472
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
608 return render_error(err);
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
609 end
5477
5986e0edd7a3 mod_http_oauth2: Use validated redirect URI when returning errors to client
Kim Alvefur <zash@zash.se>
parents: 5476
diff changeset
610 local q = request.url.query and http.formdecode(request.url.query);
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
611 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
612 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
613 redirect_uri = redirect_uri
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
614 .. 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
615 .. "&" .. 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
616 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
617 return {
5210
898575a0c6f3 mod_http_oauth2: Switch to '303 See Other' redirects
Matthew Wild <mwild1@gmail.com>
parents: 5209
diff changeset
618 status_code = 303;
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
619 headers = {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
620 location = redirect_uri;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
621 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
622 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
623 end
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
624
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
625 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
626 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
627 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
628 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
629 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
630 else
ac252db71027 mod_http_oauth2: Log flows enabled and disabled
Kim Alvefur <zash@zash.se>
parents: 5229
diff changeset
631 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
632 end
6a3c1febd7be mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents: 5186
diff changeset
633 end
6a3c1febd7be mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents: 5186
diff changeset
634
6a3c1febd7be mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents: 5186
diff changeset
635 -- "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
636 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
637 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
638 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
639 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
640 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
641 else
ac252db71027 mod_http_oauth2: Log flows enabled and disabled
Kim Alvefur <zash@zash.se>
parents: 5229
diff changeset
642 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
643 end
6a3c1febd7be mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents: 5186
diff changeset
644 end
6a3c1febd7be mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents: 5186
diff changeset
645
5384
b40f29ec391a mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents: 5383
diff changeset
646 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
647 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
648 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
649 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
650 verifier_transforms[handler_type] = nil;
b40f29ec391a mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents: 5383
diff changeset
651 else
b40f29ec391a mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents: 5383
diff changeset
652 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
653 end
b40f29ec391a mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents: 5383
diff changeset
654 end
b40f29ec391a mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents: 5383
diff changeset
655
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
656 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
657 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
658
3934
469408682152 mod_http_oauth2: Set content type on successful repsponses (fixes #1501)
Kim Alvefur <zash@zash.se>
parents: 3920
diff changeset
659 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
660 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
661 if not params then
5474
d0b93105b289 mod_http_oauth2: Don't return redirects or HTML from token endpoint
Kim Alvefur <zash@zash.se>
parents: 5473
diff changeset
662 return 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
663 end
5223
8b2a36847912 mod_http_oauth2: Support HTTP Basic auth on token endpoint
Matthew Wild <mwild1@gmail.com>
parents: 5222
diff changeset
664
5225
3439eb37f23b mod_http_oauth2: token endpoint: handle missing credentials
Matthew Wild <mwild1@gmail.com>
parents: 5224
diff changeset
665 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
666 -- 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
667 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
668 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
669 end
8b2a36847912 mod_http_oauth2: Support HTTP Basic auth on token endpoint
Matthew Wild <mwild1@gmail.com>
parents: 5222
diff changeset
670
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
671 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
672 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
673 if not grant_handler then
5474
d0b93105b289 mod_http_oauth2: Don't return redirects or HTML from token endpoint
Kim Alvefur <zash@zash.se>
parents: 5473
diff changeset
674 return 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
675 end
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
676 return grant_handler(params);
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
677 end
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
678
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
679 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
680 local request = event.request;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
681
5472
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
682 -- Directly returning errors to the user before we have a validated client object
4258
cc712899becd mod_http_oauth2: Unpack event object to improve readability
Kim Alvefur <zash@zash.se>
parents: 4257
diff changeset
683 if not request.url.query then
5472
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
684 return render_error(oauth_error("invalid_request", "Missing query parameters"));
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
685 end
4258
cc712899becd mod_http_oauth2: Unpack event object to improve readability
Kim Alvefur <zash@zash.se>
parents: 4257
diff changeset
686 local params = http.formdecode(request.url.query);
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
687 if not params then
5472
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
688 return render_error(oauth_error("invalid_request", "Invalid query parameters"));
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
689 end
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
690
5471
d4d333cb75b2 mod_http_oauth2: Clarify some error messages
Kim Alvefur <zash@zash.se>
parents: 5470
diff changeset
691 if not params.client_id then
5472
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
692 return render_error(oauth_error("invalid_request", "Missing 'client_id' parameter"));
5471
d4d333cb75b2 mod_http_oauth2: Clarify some error messages
Kim Alvefur <zash@zash.se>
parents: 5470
diff changeset
693 end
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
694
5459
260a859be86a mod_http_oauth2: Rename variables to improve clarity
Kim Alvefur <zash@zash.se>
parents: 5458
diff changeset
695 local ok, client = verify_client(params.client_id);
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
696
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
697 if not ok then
5472
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
698 return render_error(oauth_error("invalid_request", "Invalid 'client_id' parameter"));
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
699 end
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
700
5477
5986e0edd7a3 mod_http_oauth2: Use validated redirect URI when returning errors to client
Kim Alvefur <zash@zash.se>
parents: 5476
diff changeset
701 local redirect_uri = get_redirect_uri(client, params.redirect_uri);
5986e0edd7a3 mod_http_oauth2: Use validated redirect URI when returning errors to client
Kim Alvefur <zash@zash.se>
parents: 5476
diff changeset
702 if not redirect_uri then
5475
022733437fef mod_http_oauth2: Validate redirect_uri before using it for error redirects
Kim Alvefur <zash@zash.se>
parents: 5474
diff changeset
703 return render_error(oauth_error("invalid_request", "Invalid 'redirect_uri' parameter"));
022733437fef mod_http_oauth2: Validate redirect_uri before using it for error redirects
Kim Alvefur <zash@zash.se>
parents: 5474
diff changeset
704 end
022733437fef mod_http_oauth2: Validate redirect_uri before using it for error redirects
Kim Alvefur <zash@zash.se>
parents: 5474
diff changeset
705 -- From this point we know that redirect_uri is safe to use
022733437fef mod_http_oauth2: Validate redirect_uri before using it for error redirects
Kim Alvefur <zash@zash.se>
parents: 5474
diff changeset
706
5405
c7a5caad28ef mod_http_oauth2: Enforce response type encoded in client_id
Kim Alvefur <zash@zash.se>
parents: 5404
diff changeset
707 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
708 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
709 if not client_response_types:contains(params.response_type) then
5477
5986e0edd7a3 mod_http_oauth2: Use validated redirect URI when returning errors to client
Kim Alvefur <zash@zash.se>
parents: 5476
diff changeset
710 return error_response(request, redirect_uri, oauth_error("invalid_client", "'response_type' not allowed"));
5405
c7a5caad28ef mod_http_oauth2: Enforce response type encoded in client_id
Kim Alvefur <zash@zash.se>
parents: 5404
diff changeset
711 end
c7a5caad28ef mod_http_oauth2: Enforce response type encoded in client_id
Kim Alvefur <zash@zash.se>
parents: 5404
diff changeset
712
5447
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
713 local requested_scopes = parse_scopes(params.scope or "");
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
714 if client.scope then
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
715 local client_scopes = set.new(parse_scopes(client.scope));
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
716 requested_scopes:filter(function(scope)
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
717 return client_scopes:contains(scope);
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
718 end);
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
719 end
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
720
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
721 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
722 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
723 -- Render login page
5466
398d936e77fb mod_http_oauth2: Add support for the OpenID 'login_hint' parameter
Kim Alvefur <zash@zash.se>
parents: 5465
diff changeset
724 local extra = {};
398d936e77fb mod_http_oauth2: Add support for the OpenID 'login_hint' parameter
Kim Alvefur <zash@zash.se>
parents: 5465
diff changeset
725 if params.login_hint then
398d936e77fb mod_http_oauth2: Add support for the OpenID 'login_hint' parameter
Kim Alvefur <zash@zash.se>
parents: 5465
diff changeset
726 extra.username_hint = (jid.prepped_split(params.login_hint));
398d936e77fb mod_http_oauth2: Add support for the OpenID 'login_hint' parameter
Kim Alvefur <zash@zash.se>
parents: 5465
diff changeset
727 extra.no_username_hint = not extra.username_hint;
398d936e77fb mod_http_oauth2: Add support for the OpenID 'login_hint' parameter
Kim Alvefur <zash@zash.se>
parents: 5465
diff changeset
728 end
398d936e77fb mod_http_oauth2: Add support for the OpenID 'login_hint' parameter
Kim Alvefur <zash@zash.se>
parents: 5465
diff changeset
729 return render_page(templates.login, { state = auth_state; client = client; extra = extra });
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
730 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
731 -- Render consent page
5447
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
732 local scopes, roles = split_scopes(requested_scopes);
5452
b071d8ee6555 mod_http_oauth2: Show only roles the user can use in consent dialog
Kim Alvefur <zash@zash.se>
parents: 5451
diff changeset
733 roles = user_assumable_roles(auth_state.user.username, roles);
5429
0bbeee8ba8b5 mod_http_oauth2: Strip unknown scopes from consent page
Kim Alvefur <zash@zash.se>
parents: 5428
diff changeset
734 return render_page(templates.consent, { state = auth_state; client = client; scopes = scopes+roles }, true);
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
735 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
736 -- Notify client of rejection
5477
5986e0edd7a3 mod_http_oauth2: Use validated redirect URI when returning errors to client
Kim Alvefur <zash@zash.se>
parents: 5476
diff changeset
737 return error_response(request, redirect_uri, oauth_error("access_denied"));
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
738 end
5271
3a1df3adad0c mod_http_oauth2: Allow user to decide which requested scopes to grant
Kim Alvefur <zash@zash.se>
parents: 5268
diff changeset
739 -- 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
740
5447
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
741 local granted_scopes = auth_state.scopes
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
742 if client.scope then
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
743 local client_scopes = set.new(parse_scopes(client.scope));
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
744 granted_scopes:filter(function(scope)
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
745 return client_scopes:contains(scope);
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
746 end);
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
747 end
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
748
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
749 params.scope = granted_scopes:concat(" ");
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
750
5257
b2120fb4a279 mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents: 5256
diff changeset
751 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
752 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
753 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
754 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
755 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
756 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
757 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
758 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
759 });
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
760 local response_type = params.response_type;
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
761 local response_handler = response_type_handlers[response_type];
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
762 if not response_handler then
5477
5986e0edd7a3 mod_http_oauth2: Use validated redirect URI when returning errors to client
Kim Alvefur <zash@zash.se>
parents: 5476
diff changeset
763 return error_response(request, redirect_uri, oauth_error("unsupported_response_type"));
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
764 end
5468
14b5446e22e1 mod_http_oauth2: Fix returning errors from response handlers
Kim Alvefur <zash@zash.se>
parents: 5467
diff changeset
765 local ret = response_handler(client, params, user_jid, id_token);
14b5446e22e1 mod_http_oauth2: Fix returning errors from response handlers
Kim Alvefur <zash@zash.se>
parents: 5467
diff changeset
766 if errors.is_err(ret) then
5477
5986e0edd7a3 mod_http_oauth2: Use validated redirect URI when returning errors to client
Kim Alvefur <zash@zash.se>
parents: 5476
diff changeset
767 return error_response(request, redirect_uri, ret);
5468
14b5446e22e1 mod_http_oauth2: Fix returning errors from response handlers
Kim Alvefur <zash@zash.se>
parents: 5467
diff changeset
768 end
14b5446e22e1 mod_http_oauth2: Fix returning errors from response handlers
Kim Alvefur <zash@zash.se>
parents: 5467
diff changeset
769 return ret;
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
770 end
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
771
4370
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
772 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
773 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
774 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
775 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
776 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
777 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
778 return 401;
f845c218e52c mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents: 5264
diff changeset
779 end
f845c218e52c mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents: 5264
diff changeset
780 -- OAuth "client" credentials
f845c218e52c mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents: 5264
diff changeset
781 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
782 return 401;
f845c218e52c mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents: 5264
diff changeset
783 end
4370
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
784 end
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
785
5267
60e0bc35de33 mod_http_oauth2: Relax payload content type checking in revocation
Kim Alvefur <zash@zash.se>
parents: 5266
diff changeset
786 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
787 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
788 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
789 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
790 end
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
791 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
792 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
793 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
794 return 500;
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
795 end
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
796 return 200;
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
797 end
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
798
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
799 local registration_schema = {
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
800 type = "object";
5237
3354f943c1fa mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents: 5236
diff changeset
801 required = {
3354f943c1fa mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents: 5236
diff changeset
802 -- 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
803 "client_name";
3354f943c1fa mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents: 5236
diff changeset
804 "client_uri";
3354f943c1fa mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents: 5236
diff changeset
805 -- 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
806 "redirect_uris";
3354f943c1fa mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents: 5236
diff changeset
807 };
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
808 properties = {
5454
6970c73711c2 mod_http_oauth2: Reject duplicate redirect URIs in registration
Kim Alvefur <zash@zash.se>
parents: 5453
diff changeset
809 redirect_uris = { type = "array"; minItems = 1; uniqueItems = true; 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
810 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
811 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
812 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
813 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
814 };
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
815 grant_types = {
5236
ff8623e2f9d9 mod_http_oauth2: Reorder client metadata validation schema
Kim Alvefur <zash@zash.se>
parents: 5231
diff changeset
816 type = "array";
5455
80a81e7f3c4e mod_http_oauth2: Require non-empty arrays in client registration
Kim Alvefur <zash@zash.se>
parents: 5454
diff changeset
817 minItems = 1;
5456
9008aea491bf mod_http_oauth2: Reject duplicate list items in client registration
Kim Alvefur <zash@zash.se>
parents: 5455
diff changeset
818 uniqueItems = true;
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
819 items = {
5236
ff8623e2f9d9 mod_http_oauth2: Reorder client metadata validation schema
Kim Alvefur <zash@zash.se>
parents: 5231
diff changeset
820 type = "string";
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
821 enum = {
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
822 "authorization_code";
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
823 "implicit";
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
824 "password";
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
825 "client_credentials";
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
826 "refresh_token";
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
827 "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
828 "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
829 };
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
830 };
5366
db4c66a1d24b mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents: 5365
diff changeset
831 default = { "authorization_code" };
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
832 };
5367
93d445b26063 mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents: 5366
diff changeset
833 application_type = { type = "string"; enum = { "native"; "web" }; default = "web" };
5456
9008aea491bf mod_http_oauth2: Reject duplicate list items in client registration
Kim Alvefur <zash@zash.se>
parents: 5455
diff changeset
834 response_types = {
9008aea491bf mod_http_oauth2: Reject duplicate list items in client registration
Kim Alvefur <zash@zash.se>
parents: 5455
diff changeset
835 type = "array";
9008aea491bf mod_http_oauth2: Reject duplicate list items in client registration
Kim Alvefur <zash@zash.se>
parents: 5455
diff changeset
836 minItems = 1;
9008aea491bf mod_http_oauth2: Reject duplicate list items in client registration
Kim Alvefur <zash@zash.se>
parents: 5455
diff changeset
837 uniqueItems = true;
9008aea491bf mod_http_oauth2: Reject duplicate list items in client registration
Kim Alvefur <zash@zash.se>
parents: 5455
diff changeset
838 items = { type = "string"; enum = { "code"; "token" } };
9008aea491bf mod_http_oauth2: Reject duplicate list items in client registration
Kim Alvefur <zash@zash.se>
parents: 5455
diff changeset
839 default = { "code" };
9008aea491bf mod_http_oauth2: Reject duplicate list items in client registration
Kim Alvefur <zash@zash.se>
parents: 5455
diff changeset
840 };
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
841 client_name = { type = "string" };
5359
230fc6a0c086 mod_http_oauth2: Use new Lua pattern schema properties
Kim Alvefur <zash@zash.se>
parents: 5358
diff changeset
842 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
843 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
844 scope = { type = "string" };
5455
80a81e7f3c4e mod_http_oauth2: Require non-empty arrays in client registration
Kim Alvefur <zash@zash.se>
parents: 5454
diff changeset
845 contacts = { type = "array"; minItems = 1; 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
846 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
847 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
848 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
849 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
850 software_id = { type = "string"; format = "uuid" };
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
851 software_version = { type = "string" };
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
852 };
5365
698fef74ce53 mod_http_oauth2: Allow only l10n variants of name in client metadata
Kim Alvefur <zash@zash.se>
parents: 5364
diff changeset
853 luaPatternProperties = {
698fef74ce53 mod_http_oauth2: Allow only l10n variants of name in client metadata
Kim Alvefur <zash@zash.se>
parents: 5364
diff changeset
854 -- 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
855 ["^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
856 ["^[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
857 };
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
858 }
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
859
5367
93d445b26063 mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents: 5366
diff changeset
860 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
861 local uri = url.parse(redirect_uri);
5457
9156a4754466 mod_http_oauth2: Reject relative redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5456
diff changeset
862 if not uri.scheme then
9156a4754466 mod_http_oauth2: Reject relative redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5456
diff changeset
863 return false; -- no relative URLs
9156a4754466 mod_http_oauth2: Reject relative redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5456
diff changeset
864 end
5367
93d445b26063 mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents: 5366
diff changeset
865 if app_type == "native" then
5458
813fe4f76286 mod_http_oauth2: Do minimal validation of private-use URI schemes
Kim Alvefur <zash@zash.se>
parents: 5457
diff changeset
866 return uri.scheme == "http" and loopbacks:contains(uri.host) or redirect_uri == oob_uri or uri.scheme:find(".", 1, true) ~= nil;
5367
93d445b26063 mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents: 5366
diff changeset
867 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
868 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
869 end
93d445b26063 mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents: 5366
diff changeset
870 end
93d445b26063 mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents: 5366
diff changeset
871
5259
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
872 function create_client(client_metadata)
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
873 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
874 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
875 end
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
876
5366
db4c66a1d24b mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents: 5365
diff changeset
877 -- Fill in default values
db4c66a1d24b mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents: 5365
diff changeset
878 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
879 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
880 client_metadata[propname] = propspec.default;
db4c66a1d24b mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents: 5365
diff changeset
881 end
db4c66a1d24b mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents: 5365
diff changeset
882 end
db4c66a1d24b mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents: 5365
diff changeset
883
5246
fd0d25b42cd9 mod_http_oauth2: Validate all URIs against client_uri in client registration
Kim Alvefur <zash@zash.se>
parents: 5245
diff changeset
884 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
885 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
886 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
887 end
fd0d25b42cd9 mod_http_oauth2: Validate all URIs against client_uri in client registration
Kim Alvefur <zash@zash.se>
parents: 5245
diff changeset
888
5239
8620a635106e mod_http_oauth2: Validate basic URI syntax of redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5237
diff changeset
889 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
890 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
891 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
892 end
4746609a6656 mod_http_oauth2: Validate that informative URLs match the redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5241
diff changeset
893 end
4746609a6656 mod_http_oauth2: Validate that informative URLs match the redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5241
diff changeset
894
5244
fa7bd721a3f6 mod_http_oauth2: Fix validation of informative URIs
Kim Alvefur <zash@zash.se>
parents: 5243
diff changeset
895 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
896 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
897 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
898 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
899 end
5239
8620a635106e mod_http_oauth2: Validate basic URI syntax of redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5237
diff changeset
900 end
8620a635106e mod_http_oauth2: Validate basic URI syntax of redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5237
diff changeset
901 end
8620a635106e mod_http_oauth2: Validate basic URI syntax of redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5237
diff changeset
902
5357
eda3b078ba2c mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents: 5356
diff changeset
903 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
904 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
905 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
906 -- 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
907 client_metadata[k] = nil;
1087f697c3f3 mod_http_oauth2: Strip unknown extra fields from client registration
Kim Alvefur <zash@zash.se>
parents: 5403
diff changeset
908 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
909 -- 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
910 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
911 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
912 end
eda3b078ba2c mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents: 5356
diff changeset
913 end
eda3b078ba2c mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents: 5356
diff changeset
914 end
eda3b078ba2c mod_http_oauth2: Validate (unused at this point) localized URIs
Kim Alvefur <zash@zash.se>
parents: 5356
diff changeset
915
5406
b86d80e21c60 mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents: 5405
diff changeset
916 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
917 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
918
b86d80e21c60 mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents: 5405
diff changeset
919 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
920 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
921 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
922 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
923 end
b86d80e21c60 mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents: 5405
diff changeset
924
b86d80e21c60 mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents: 5405
diff changeset
925 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
926 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
927 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
928 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
929 end
b86d80e21c60 mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents: 5405
diff changeset
930
5243
d5dc8edb2695 mod_http_oauth2: Use more compact IDs
Kim Alvefur <zash@zash.se>
parents: 5242
diff changeset
931 -- 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
932 -- 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
933 client_metadata.nonce = id.short();
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
934
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
935 -- Do we want to keep everything?
5459
260a859be86a mod_http_oauth2: Rename variables to improve clarity
Kim Alvefur <zash@zash.se>
parents: 5458
diff changeset
936 local client_id = sign_client(client_metadata);
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
937
5221
22483cfce3ce mod_http_oauth2: Reflect ALL attributes of the client registration
Matthew Wild <mwild1@gmail.com>
parents: 5219
diff changeset
938 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
939 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
940
5407
149634647b48 mod_http_oauth2: Don't issue client_secret when not using authentication
Kim Alvefur <zash@zash.se>
parents: 5406
diff changeset
941 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
942 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
943 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
944 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
945
149634647b48 mod_http_oauth2: Don't issue client_secret when not using authentication
Kim Alvefur <zash@zash.se>
parents: 5406
diff changeset
946 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
947 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
948 end
5202
b81fd0d22c66 mod_http_oauth2: Calculate client secret expiry in registration response
Kim Alvefur <zash@zash.se>
parents: 5201
diff changeset
949 end
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
950
5259
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
951 return client_metadata;
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
952 end
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
953
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
954 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
955 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
956 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
957 if err then
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
958 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
959 end
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
960
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
961 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
962 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
963
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
964 return {
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
965 status_code = 201;
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
966 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
967 body = json.encode(response);
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
968 };
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
969 end
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
970
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
971 if not registration_key then
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
972 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
973 handle_authorization_request = nil
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
974 handle_register_request = nil
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
975 end
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
976
5228
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
977 local function handle_userinfo_request(event)
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
978 local request = event.request;
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
979 local credentials = get_request_credentials(request);
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
980 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
981 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
982 return 401;
5228
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
983 end
5336
77ac04bd2f65 mod_http_oauth2: Add some debug logging for UserInfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5335
diff changeset
984 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
985 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
986 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
987 return 403;
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
988 end
5337
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
989 local scopes = set.new()
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
990 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
991 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
992 else
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
993 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
994 end
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
995
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
996 if not scopes:contains("openid") then
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
997 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
998 -- 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
999 return 403;
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1000 end
5228
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1001
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1002 local user_info = {
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1003 iss = get_issuer();
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1004 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
1005 }
5337
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1006
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1007 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
1008 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
1009 if not token_claims:empty() then
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1010 -- Another module can do that
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1011 module:fire_event("token/userinfo", {
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1012 token = token_info;
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1013 claims = token_claims;
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1014 username = jid.split(token_info.jid);
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1015 userinfo = user_info;
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1016 });
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1017 end
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1018
5228
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1019 return {
5258
9629971e307f mod_http_oauth2: Fix userinfo status code off-by-one
Kim Alvefur <zash@zash.se>
parents: 5257
diff changeset
1020 status_code = 200;
5228
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1021 headers = { content_type = "application/json" };
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1022 body = json.encode(user_info);
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1023 };
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1024 end
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1025
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1026 module:depends("http");
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1027 module:provides("http", {
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1028 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
1029 -- 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
1030 -- 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
1031
12498c0d705f mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents: 5378
diff changeset
1032 -- 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
1033 ["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
1034
12498c0d705f mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents: 5378
diff changeset
1035 -- 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
1036 ["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
1037 ["POST /authorize"] = handle_authorization_request;
5245
e22cae58141d mod_http_oauth2: Organize HTTP routes with comments
Kim Alvefur <zash@zash.se>
parents: 5244
diff changeset
1038
5382
12498c0d705f mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents: 5378
diff changeset
1039 -- 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
1040 -- 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
1041 -- is delivered here.
5245
e22cae58141d mod_http_oauth2: Organize HTTP routes with comments
Kim Alvefur <zash@zash.se>
parents: 5244
diff changeset
1042
5382
12498c0d705f mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents: 5378
diff changeset
1043 -- 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
1044 ["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
1045
12498c0d705f mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents: 5378
diff changeset
1046 -- 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
1047
12498c0d705f mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents: 5378
diff changeset
1048 -- 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
1049 ["POST /revoke"] = handle_revocation_request;
5245
e22cae58141d mod_http_oauth2: Organize HTTP routes with comments
Kim Alvefur <zash@zash.se>
parents: 5244
diff changeset
1050
e22cae58141d mod_http_oauth2: Organize HTTP routes with comments
Kim Alvefur <zash@zash.se>
parents: 5244
diff changeset
1051 -- OpenID
5228
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1052 ["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
1053
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1054 -- Optional static content for templates
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1055 ["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
1056 headers = {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1057 ["Content-Type"] = "text/css";
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1058 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1059 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
1060 } or nil;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1061 ["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
1062 headers = {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1063 ["Content-Type"] = "text/javascript";
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1064 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1065 body = templates.js;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1066 } or nil;
5393
9b9d612f9083 mod_http_oauth2: Add way to retrieve registration schema
Kim Alvefur <zash@zash.se>
parents: 5392
diff changeset
1067
9b9d612f9083 mod_http_oauth2: Add way to retrieve registration schema
Kim Alvefur <zash@zash.se>
parents: 5392
diff changeset
1068 -- Some convenient fallback handlers
9b9d612f9083 mod_http_oauth2: Add way to retrieve registration schema
Kim Alvefur <zash@zash.se>
parents: 5392
diff changeset
1069 ["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
1070 ["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
1071 ["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
1072 };
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1073 });
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1074
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1075 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
1076
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1077 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
1078 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
1079 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
1080 return;
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1081 end
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1082 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
1083 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
1084 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
1085 end, 5);
5189
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1086
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1087 -- OIDC Discovery
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1088
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1089 module:provides("http", {
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1090 name = "oauth2-discovery";
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1091 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
1092 route = {
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1093 ["GET"] = {
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1094 headers = { content_type = "application/json" };
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1095 body = json.encode {
5263
381c62ef52aa mod_http_oauth2: Group metadata section into OAuth and OpenID
Kim Alvefur <zash@zash.se>
parents: 5262
diff changeset
1096 -- 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
1097 issuer = get_issuer();
5200
afed7d5bd65c mod_http_oauth2: Advertise endpoints that are enabled
Kim Alvefur <zash@zash.se>
parents: 5199
diff changeset
1098 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
1099 token_endpoint = handle_token_grant and module:http_url() .. "/token" or nil;
afed7d5bd65c mod_http_oauth2: Advertise endpoints that are enabled
Kim Alvefur <zash@zash.se>
parents: 5199
diff changeset
1100 registration_endpoint = handle_register_request and module:http_url() .. "/register" or nil;
5467
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
1101 scopes_supported = usermanager.get_all_roles
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
1102 and array(it.keys(usermanager.get_all_roles(module.host))):push("xmpp"):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
1103 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
1104 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
1105 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
1106 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
1107 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
1108 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
1109 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
1110 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
1111 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
1112 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
1113 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
1114
381c62ef52aa mod_http_oauth2: Group metadata section into OAuth and OpenID
Kim Alvefur <zash@zash.se>
parents: 5262
diff changeset
1115 -- OpenID
381c62ef52aa mod_http_oauth2: Group metadata section into OAuth and OpenID
Kim Alvefur <zash@zash.se>
parents: 5262
diff changeset
1116 userinfo_endpoint = handle_register_request and module:http_url() .. "/userinfo" or nil;
5465
66e13e79928b mod_http_oauth2: Note about partial OpenID Discovery implementation
Kim Alvefur <zash@zash.se>
parents: 5463
diff changeset
1117 jwks_uri = nil; -- REQUIRED in OpenID Discovery but not in OAuth 2.0 Metadata
66e13e79928b mod_http_oauth2: Note about partial OpenID Discovery implementation
Kim Alvefur <zash@zash.se>
parents: 5463
diff changeset
1118 id_token_signing_alg_values_supported = { "HS256" }; -- The algorithm RS256 MUST be included, but we use HS256 and client_secret as shared key.
5189
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1119 };
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1120 };
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1121 };
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1122 });
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1123
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1124 module:shared("tokenauth/oauthbearer_config").oidc_discovery_url = module:http_url("oauth2-discovery", "/.well-known/oauth-authorization-server");