Browse Source

Add basic ASAP support to mod_auth_token

See: http://s2sauth.bitbucket.org/
j8
Sam Whited 9 years ago
parent
commit
7f2fa9597c
2 changed files with 68 additions and 33 deletions
  1. 65
    14
      prosody-plugins/mod_auth_token.lua
  2. 3
    19
      prosody-plugins/token/util.lib.lua

+ 65
- 14
prosody-plugins/mod_auth_token.lua View File

@@ -1,10 +1,17 @@
1 1
 -- Token authentication
2 2
 -- Copyright (C) 2015 Atlassian
3 3
 
4
+local basexx = require 'basexx'
5
+local have_async, async = pcall(require, "util.async");
6
+local formdecode = require "util.http".formdecode;
4 7
 local generate_uuid = require "util.uuid".generate;
8
+local http = require "net.http";
9
+local json = require 'cjson'
10
+json.encode_empty_table('array')
5 11
 local new_sasl = require "util.sasl".new;
12
+local path = require "util.paths";
6 13
 local sasl = require "util.sasl";
7
-local formdecode = require "util.http".formdecode;
14
+local timer = require "util.timer";
8 15
 local token_util = module:require "token/util";
9 16
 
10 17
 -- define auth provider
@@ -14,6 +21,7 @@ local host = module.host;
14 21
 
15 22
 local appId = module:get_option_string("app_id");
16 23
 local appSecret = module:get_option_string("app_secret");
24
+local asapKeyServer = module:get_option_string("asap_key_server");
17 25
 local allowEmptyToken = module:get_option_boolean("allow_empty_token");
18 26
 local disableRoomNameConstraints = module:get_option_boolean("disable_room_name_constraints");
19 27
 
@@ -26,8 +34,13 @@ if appId == nil then
26 34
 	return;
27 35
 end
28 36
 
29
-if appSecret == nil then
30
-	module:log("error", "'app_secret' must not be empty");
37
+if appSecret == nil and asapKeyServer == nil then
38
+	module:log("error", "'app_secret' or 'asap_key_server' must be specified");
39
+	return;
40
+end
41
+
42
+if asapKeyServer and not have_async then
43
+	module:log("error", "requires a version of Prosody with util.async");
31 44
 	return;
32 45
 end
33 46
 
@@ -64,6 +77,34 @@ function provider.delete_user(username)
64 77
 	return nil;
65 78
 end
66 79
 
80
+local http_timeout = 30;
81
+local http_headers = {
82
+	["User-Agent"] = "Prosody ("..prosody.version.."; "..prosody.platform..")"
83
+};
84
+
85
+-- TODO: This *needs* to be memoized before going to prod.
86
+function get_public_key(keyId)
87
+	local wait, done = async.waiter();
88
+	local content, code; --, request, response;
89
+	local function cb(content_, code_, response_, request_)
90
+		content, code = content_, code_;
91
+		done();
92
+	end
93
+	local request = http.request(path.join(asapKeyServer, keyId), {
94
+		headers = http_headers or {},
95
+		method = "GET"
96
+	}, cb);
97
+	-- TODO: Is the done() call racey?
98
+	timer.add_task(http_timeout, function() http.destroy_request(request); done(); end);
99
+	wait();
100
+
101
+	if code == 200 or code == 204 then
102
+		return content;
103
+	end
104
+
105
+	return nil
106
+end
107
+
67 108
 function provider.get_sasl_handler(session)
68 109
 	-- JWT token extracted from BOSH URL
69 110
 	local token = session.auth_token;
@@ -71,25 +112,35 @@ function provider.get_sasl_handler(session)
71 112
 	local function get_username_from_token(self, message)
72 113
 
73 114
 		if token == nil then
74
-			if allowEmptyToken == true then
75
-				return true;
115
+			if allowEmptyToken then
116
+				return true
76 117
 			else
77 118
 				return false, "not-allowed", "token required";
78 119
 			end
79 120
 		end
80 121
 
81
-		-- here we check if 'room' claim exists
82
-		local room, roomErr = token_util.get_room_name(token, appSecret);
83
-		if room == nil and disableRoomNameConstraints ~= true then
84
-            if roomErr == nil then
85
-                roomErr = "'room' claim is missing";
86
-            end
87
-			return false, "not-allowed", roomErr;
122
+		local pubKey;
123
+		if asapKeyServer and session.auth_token ~= nil then
124
+			local dotFirst = session.auth_token:find("%.")
125
+			if not dotFirst then return nil, "Invalid token" end
126
+			local header = json.decode(basexx.from_url64(session.auth_token:sub(1,dotFirst-1)))
127
+			local kid = header["kid"]
128
+			if kid == nil then
129
+				return false, "not-allowed", "'kid' claim is missing";
130
+			end
131
+			pubKey = get_public_key(kid);
132
+			if pubKey == nil then
133
+				return false, "not-allowed", "could not obtain public key";
134
+			end
88 135
 		end
89 136
 
90 137
 		-- now verify the whole token
91
-		local result, msg
92
-		= token_util.verify_token(token, appId, appSecret, room, disableRoomNameConstraints);
138
+		local result, msg;
139
+		if asapKeyServer then
140
+			result, msg = token_util.verify_token(token, appId, pubKey, disableRoomNameConstraints);
141
+		else
142
+			result, msg = token_util.verify_token(token, appId, appSecret, disableRoomNameConstraints);
143
+		end
93 144
 		if result == true then
94 145
 			-- Binds room name to the session which is later checked on MUC join
95 146
 			session.jitsi_meet_room = room;

+ 3
- 19
prosody-plugins/token/util.lib.lua View File

@@ -5,16 +5,7 @@ local jwt = require "luajwtjitsi";
5 5
 
6 6
 local _M = {};
7 7
 
8
-local function _get_room_name(token, appSecret)
9
-	local claims, err = jwt.decode(token, appSecret);
10
-	if claims ~= nil then
11
-		return claims["room"];
12
-	else
13
-		return nil, err;
14
-	end
15
-end
16
-
17
-local function _verify_token(token, appId, appSecret, roomName, disableRoomNameConstraints)
8
+local function _verify_token(token, appId, appSecret, disableRoomNameConstraints)
18 9
 
19 10
 	local claims, err = jwt.decode(token, appSecret, true);
20 11
 	if claims == nil then
@@ -38,19 +29,12 @@ local function _verify_token(token, appId, appSecret, roomName, disableRoomNameC
38 29
 	if roomClaim == nil and disableRoomNameConstraints ~= true then
39 30
 		return nil, "'room' claim is missing";
40 31
 	end
41
-	if roomName ~= nil and roomName ~= roomClaim and disableRoomNameConstraints ~= true then
42
-		return nil, "Invalid room name('room' claim)";
43
-	end
44 32
 
45 33
 	return true;
46 34
 end
47 35
 
48
-function _M.verify_token(token, appId, appSecret, roomName, disableRoomNameConstraints)
49
-	return _verify_token(token, appId, appSecret, roomName, disableRoomNameConstraints);
50
-end
51
-
52
-function _M.get_room_name(token, appSecret)
53
-	return _get_room_name(token, appSecret);
36
+function _M.verify_token(token, appId, appSecret, disableRoomNameConstraints)
37
+	return _verify_token(token, appId, appSecret, disableRoomNameConstraints);
54 38
 end
55 39
 
56 40
 return _M;

Loading…
Cancel
Save