Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

mod_auth_token.lua 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. -- Token authentication
  2. -- Copyright (C) 2015 Atlassian
  3. local basexx = require 'basexx';
  4. local have_async, async = pcall(require, "util.async");
  5. local formdecode = require "util.http".formdecode;
  6. local generate_uuid = require "util.uuid".generate;
  7. local http = require "net.http";
  8. local json = require 'cjson'
  9. json.encode_empty_table('array')
  10. local new_sasl = require "util.sasl".new;
  11. local path = require "util.paths";
  12. local sasl = require "util.sasl";
  13. local timer = require "util.timer";
  14. local token_util = module:require "token/util";
  15. -- define auth provider
  16. local provider = {};
  17. local host = module.host;
  18. local appId = module:get_option_string("app_id");
  19. local appSecret = module:get_option_string("app_secret");
  20. local asapKeyServer = module:get_option_string("asap_key_server");
  21. local allowEmptyToken = module:get_option_boolean("allow_empty_token");
  22. local disableRoomNameConstraints = module:get_option_boolean("disable_room_name_constraints");
  23. -- TODO: Figure out a less arbitrary default cache size.
  24. local cacheSize = module:get_option_number("jwt_pubkey_cache_size", 128);
  25. local cache = require"util.cache".new(cacheSize);
  26. if allowEmptyToken == true then
  27. module:log("warn", "WARNING - empty tokens allowed");
  28. end
  29. if appId == nil then
  30. module:log("error", "'app_id' must not be empty");
  31. return;
  32. end
  33. if appSecret == nil and asapKeyServer == nil then
  34. module:log("error", "'app_secret' or 'asap_key_server' must be specified");
  35. return;
  36. end
  37. if asapKeyServer and not have_async then
  38. module:log("error", "requires a version of Prosody with util.async");
  39. return;
  40. end
  41. -- Extract 'token' param from BOSH URL when session is created
  42. module:hook("bosh-session", function(event)
  43. local session, request = event.session, event.request;
  44. local query = request.url.query;
  45. if query ~= nil then
  46. session.auth_token = query and formdecode(query).token or nil;
  47. end
  48. end)
  49. function provider.test_password(username, password)
  50. return nil, "Password based auth not supported";
  51. end
  52. function provider.get_password(username)
  53. return nil;
  54. end
  55. function provider.set_password(username, password)
  56. return nil, "Set password not supported";
  57. end
  58. function provider.user_exists(username)
  59. return nil;
  60. end
  61. function provider.create_user(username, password)
  62. return nil;
  63. end
  64. function provider.delete_user(username)
  65. return nil;
  66. end
  67. local http_timeout = 30;
  68. local http_headers = {
  69. ["User-Agent"] = "Prosody ("..prosody.version.."; "..prosody.platform..")"
  70. };
  71. function get_public_key(keyId)
  72. local content = cache:get(keyId);
  73. if content == nil then
  74. -- If the key is not found in the cache.
  75. module:log("debug", "Cache miss for key: "..keyId);
  76. local code;
  77. local wait, done = async.waiter();
  78. local function cb(content_, code_, response_, request_)
  79. content, code = content_, code_;
  80. done();
  81. end
  82. local request = http.request(path.join(asapKeyServer, keyId), {
  83. headers = http_headers or {},
  84. method = "GET"
  85. }, cb);
  86. -- TODO: Is the done() call racey?
  87. timer.add_task(http_timeout, function() http.destroy_request(request); done(); end);
  88. wait();
  89. if code == 200 or code == 204 then
  90. module:log("debug", "Cache hit for key: "..keyId);
  91. return content;
  92. end
  93. else
  94. -- If the key is in the cache, use it.
  95. return content;
  96. end
  97. return nil
  98. end
  99. function provider.get_sasl_handler(session)
  100. -- JWT token extracted from BOSH URL
  101. local token = session.auth_token;
  102. local function get_username_from_token(self, message)
  103. if token == nil then
  104. if allowEmptyToken then
  105. return true
  106. else
  107. return false, "not-allowed", "token required";
  108. end
  109. end
  110. local pubKey;
  111. if asapKeyServer and session.auth_token ~= nil then
  112. local dotFirst = session.auth_token:find("%.")
  113. if not dotFirst then return nil, "Invalid token" end
  114. local header = json.decode(basexx.from_url64(session.auth_token:sub(1,dotFirst-1)))
  115. local kid = header["kid"]
  116. if kid == nil then
  117. return false, "not-allowed", "'kid' claim is missing";
  118. end
  119. pubKey = get_public_key(kid);
  120. if pubKey == nil then
  121. return false, "not-allowed", "could not obtain public key";
  122. end
  123. end
  124. -- now verify the whole token
  125. local result, msg;
  126. if asapKeyServer then
  127. result, msg = token_util.verify_token(token, appId, pubKey, disableRoomNameConstraints);
  128. else
  129. result, msg = token_util.verify_token(token, appId, appSecret, disableRoomNameConstraints);
  130. end
  131. if result == true then
  132. -- Binds room name to the session which is later checked on MUC join
  133. session.jitsi_meet_room = room;
  134. return true
  135. else
  136. return false, "not-allowed", msg
  137. end
  138. end
  139. return new_sasl(host, { anonymous = get_username_from_token });
  140. end
  141. module:provides("auth", provider);
  142. local function anonymous(self, message)
  143. local username = generate_uuid();
  144. -- This calls the handler created in 'provider.get_sasl_handler(session)'
  145. local result, err, msg = self.profile.anonymous(self, username, self.realm);
  146. self.username = username;
  147. if result == true then
  148. return "success"
  149. else
  150. return "failure", err, msg
  151. end
  152. end
  153. sasl.registerMechanism("ANONYMOUS", {"anonymous"}, anonymous);