Mercurial > prosody-modules
comparison mod_http_oauth2/mod_http_oauth2.lua @ 4340:7cd3b7ec59e9
mod_http_oauth2: Rudimentary support for scopes (but not really)
We don't support limiting access, but this change will inform the
client what permissions the created token has (e.g. is the user an
admin or not).
There is some work in progress on real scope support.
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Sat, 16 Jan 2021 19:47:22 +0000 |
parents | ec33b3b1136c |
children | dee6b5098278 |
comparison
equal
deleted
inserted
replaced
4339:3b7847c9bd26 | 4340:7cd3b7ec59e9 |
---|---|
12 | 12 |
13 local tokens = module:depends("tokenauth"); | 13 local tokens = module:depends("tokenauth"); |
14 | 14 |
15 local clients = module:open_store("oauth2_clients", "map"); | 15 local clients = module:open_store("oauth2_clients", "map"); |
16 | 16 |
17 local function filter_scopes(request_jid, requested_scope_string) --luacheck: ignore 212/requested_scope_string | |
18 -- We currently don't really support scopes, so override | |
19 -- to whatever real permissions the user has | |
20 if usermanager.is_admin(request_jid, module.host) then | |
21 return "prosody:scope:admin"; | |
22 end | |
23 return "prosody:scope:default"; | |
24 end | |
25 | |
17 local function code_expired(code) | 26 local function code_expired(code) |
18 return os.difftime(os.time(), code.issued) > 120; | 27 return os.difftime(os.time(), code.issued) > 120; |
19 end | 28 end |
20 | 29 |
21 local codes = cache.new(10000, function (_, code) | 30 local codes = cache.new(10000, function (_, code) |
45 local token = tokens.create_jid_token(token_jid, token_jid, scope, ttl); | 54 local token = tokens.create_jid_token(token_jid, token_jid, scope, ttl); |
46 return { | 55 return { |
47 token_type = "bearer"; | 56 token_type = "bearer"; |
48 access_token = token; | 57 access_token = token; |
49 expires_in = ttl; | 58 expires_in = ttl; |
59 scope = scope; | |
50 -- TODO: include refresh_token when implemented | 60 -- TODO: include refresh_token when implemented |
51 }; | 61 }; |
52 end | 62 end |
53 | 63 |
54 local grant_type_handlers = {}; | 64 local grant_type_handlers = {}; |
56 | 66 |
57 function grant_type_handlers.password(params) | 67 function grant_type_handlers.password(params) |
58 local request_jid = assert(params.username, oauth_error("invalid_request", "missing 'username' (JID)")); | 68 local request_jid = assert(params.username, oauth_error("invalid_request", "missing 'username' (JID)")); |
59 local request_password = assert(params.password, oauth_error("invalid_request", "missing 'password'")); | 69 local request_password = assert(params.password, oauth_error("invalid_request", "missing 'password'")); |
60 local request_username, request_host, request_resource = jid.prepped_split(request_jid); | 70 local request_username, request_host, request_resource = jid.prepped_split(request_jid); |
61 if params.scope and params.scope ~= "" then | 71 |
62 return oauth_error("invalid_scope", "unknown scope requested"); | |
63 end | |
64 if not (request_username and request_host) or request_host ~= module.host then | 72 if not (request_username and request_host) or request_host ~= module.host then |
65 return oauth_error("invalid_request", "invalid JID"); | 73 return oauth_error("invalid_request", "invalid JID"); |
66 end | 74 end |
67 if usermanager.test_password(request_username, request_host, request_password) then | 75 if not usermanager.test_password(request_username, request_host, request_password) then |
68 local granted_jid = jid.join(request_username, request_host, request_resource); | 76 return oauth_error("invalid_grant", "incorrect credentials"); |
69 return json.encode(new_access_token(granted_jid, nil, nil)); | 77 end |
70 end | 78 |
71 return oauth_error("invalid_grant", "incorrect credentials"); | 79 local granted_jid = jid.join(request_username, request_host, request_resource); |
80 local granted_scopes = filter_scopes(granted_jid, params.scope); | |
81 return json.encode(new_access_token(granted_jid, granted_scopes, nil)); | |
72 end | 82 end |
73 | 83 |
74 function response_type_handlers.code(params, granted_jid) | 84 function response_type_handlers.code(params, granted_jid) |
75 if not params.client_id then return oauth_error("invalid_request", "missing 'client_id'"); end | 85 if not params.client_id then return oauth_error("invalid_request", "missing 'client_id'"); end |
76 if not params.redirect_uri then return oauth_error("invalid_request", "missing 'redirect_uri'"); end | 86 if not params.redirect_uri then return oauth_error("invalid_request", "missing 'redirect_uri'"); end |
77 if params.scope and params.scope ~= "" then | |
78 return oauth_error("invalid_scope", "unknown scope requested"); | |
79 end | |
80 | 87 |
81 local client_owner, client_host, client_id = jid.prepped_split(params.client_id); | 88 local client_owner, client_host, client_id = jid.prepped_split(params.client_id); |
82 if client_host ~= module.host then | 89 if client_host ~= module.host then |
83 return oauth_error("invalid_client", "incorrect credentials"); | 90 return oauth_error("invalid_client", "incorrect credentials"); |
84 end | 91 end |
86 if err then error(err); end | 93 if err then error(err); end |
87 if not client then | 94 if not client then |
88 return oauth_error("invalid_client", "incorrect credentials"); | 95 return oauth_error("invalid_client", "incorrect credentials"); |
89 end | 96 end |
90 | 97 |
98 local granted_scopes = filter_scopes(granted_jid, params.scope); | |
99 | |
91 local code = uuid.generate(); | 100 local code = uuid.generate(); |
92 assert(codes:set(params.client_id .. "#" .. code, {issued = os.time(); granted_jid = granted_jid})); | 101 assert(codes:set(params.client_id .. "#" .. code, { |
102 issued = os.time(); | |
103 granted_jid = granted_jid; | |
104 granted_scopes = granted_scopes; | |
105 })); | |
93 | 106 |
94 local redirect = url.parse(params.redirect_uri); | 107 local redirect = url.parse(params.redirect_uri); |
95 local query = http.formdecode(redirect.query or ""); | 108 local query = http.formdecode(redirect.query or ""); |
96 if type(query) ~= "table" then query = {}; end | 109 if type(query) ~= "table" then query = {}; end |
97 table.insert(query, { name = "code", value = code }) | 110 table.insert(query, { name = "code", value = code }) |
139 module:log("debug", "authorization_code invalid or expired: %q", code); | 152 module:log("debug", "authorization_code invalid or expired: %q", code); |
140 return oauth_error("invalid_client", "incorrect credentials"); | 153 return oauth_error("invalid_client", "incorrect credentials"); |
141 end | 154 end |
142 assert(codes:set(client_owner, client_id .. "#" .. params.code, nil)); | 155 assert(codes:set(client_owner, client_id .. "#" .. params.code, nil)); |
143 | 156 |
144 return json.encode(new_access_token(code.granted_jid, nil, nil)); | 157 return json.encode(new_access_token(code.granted_jid, code.granted_scopes, nil)); |
145 end | 158 end |
146 | 159 |
147 local function check_credentials(request) | 160 local function check_credentials(request) |
148 local auth_type, auth_data = string.match(request.headers.authorization, "^(%S+)%s(.+)$"); | 161 local auth_type, auth_data = string.match(request.headers.authorization, "^(%S+)%s(.+)$"); |
149 | 162 |