Browse Source

Adds Prosody plugin for token authentication.

master
paweldomas 9 years ago
parent
commit
531b81cce3

+ 6
- 0
debian/control View File

@@ -32,3 +32,9 @@ Description: Prosody configuration for Jitsi Meet
32 32
  .
33 33
  This package contains configuration for Prosody to be used with
34 34
  Jitsi Meet.
35
+
36
+Package: jitsi-meet-tokens
37
+Architecture: all
38
+Depends: ${misc:Depends}, prosody | prosody-trunk, jitsi-meet-prosody
39
+Description: Prosody token authentication plugin for Jitsi Meet
40
+

+ 7
- 0
debian/jitsi-meet-tokens.README.Debian View File

@@ -0,0 +1,7 @@
1
+Token authentication plugin for Jitsi Meet
2
+----------------------------
3
+
4
+Jitsi Meet is a WebRTC video conferencing application. This package contains
5
+Prosody plugin which enables token authentication in Jitsi Meet installation.
6
+
7
+ -- Pawel Domas <pawel.domas@jitsi.org>  Mon, 2 Nov 2015 14:45:00 -0600

+ 10
- 0
debian/jitsi-meet-tokens.config View File

@@ -0,0 +1,10 @@
1
+#!/bin/sh -e
2
+
3
+# Source debconf library.
4
+. /usr/share/debconf/confmodule
5
+
6
+db_input critical jitsi-meet-tokens/appid || true
7
+db_go
8
+
9
+db_input critical jitsi-meet-tokens/appsecret || true
10
+db_go

+ 0
- 0
debian/jitsi-meet-tokens.docs View File


+ 1
- 0
debian/jitsi-meet-tokens.install View File

@@ -0,0 +1 @@
1
+prosody-plugins/     /usr/share/jitsi-meet/

+ 91
- 0
debian/jitsi-meet-tokens.postinst View File

@@ -0,0 +1,91 @@
1
+#!/bin/bash
2
+# postinst script for jitsi-meet-tokens
3
+#
4
+# see: dh_installdeb(1)
5
+
6
+set -e
7
+
8
+# summary of how this script can be called:
9
+#        * <postinst> `configure' <most-recently-configured-version>
10
+#        * <old-postinst> `abort-upgrade' <new version>
11
+#        * <conflictor's-postinst> `abort-remove' `in-favour' <package>
12
+#          <new-version>
13
+#        * <postinst> `abort-remove'
14
+#        * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
15
+#          <failed-install-package> <version> `removing'
16
+#          <conflicting-package> <version>
17
+# for details, see http://www.debian.org/doc/debian-policy/ or
18
+# the debian-policy package
19
+
20
+
21
+case "$1" in
22
+    configure)
23
+
24
+        if [ -f "/etc/jitsi/videobridge/config" ] ; then
25
+            . /etc/jitsi/videobridge/config
26
+        fi
27
+
28
+        if [ -f "/etc/jitsi/jicofo/config" ] ; then
29
+            . /etc/jitsi/jicofo/config
30
+        fi
31
+
32
+        # loading debconf
33
+        . /usr/share/debconf/confmodule
34
+
35
+        db_get jitsi-meet-tokens/appid
36
+        if [ "$RET" = "false" ] ; then
37
+            echo "Application ID is mandatory"
38
+            exit 1
39
+        fi
40
+        APP_ID=$RET
41
+
42
+        db_get jitsi-meet-tokens/appsecret
43
+        if [ "$RET" = "false" ] ; then
44
+            echo "Application secret is mandatory"
45
+        fi
46
+        APP_SECRET=$RET
47
+
48
+        # We can adjust Prosody config only if there is Jvb or Jicofo domain configured
49
+        PROSODY_HOST_CONFIG="/etc/prosody/conf.avail/$JVB_HOSTNAME.cfg.lua"
50
+        if [ ! -f "$PROSODY_HOST_CONFIG" ] ; then
51
+            PROSODY_HOST_CONFIG="/etc/prosody/conf.avail/$JICOFO_HOSTNAME.cfg.lua"
52
+        fi
53
+
54
+        # Store config filename for purge
55
+        db_set jitsi-meet-prosody/prosody_config $PROSODY_HOST_CONFIG
56
+
57
+        db_stop
58
+
59
+        if [ -f "$PROSODY_HOST_CONFIG" ] ; then
60
+            if grep -q "--plugin_paths" "$PROSODY_HOST_CONFIG"; then
61
+                # enable tokens in prosody host config
62
+                sed -i "s/--plugin_paths/plugin_paths/g" $PROSODY_HOST_CONFIG
63
+                sed -i 's/authentication = "anonymous"/authentication = "token"/g' $PROSODY_HOST_CONFIG
64
+                sed -i "s/--app_id=example_app_id/app_id=$APP_ID/g" $PROSODY_HOST_CONFIG
65
+                sed -i "s/--app_secret=example_app_secret/app_secret=$APP_SECRET/g" $PROSODY_HOST_CONFIG
66
+                sed -i 's/--modules_enabled = { "token_verification" }/modules_enabled = { "token_verification" }/g' $PROSODY_HOST_CONFIG
67
+
68
+            else
69
+                echo "Failed apply auto-config to $PROSODY_HOST_CONFIG which most likely comes from not supported version of jitsi-meet"
70
+            fi
71
+        else
72
+            echo "Prosody config not found at $PROSODY_HOST_CONFIG - unable to auto-configure token authentication"
73
+        fi
74
+	
75
+    ;;
76
+
77
+    abort-upgrade|abort-remove|abort-deconfigure)
78
+    ;;
79
+
80
+    *)
81
+        echo "postinst called with unknown argument \`$1'" >&2
82
+        exit 1
83
+    ;;
84
+esac
85
+
86
+# dh_installdeb will replace this with shell code automatically
87
+# generated by other debhelper scripts.
88
+
89
+#DEBHELPER#
90
+
91
+exit 0

