From 38fc1c01d4c56a95d2fe6215e01e0127fdf8eb34 Mon Sep 17 00:00:00 2001 From: paweldomas Date: Mon, 11 Jul 2016 13:44:49 +0200 Subject: [PATCH 1/2] Move XMPP login prompt handling to AuthHandler --- connection.js | 32 ++----------------- modules/UI/authentication/AuthHandler.js | 39 ++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 32 deletions(-) diff --git a/connection.js b/connection.js index 5add17e48..94f73e5e4 100644 --- a/connection.js +++ b/connection.js @@ -1,6 +1,5 @@ /* global APP, JitsiMeetJS, config */ -//FIXME: -import LoginDialog from './modules/UI/authentication/LoginDialog'; +import AuthHandler from './modules/UI/authentication/AuthHandler'; const ConnectionEvents = JitsiMeetJS.events.connection; const ConnectionErrors = JitsiMeetJS.errors.connection; @@ -92,33 +91,6 @@ function connect(id, password, roomName) { }); } -/** - * Show Authentication Dialog and try to connect with new credentials. - * If failed to connect because of PASSWORD_REQUIRED error - * then ask for password again. - * @param {string} [roomName] - * @returns {Promise} - */ -function requestAuth(roomName) { - return new Promise(function (resolve, reject) { - let authDialog = LoginDialog.showAuthDialog( - function (id, password) { - connect(id, password, roomName).then(function (connection) { - authDialog.close(); - resolve(connection); - }, function (err) { - if (err === ConnectionErrors.PASSWORD_REQUIRED) { - authDialog.displayError(err); - } else { - authDialog.close(); - reject(err); - } - }); - } - ); - }); -} - /** * Open JitsiConnection using provided credentials. * If retry option is true it will show auth dialog on PASSWORD_REQUIRED error. @@ -157,7 +129,7 @@ export function openConnection({id, password, retry, roomName}) { if (config.token) { throw err; } else { - return requestAuth(roomName); + return AuthHandler.requestAuth(roomName, connect); } } else { throw err; diff --git a/modules/UI/authentication/AuthHandler.js b/modules/UI/authentication/AuthHandler.js index fc321af3a..98586d13c 100644 --- a/modules/UI/authentication/AuthHandler.js +++ b/modules/UI/authentication/AuthHandler.js @@ -1,11 +1,11 @@ -/* global JitsiMeetJS, APP */ +/* global APP, config, JitsiMeetJS, Promise */ import LoginDialog from './LoginDialog'; -import UIEvents from '../../../service/UI/UIEvents'; import UIUtil from '../util/UIUtil'; import {openConnection} from '../../../connection'; const ConferenceEvents = JitsiMeetJS.events.conference; +const ConnectionErrors = JitsiMeetJS.errors.connection; let externalAuthWindow; let authRequiredDialog; @@ -157,10 +157,45 @@ function closeAuth() { } } +function showXmppPasswordPrompt(roomName, connect) { + return new Promise(function (resolve, reject) { + let authDialog = LoginDialog.showAuthDialog( + function (id, password) { + connect(id, password, roomName).then(function (connection) { + authDialog.close(); + resolve(connection); + }, function (err) { + if (err === ConnectionErrors.PASSWORD_REQUIRED) { + authDialog.displayError(err); + } else { + authDialog.close(); + reject(err); + } + }); + } + ); + }); +} + +/** + * Show Authentication Dialog and try to connect with new credentials. + * If failed to connect because of PASSWORD_REQUIRED error + * then ask for password again. + * @param {string} [roomName] name of the conference room + * @param {function(id, password, roomName)} [connect] function that returns + * a Promise which resolves with JitsiConnection or fails with one of + * ConnectionErrors. + * @returns {Promise} + */ +function requestAuth(roomName, connect) { + return showXmppPasswordPrompt(roomName, connect); +} + export default { authenticate, requireAuth, + requestAuth, closeAuth, logout }; From f977030bd6bc9d656e057756653a68c293076ee1 Mon Sep 17 00:00:00 2001 From: paweldomas Date: Mon, 11 Jul 2016 13:46:11 +0200 Subject: [PATCH 2/2] Add support for JWT login service --- modules/UI/authentication/AuthHandler.js | 106 +++++++++++++++++++++-- 1 file changed, 101 insertions(+), 5 deletions(-) diff --git a/modules/UI/authentication/AuthHandler.js b/modules/UI/authentication/AuthHandler.js index 98586d13c..5c9288346 100644 --- a/modules/UI/authentication/AuthHandler.js +++ b/modules/UI/authentication/AuthHandler.js @@ -10,6 +10,11 @@ const ConnectionErrors = JitsiMeetJS.errors.connection; let externalAuthWindow; let authRequiredDialog; +let isTokenAuthEnabled + = typeof config.tokenAuthUrl === "string" && config.tokenAuthUrl.length; +let getTokenAuthUrl + = JitsiMeetJS.util.AuthUtil.getTokenAuthUrl.bind(null, config.tokenAuthUrl); + /** * Authenticate using external service or just focus * external auth window if there is one already. @@ -23,19 +28,103 @@ function doExternalAuth (room, lockPassword) { return; } if (room.isJoined()) { - room.getExternalAuthUrl(true).then(function (url) { + let getUrl; + if (isTokenAuthEnabled) { + getUrl = Promise.resolve(getTokenAuthUrl(room.getName(), true)); + initJWTTokenListener(room); + } else { + getUrl = room.getExternalAuthUrl(true); + } + getUrl.then(function (url) { externalAuthWindow = LoginDialog.showExternalAuthDialog( url, function () { externalAuthWindow = null; - room.join(lockPassword); + if (!isTokenAuthEnabled) { + room.join(lockPassword); + } } ); }); } else { // If conference has not been started yet // then redirect to login page - room.getExternalAuthUrl().then(UIUtil.redirect); + if (isTokenAuthEnabled) { + redirectToTokenAuthService(room.getName()); + } else { + room.getExternalAuthUrl().then(UIUtil.redirect); + } + } +} + +/** + * Redirect the user to the token authentication service for the login to be + * performed. Once complete it is expected that the service wil bring the user + * back with "?jwt={the JWT token}" query parameter added. + * @param {string} [roomName] the name of the conference room. + */ +function redirectToTokenAuthService(roomName) { + UIUtil.redirect(getTokenAuthUrl(roomName, false)); +} + +/** + * Initializes 'message' listener that will wait for a JWT token to be received + * from the token authentication service opened in a popup window. + * @param room the name fo the conference room. + */ +function initJWTTokenListener(room) { + var self = this; + var listener = function (event) { + if (externalAuthWindow !== event.source) { + console.warn("Ignored message not coming " + + "from external authnetication window"); + return; + } + if (event.data && event.data.jwtToken) { + config.token = event.data.jwtToken; + console.info("Received JWT token:", config.token); + var roomName = room.getName(); + openConnection({retry: false, roomName: roomName }) + .then(function (connection) { + // Start new connection + let newRoom = connection.initJitsiConference( + roomName, APP.conference._getConferenceOptions()); + // Authenticate from the new connection to get + // the session-ID from the focus, which wil then be used + // to upgrade current connection's user role + newRoom.room.moderator.authenticate().then(function () { + connection.disconnect(); + // At this point we'll have session-ID stored in + // the settings. It wil be used in the call below + // to upgrade user's role + room.room.moderator.authenticate() + .then(function () { + console.info("User role upgrade done !"); + unregister(); + }).catch(function (err, errCode) { + console.error( + "Authentication failed: ", err, errCode); + unregister(); + } + ); + }).catch(function (error, code) { + unregister(); + connection.disconnect(); + console.error( + 'Authentication failed on the new connection', + error, code); + }); + }, function (err) { + unregister(); + console.error("Failed to open new connection", err); + }); + } + }; + var unregister = function () { + window.removeEventListener("message", listener); + }; + if (window.addEventListener) { + window.addEventListener("message", listener, false); } } @@ -100,7 +189,7 @@ function doXmppAuth (room, lockPassword) { * @param {string} [lockPassword] password to use if the conference is locked */ function authenticate (room, lockPassword) { - if (room.isExternalAuthEnabled()) { + if (isTokenAuthEnabled || room.isExternalAuthEnabled()) { doExternalAuth(room, lockPassword); } else { doXmppAuth(room, lockPassword); @@ -188,7 +277,14 @@ function showXmppPasswordPrompt(roomName, connect) { * @returns {Promise} */ function requestAuth(roomName, connect) { - return showXmppPasswordPrompt(roomName, connect); + if (isTokenAuthEnabled) { + // This Promise never resolves as user gets redirected to another URL + return new Promse(function (resolve, reject) { + redirectToTokenAuthService(roomName); + }); + } else { + return showXmppPasswordPrompt(roomName, connect); + } }