util/sasl/oauthbearer.lua
author Kim Alvefur <zash@zash.se>
Thu, 02 Mar 2023 14:37:46 +0100
changeset 12922 ed20555f163a
parent 12915 ab1164eda011
child 12940 b796e08e6376
permissions -rw-r--r--
util.sasl.oauthbearer: Fix traceback on authz in unexpected format E.g. if you were to just pass "username" without @hostname, the split will return nil, "username" and the nil gets passed to saslprep() and it does not like that.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
12915
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     1
local saslprep = require "util.encodings".stringprep.saslprep;
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     2
local nodeprep = require "util.encodings".stringprep.nodeprep;
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     3
local jid = require "util.jid";
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     4
local json = require "util.json";
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     5
local log = require "util.logger".init("sasl");
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     6
local _ENV = nil;
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     7
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     8
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     9
local function oauthbearer(self, message)
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    10
	if not message then
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    11
		return "failure", "malformed-request";
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    12
	end
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    13
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    14
	if message == "\001" then
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    15
		return "failure", "not-authorized";
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    16
	end
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    17
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    18
	local gs2_authzid, kvpairs = message:match("n,a=([^,]+),(.+)$");
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    19
	if not gs2_authzid then
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    20
		return "failure", "malformed-request";
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    21
	end
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    22
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    23
	local auth_header;
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    24
	for k, v in kvpairs:gmatch("([a-zA-Z]+)=([\033-\126 \009\r\n]*)\001") do
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    25
		if k == "auth" then
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    26
			auth_header = v;
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    27
			break;
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    28
		end
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    29
	end
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    30
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    31
	if not auth_header then
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    32
		return "failure", "malformed-request";
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    33
	end
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    34
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    35
	local username = jid.prepped_split(gs2_authzid);
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    36
12922
ed20555f163a util.sasl.oauthbearer: Fix traceback on authz in unexpected format
Kim Alvefur <zash@zash.se>
parents: 12915
diff changeset
    37
	if not username or username == "" then
ed20555f163a util.sasl.oauthbearer: Fix traceback on authz in unexpected format
Kim Alvefur <zash@zash.se>
parents: 12915
diff changeset
    38
		return "failure", "malformed-request", "Expected authorization identity in the username@hostname format";
ed20555f163a util.sasl.oauthbearer: Fix traceback on authz in unexpected format
Kim Alvefur <zash@zash.se>
parents: 12915
diff changeset
    39
	end
ed20555f163a util.sasl.oauthbearer: Fix traceback on authz in unexpected format
Kim Alvefur <zash@zash.se>
parents: 12915
diff changeset
    40
12915
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    41
	-- SASLprep username
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    42
	username = saslprep(username);
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    43
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    44
	if not username or username == "" then
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    45
		log("debug", "Username violates SASLprep.");
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    46
		return "failure", "malformed-request", "Invalid username.";
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    47
	end
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    48
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    49
	local _nodeprep = self.profile.nodeprep;
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    50
	if _nodeprep ~= false then
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    51
		username = (_nodeprep or nodeprep)(username);
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    52
		if not username or username == "" then
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    53
			return "failure", "malformed-request", "Invalid username or password."
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    54
		end
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    55
	end
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    56
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    57
	self.username = username;
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    58
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    59
	local token = auth_header:match("^Bearer (.+)$");
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    60
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    61
	local correct, state, token_info = self.profile.oauthbearer(self, username, token, self.realm);
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    62
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    63
	if state == false then
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    64
		return "failure", "account-disabled";
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    65
	elseif state == nil or not correct then
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    66
		-- For token-level errors, RFC 7628 demands use of a JSON-encoded
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    67
		-- challenge response upon failure. We relay additional info from
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    68
		-- the auth backend if available.
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    69
		return "challenge", json.encode({
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    70
			status = token_info and token_info.status or "invalid_token";
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    71
			scope = token_info and token_info.scope or nil;
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    72
			["openid-configuration"] = token_info and token_info.oidc_discovery_url or nil;
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    73
		});
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    74
	end
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    75
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    76
	self.resource = token_info.resource;
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    77
	self.role = token_info.role;
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    78
	return "success";
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    79
end
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    80
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    81
local function init(registerMechanism)
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    82
	registerMechanism("OAUTHBEARER", {"oauthbearer"}, oauthbearer);
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    83
end
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    84
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    85
return {
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    86
	init = init;
ab1164eda011 util.sasl: Add SASL OAUTHBEARER mechanism (RFC 7628)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    87
}