Mercurial > prosody-modules
comparison mod_auth_oauth_external/mod_auth_oauth_external.lua @ 6364:9c110fbecd86
mod_auth_oauth_external: Record existence of users
This allows iterating over users as well as existence checks.
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Sat, 17 Jan 2026 05:14:25 +0100 |
| parents | 97a9f939d472 |
| children | 42866d42e267 |
comparison
equal
deleted
inserted
replaced
| 6363:8f65b23a5fd2 | 6364:9c110fbecd86 |
|---|---|
| 25 registration -> { client_id client_secret } | 25 registration -> { client_id client_secret } |
| 26 { client_id client_secret validation } -> required | 26 { client_id client_secret validation } -> required |
| 27 } | 27 } |
| 28 --]] | 28 --]] |
| 29 | 29 |
| 30 local accounts = module:open_store("accounts"); | |
| 31 | |
| 30 local host = module.host; | 32 local host = module.host; |
| 31 local provider = {}; | 33 local provider = {}; |
| 32 | 34 |
| 35 -- TODO remove, not needed after https://hg.prosody.im/trunk/rev/01f95f3de6fc | |
| 33 local function not_implemented() | 36 local function not_implemented() |
| 34 return nil, "method not implemented" | 37 return nil, "method not implemented" |
| 35 end | 38 end |
| 36 | 39 |
| 37 -- With proper OAuth 2, most of these should be handled at the authorization | 40 -- With proper OAuth 2, most of these should be handled at the authorization |
| 40 provider.get_password = not_implemented; | 43 provider.get_password = not_implemented; |
| 41 provider.set_password = not_implemented; | 44 provider.set_password = not_implemented; |
| 42 provider.create_user = not_implemented; | 45 provider.create_user = not_implemented; |
| 43 provider.delete_user = not_implemented; | 46 provider.delete_user = not_implemented; |
| 44 | 47 |
| 45 function provider.user_exists(_username) | 48 function provider.get_account_info(username) |
| 46 -- Can this even be done in a generic way in OAuth 2? | 49 local account = accounts:get(username); |
| 47 -- OIDC and WebFinger perhaps? | 50 if not account then return nil, "Account not available"; end |
| 48 return true; | 51 return { |
| 52 created = account.created; | |
| 53 password_updated = account.updated; | |
| 54 enabled = not account.disabled; | |
| 55 }; | |
| 56 end | |
| 57 | |
| 58 function provider.user_exists(username) | |
| 59 local account, err = accounts:get(username); | |
| 60 if err then | |
| 61 return nil, err; | |
| 62 elseif account then | |
| 63 return true; | |
| 64 else | |
| 65 return false | |
| 66 end | |
| 49 end | 67 end |
| 50 | 68 |
| 51 function provider.users() | 69 function provider.users() |
| 52 -- TODO this could be done by recording known users locally | 70 return accounts:users(); |
| 53 return function () | |
| 54 module:log("debug", "User iteration not supported"); | |
| 55 return nil; | |
| 56 end | |
| 57 end | 71 end |
| 58 | 72 |
| 59 function provider.get_sasl_handler() | 73 function provider.get_sasl_handler() |
| 60 local profile = {}; | 74 local profile = {}; |
| 61 profile.http_client = http.default:new({ connection_pooling = true }); -- TODO configurable | 75 profile.http_client = http.default:new({ connection_pooling = true }); -- TODO configurable |
| 84 end | 98 end |
| 85 if not validation_endpoint then | 99 if not validation_endpoint then |
| 86 -- We're not going to get more info, only the username | 100 -- We're not going to get more info, only the username |
| 87 self.username = jid.escape(username); | 101 self.username = jid.escape(username); |
| 88 self.token_info = token_resp; | 102 self.token_info = token_resp; |
| 103 accounts:set(self.username, { exists = true }); | |
| 89 return true, true; | 104 return true, true; |
| 90 end | 105 end |
| 91 local ret, err = async.wait_for(self.profile.http_client:request(validation_endpoint, | 106 local ret, err = async.wait_for(self.profile.http_client:request(validation_endpoint, |
| 92 { headers = { ["Authorization"] = "Bearer " .. token_resp.access_token; ["Accept"] = "application/json" } })); | 107 { headers = { ["Authorization"] = "Bearer " .. token_resp.access_token; ["Accept"] = "application/json" } })); |
| 93 if err then | 108 if err then |
| 102 elseif type(response[username_field]) ~= "string" then | 117 elseif type(response[username_field]) ~= "string" then |
| 103 return false, nil, nil; | 118 return false, nil, nil; |
| 104 end | 119 end |
| 105 self.username = jid.escape(response[username_field]); | 120 self.username = jid.escape(response[username_field]); |
| 106 self.token_info = response; | 121 self.token_info = response; |
| 122 accounts:set(self.username, { exists = true }); | |
| 107 return true, true; | 123 return true, true; |
| 108 end | 124 end |
| 109 end | 125 end |
| 110 if validation_endpoint then | 126 if validation_endpoint then |
| 111 function profile:oauthbearer(token) | 127 function profile:oauthbearer(token) |