+ 73
- 0
debian/jitsi-meet-tokens.postrm View File

@@ -0,0 +1,73 @@
1
+#!/bin/sh
2
+# postrm script for jitsi-meet-tokens
3
+#
4
+# see: dh_installdeb(1)
5
+
6
+set -e
7
+
8
+# summary of how this script can be called:
9
+#        * <postrm> `remove'
10
+#        * <postrm> `purge'
11
+#        * <old-postrm> `upgrade' <new-version>
12
+#        * <new-postrm> `failed-upgrade' <old-version>
13
+#        * <new-postrm> `abort-install'
14
+#        * <new-postrm> `abort-install' <old-version>
15
+#        * <new-postrm> `abort-upgrade' <old-version>
16
+#        * <disappearer's-postrm> `disappear' <overwriter>
17
+#          <overwriter-version>
18
+# for details, see http://www.debian.org/doc/debian-policy/ or
19
+# the debian-policy package
20
+
21
+# Load debconf
22
+. /usr/share/debconf/confmodule
23
+
24
+
25
+case "$1" in
26
+    remove)
27
+
28
+        db_get jitsi-meet-prosody/prosody_config
29
+        PROSODY_HOST_CONFIG=$RET
30
+
31
+        if [ -f "$PROSODY_HOST_CONFIG" ] ; then
32
+
33
+            db_get jitsi-meet-tokens/appid
34
+            APP_ID=$RET
35
+
36
+            db_get jitsi-meet-tokens/appsecret
37
+            APP_SECRET=$RET
38
+
39
+            # Revert prosody config
40
+            sed -i "s/plugin_paths/--plugin_paths/g" $PROSODY_HOST_CONFIG
41
+            sed -i 's/authentication = "token"/authentication = "anonymous"/g' $PROSODY_HOST_CONFIG
42
+            sed -i "s/app_id=$APP_ID/--app_id=example_app_id/g" $PROSODY_HOST_CONFIG
43
+            sed -i "s/app_secret=$APP_SECRET/--app_secret=example_app_secret/g" $PROSODY_HOST_CONFIG
44
+            sed -i 's/modules_enabled = { "token_verification" }/--modules_enabled = { "token_verification" }/g' $PROSODY_HOST_CONFIG
45
+
46
+            if [ -x "/etc/init.d/prosody" ]; then
47
+                invoke-rc.d prosody reload
48
+            fi
49
+        fi
50
+
51
+        db_stop
52
+    ;;
53
+
54
+    purge)
55
+    ;;
56
+
57
+    upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
58
+    ;;
59
+
60
+    *)
61
+        echo "postrm called with unknown argument \`$1'" >&2
62
+        exit 1
63
+    ;;
64
+esac
65
+
66
+# dh_installdeb will replace this with shell code automatically
67
+# generated by other debhelper scripts.
68
+
69
+#DEBHELPER#
70
+
71
+db_stop
72
+
73
+exit 0

+ 14
- 0
debian/jitsi-meet-tokens.templates View File

@@ -0,0 +1,14 @@
1
+Template: jitsi-meet-tokens/appid
2
+Type: string
3
+_Description: The application ID to be used by token authentication plugin:
4
+  Application ID:
5
+
6
+Template: jitsi-meet-tokens/appsecret
7
+Type: password
8
+_Description: The application secret to be used by token authentication plugin:
9
+  Application secret:
10
+
11
+Template: jitsi-meet-prosody/prosody_config
12
+Type: string
13
+_Description: The location of Jitsi Meet Prosody config file
14
+  Jitsi-meet Prosody config file location:

