annotate mod_auth_oauthbearer/mod_auth_oauthbearer.lua @ 5255:001c8fdc91a4

mod_http_oauth2: Add support for the "openid" scope This "openid" scope is there to signal access to the userinfo endpoint, which is needed for OIDC support. We don't actually check this later because the userinfo endpoint only returns info embedded in the token itself, but in the future we may want to check this more carefully.
author Kim Alvefur <zash@zash.se>
date Thu, 16 Mar 2023 17:06:35 +0100
parents d2bf9c8be3a3
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
3114
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
1 local host = module.host;
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
2 local log = module._log;
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
3 local new_sasl = require "util.sasl".new;
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
4 local base64 = require "util.encodings".base64.encode;
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
5
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
6 local provider = {};
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
7
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
8 local oauth_client_id = module:get_option_string("oauth_client_id", "");
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
9 local oauth_client_secret = module:get_option_string("oauth_client_secret", "");
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
10 local oauth_url = module:get_option_string("oauth_url", "");
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
11
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
12 if oauth_client_id == "" then error("oauth_client_id required") end
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
13 if oauth_client_secret == "" then error("oauth_client_secret required") end
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
14 if oauth_url == "" then error("oauth_url required") end
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
15
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
16 -- globals required by socket.http
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
17 if rawget(_G, "PROXY") == nil then
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
18 rawset(_G, "PROXY", false)
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
19 end
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
20 if rawget(_G, "base_parsed") == nil then
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
21 rawset(_G, "base_parsed", false)
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
22 end
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
23
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
24 local function interp(s, tab)
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
25 -- String interpolation, so that we can make the oauth_url configurable
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
26 -- e.g. oauth_url = "https://api.github.com/applications/{{oauth_client_id}}/tokens/{{password}}";
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
27 --
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
28 -- See: http://lua-users.org/wiki/StringInterpolation
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
29 return (s:gsub('(%b{})', function(w) return tab[w:sub(3, -3)] or w end))
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
30 end
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
31
3115
d2bf9c8be3a3 Remove debugging helpers and clean up a little
JC Brand <jc@opkode.com>
parents: 3114
diff changeset
32 function provider.test_password(username, password, realm)
3114
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
33 log("debug", "Testing signed OAuth2 for user %s at realm %s", username, realm);
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
34 local https = require "ssl.https";
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
35 local url = interp(oauth_url, {oauth_client_id = oauth_client_id, password = password});
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
36
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
37 module:log("debug", "The URL is: "..url);
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
38 local _, code, headers, status = https.request{
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
39 url = url,
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
40 headers = {
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
41 Authorization = "Basic "..base64(oauth_client_id..":"..oauth_client_secret);
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
42 }
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
43 };
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
44 if type(code) == "number" and code >= 200 and code <= 299 then
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
45 module:log("debug", "OAuth provider confirmed valid password");
3115
d2bf9c8be3a3 Remove debugging helpers and clean up a little
JC Brand <jc@opkode.com>
parents: 3114
diff changeset
46 return true;
3114
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
47 else
3115
d2bf9c8be3a3 Remove debugging helpers and clean up a little
JC Brand <jc@opkode.com>
parents: 3114
diff changeset
48 module:log("debug", "OAuth provider returned status code: "..code);
3114
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
49 end
3115
d2bf9c8be3a3 Remove debugging helpers and clean up a little
JC Brand <jc@opkode.com>
parents: 3114
diff changeset
50 module:log("warn", "Auth failed. Invalid username/password or misconfiguration.");
d2bf9c8be3a3 Remove debugging helpers and clean up a little
JC Brand <jc@opkode.com>
parents: 3114
diff changeset
51 return nil;
3114
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
52 end
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
53
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
54 function provider.users()
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
55 return function()
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
56 return nil;
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
57 end
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
58 end
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
59
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
60 function provider.set_password(username, password)
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
61 return nil, "Changing passwords not supported";
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
62 end
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
63
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
64 function provider.user_exists(username)
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
65 return true;
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
66 end
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
67
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
68 function provider.create_user(username, password)
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
69 return nil, "User creation not supported";
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
70 end
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
71
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
72 function provider.delete_user(username)
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
73 return nil , "User deletion not supported";
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
74 end
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
75
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
76 function provider.get_sasl_handler()
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
77 local supported_mechanisms = {};
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
78 supported_mechanisms["OAUTHBEARER"] = true;
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
79 return new_sasl(host, {
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
80 oauthbearer = function(sasl, username, password, realm)
3115
d2bf9c8be3a3 Remove debugging helpers and clean up a little
JC Brand <jc@opkode.com>
parents: 3114
diff changeset
81 return provider.test_password(username, password, realm), true;
3114
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
82 end,
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
83 mechanisms = supported_mechanisms
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
84 });
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
85 end
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
86
73ada978dabc mod_sasl_oauthbearer and mod_auth_oauthbearer
JC Brand <jc@opkode.com>
parents:
diff changeset
87 module:provides("auth", provider);