File

util/sasl/oauthbearer.lua @ 13134:638f627e707f

util.datamanager: Add O(1) list indexing with on-disk index Index file contains offsets and lengths of each item() which allows seeking directly to each item and reading it without parsing the entire file. Also allows tricks like binary search, assuming items have some defined order. We take advantage of the 1-based indexing in tables to store a magic header in the 0 position, so that table index 1 ends up at file index 1.
author Kim Alvefur <zash@zash.se>
date Tue, 11 May 2021 02:09:56 +0200
parent 13112:b6aaab0846fe
line wrap: on
line source

local json = require "prosody.util.json";
local _ENV = nil;


local function oauthbearer(self, message)
	if not message then
		return "failure", "malformed-request";
	end

	if message == "\001" then
		return "failure", "not-authorized";
	end

	-- gs2-header kvsep *kvpair kvsep
	local gs2_header, kvpairs = message:match("^(n,[^,]*,)\001(.+)\001$");
	if not gs2_header then
		return "failure", "malformed-request";
	end
	local gs2_authzid = gs2_header:match("^[^,]*,a=([^,]*),$");

	-- key "=" value kvsep
	local auth_header;
	for k, v in kvpairs:gmatch("([a-zA-Z]+)=([\033-\126 \009\r\n]*)\001") do
		if k == "auth" then
			auth_header = v;
			break;
		end
	end

	if not auth_header then
		return "failure", "malformed-request";
	end

	local token = auth_header:match("^Bearer (.+)$");

	local username, state, token_info = self.profile.oauthbearer(self, token, self.realm, gs2_authzid);

	if state == false then
		return "failure", "account-disabled";
	elseif state == nil or not username then
		-- For token-level errors, RFC 7628 demands use of a JSON-encoded
		-- challenge response upon failure. We relay additional info from
		-- the auth backend if available.
		return "challenge", json.encode({
			status = token_info and token_info.status or "invalid_token";
			scope = token_info and token_info.scope or nil;
			["openid-configuration"] = token_info and token_info.oidc_discovery_url or nil;
		});
	end
	self.username = username;
	self.token_info = token_info;

	return "success";
end

local function init(registerMechanism)
	registerMechanism("OAUTHBEARER", {"oauthbearer"}, oauthbearer);
end

return {
	init = init;
}