+ 9
- 1
doc/debian/jitsi-meet-prosody/prosody.cfg.lua-jvb.example View File

@@ -1,6 +1,13 @@
1
+-- Plugins path gets uncommented during jitsi-meet-tokens package install - that's where token plugin is located
2
+--plugin_paths = { "/usr/share/jitsi-meet/prosody-plugins/" }
3
+
1 4
 VirtualHost "jitmeet.example.com"
2 5
         -- enabled = false -- Remove this line to enable this host
3 6
         authentication = "anonymous"
7
+        -- Two properties below get uncommented by jitsi-meet-tokens package config
8
+        -- and authentication above is switched to "token"
9
+        --app_id=example_app_id
10
+        --app_secret=example_app_secret
4 11
         -- Assign this host a certificate for TLS, otherwise it would use the one
5 12
         -- set in the global section (if any).
6 13
         -- Note that old-style SSL on port 5223 only supports one certificate, and will always
@@ -17,13 +24,14 @@ VirtualHost "jitmeet.example.com"
17 24
         }
18 25
 
19 26
 Component "conference.jitmeet.example.com" "muc"
27
+    --modules_enabled = { "token_verification" }
20 28
 admins = { "focusUser@auth.jitmeet.example.com" }
21 29
 
22 30
 Component "jitsi-videobridge.jitmeet.example.com"
23 31
     component_secret = "jitmeetSecret"
24 32
 
25 33
 VirtualHost "auth.jitmeet.example.com"
26
-        authentication = "internal_plain"
34
+    authentication = "internal_plain"
27 35
 
28 36
 Component "focus.jitmeet.example.com"
29 37
     component_secret = "focusSecret"

+ 75
- 0
prosody-plugins/mod_auth_token.lua View File

@@ -0,0 +1,75 @@
1
+-- Token authentication
2
+-- Copyright (C) 2015 Atlassian
3
+
4
+local usermanager = require "core.usermanager";
5
+local new_sasl = require "util.sasl".new;
6
+
7
+local log = module._log;
8
+local host = module.host;
9
+
10
+local token_util = module:require "token/util";
11
+
12
+-- define auth provider
13
+local provider = {};
14
+
15
+--do
16
+--	local list;
17
+--	for mechanism in pairs(new_sasl(module.host):mechanisms()) do
18
+--		list = (not(list) and mechanism) or (list..", "..mechanism);
19
+--	end
20
+--	if not list then
21
+--		module:log("error", "No mechanisms");
22
+--	else
23
+--		module:log("error", "Mechanisms: %s", list);
24
+--	end
25
+--end
26
+
27
+
28
+local appId = module:get_option_string("app_id");
29
+local appSecret = module:get_option_string("app_secret");
30
+local tokenLifetime = module:get_option_number("token_lifetime");
31
+
32
+function provider.test_password(username, password)
33
+	local result, msg = token_util.verify_password(password, appId, appSecret, tokenLifetime);
34
+	if result == true then
35
+		return true;
36
+	else
37
+		log("error", "Token auth failed for user %s, reason: %s",username, msg);
38
+		return nil, msg;
39
+	end
40
+end
41
+
42
+function provider.get_password(username)
43
+	return nil;
44
+end
45
+
46
+function provider.set_password(username, password)
47
+	return nil, "Set password not supported";
48
+end
49
+
50
+function provider.user_exists(username)
51
+	return nil;
52
+end
53
+
54
+function provider.users()
55
+	return next, hosts[module.host].sessions, nil;
56
+end
57
+
58
+function provider.create_user(username, password)
59
+	return nil;
60
+end
61
+
62
+function provider.delete_user(username)
63
+	return nil;
64
+end
65
+
66
+function provider.get_sasl_handler()
67
+	local testpass_authentication_profile = {
68
+		plain_test = function(sasl, username, password, realm)
69
+			return usermanager.test_password(username, realm, password), true;
70
+		end
71
+	};
72
+	return new_sasl(host, testpass_authentication_profile);
73
+end
74
+
75
+module:provides("auth", provider);

+ 52
- 0
prosody-plugins/mod_token_verification.lua View File

@@ -0,0 +1,52 @@
1
+-- Token authentication
2
+-- Copyright (C) 2015 Atlassian
3
+
4
+local log = module._log;
5
+local host = module.host;
6
+local st = require "util.stanza";
7
+local token_util = module:require("token/util");
8
+local is_admin = require "core.usermanager".is_admin;
9
+
10
+
11
+local parentHostName = string.gmatch(tostring(host), "%w+.(%w.+)")();
12
+if parentHostName == nil then
13
+	log("error", "Failed to start - unable to get parent hostname");
14
+	return;
15
+end
16
+
17
+local parentCtx = module:context(parentHostName);
18
+if parentCtx == nil then
19
+	log("error", "Failed to start - unable to get parent context for host: %s", tostring(parentHostName));
20
+	return;
21
+end
22
+
23
+local appId = parentCtx:get_option_string("app_id");
24
+local appSecret = parentCtx:get_option_string("app_secret");
25
+local tokenLifetime = parentCtx:get_option_string("token_lifetime");
26
+
27
+log("debug", "%s - starting MUC token verifier app_id: %s app_secret: %s token-lifetime: %s",
28
+	tostring(host), tostring(appId), tostring(appSecret), tostring(tokenLifetime));
29
+
30
+local function handle_pre_create(event)
31
+	local origin, stanza = event.origin, event.stanza;	
32
+	local token = stanza:get_child("token", "http://jitsi.org/jitmeet/auth-token");
33
+	-- token not required for admin users
34
+	local user_jid = stanza.attr.from;	
35
+	if is_admin(user_jid) then
36
+		log("debug", "Token not required from admin user: %s", user_jid);
37
+		return nil;
38
+	end
39
+	log("debug", "Will verify token for user: %s ", user_jid);
40
+	if token ~= nil then
41
+		token = token[1];
42
+	end
43
+	local result, msg = token_util.verify_password(token, appId, appSecret, tokenLifetime);
44
+	if result ~= true then
45
+		log("debug", "Token verification failed: %s", msg);
46
+		origin.send(st.error_reply(stanza, "cancel", "not-allowed", msg));
47
+		return true;
48
+	end
49
+end
50
+
51
+module:hook("muc-room-pre-create", handle_pre_create);
52
+

+ 76
- 0
prosody-plugins/token/util.lib.lua View File

@@ -0,0 +1,76 @@
1
+-- Token authentication
2
+-- Copyright (C) 2015 Atlassian
3
+
4
+local hashes = require "util.hashes";
5
+
6
+local _M = {};
7
+
8
+local function calc_hash(password, appId, appSecret)
9
+	local hash, room, ts = string.match(password, "(%w+)_(%w+)_(%d+)");
10
+	if hash ~= nil and room ~= nil and ts ~= nil then
11
+		log("debug", "Hash: '%s' room: '%s', ts: '%s'", hash, room, ts);
12
+                local toHash = room .. ts .. appId .. appSecret;
13
+		log("debug", "to be hashed: '%s'", toHash);
14
+		local hash = hashes.sha256(toHash, true);
15
+		log("debug", "hash: '%s'", hash);
16
+		return hash;
17
+	else
18
+		log("error", "Invalid password format: '%s'", password);
19
+		return nil;
20
+	end
21
+end
22
+
23
+local function extract_hash(password)
24
+	local hash, room, ts = string.match(password, "(%w+)_(%w+)_(%d+)");
25
+	return hash;
26
+end
27
+
28
+local function extract_ts(password)
29
+	local hash, room, ts = string.match(password, "(%w+)_(%w+)_(%d+)");
30
+	return ts;
31
+end
32
+
33
+local function get_utc_timestamp()
34
+        return os.time(os.date("!*t")) * 1000;
35
+end
36
+
37
+local function verify_timestamp(ts, tokenLifetime)
38
+	return get_utc_timestamp() - ts <= tokenLifetime;
39
+end
40
+
41
+local function verify_password_impl(password, appId, appSecret, tokenLifetime)
42
+
43
+	if password == nil then
44
+   		return nil, "password is missing";
45
+        end
46
+
47
+	if tokenLifetime == nil then
48
+		tokenLifetime = 24 * 60 * 60 * 1000;
49
+	end
50
+
51
+	local ts = extract_ts(password);	
52
+	if ts == nil then
53
+		return nil, "timestamp not found in the password";
54
+	end
55
+       	local os_ts = get_utc_timestamp();
56
+	log("debug", "System TS: '%s' user TS: %s", tostring(os_ts), tostring(ts));
57
+	local isValid = verify_timestamp(ts, tokenLifetime);
58
+	if not isValid then
59
+		return nil, "token expired";
60
+	end
61
+
62
+	local realHash = calc_hash(password, appId, appSecret);
63
+	local givenhash = extract_hash(password);
64
+        log("debug", "Compare '%s' to '%s'", tostring(realHash), tostring(givenhash));
65
+	if realHash == givenhash then
66
+		return true;
67
+	else
68
+		return nil, "invalid hash";
69
+	end
70
+end
71
+
72
+function _M.verify_password(password, appId, appSecret, tokenLifetime)
73
+	return verify_password_impl(password, appId, appSecret, tokenLifetime);
74
+end
75
+
76
+return _M;

Loading…
Cancel
Save