Merge pull request #728 from jitsi/jwt-login-service-2

Jwt login service 2
This commit is contained in:
hristoterezov 2016-07-11 15:12:40 -05:00 committed by GitHub
commit c04874b087
2 changed files with 139 additions and 36 deletions

View File

@ -1,6 +1,5 @@
/* global APP, JitsiMeetJS, config */ /* global APP, JitsiMeetJS, config */
//FIXME: import AuthHandler from './modules/UI/authentication/AuthHandler';
import LoginDialog from './modules/UI/authentication/LoginDialog';
const ConnectionEvents = JitsiMeetJS.events.connection; const ConnectionEvents = JitsiMeetJS.events.connection;
const ConnectionErrors = JitsiMeetJS.errors.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<JitsiConnection>}
*/
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. * Open JitsiConnection using provided credentials.
* If retry option is true it will show auth dialog on PASSWORD_REQUIRED error. * 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) { if (config.token) {
throw err; throw err;
} else { } else {
return requestAuth(roomName); return AuthHandler.requestAuth(roomName, connect);
} }
} else { } else {
throw err; throw err;

View File

@ -1,15 +1,20 @@
/* global JitsiMeetJS, APP */ /* global APP, config, JitsiMeetJS, Promise */
import LoginDialog from './LoginDialog'; import LoginDialog from './LoginDialog';
import UIEvents from '../../../service/UI/UIEvents';
import UIUtil from '../util/UIUtil'; import UIUtil from '../util/UIUtil';
import {openConnection} from '../../../connection'; import {openConnection} from '../../../connection';
const ConferenceEvents = JitsiMeetJS.events.conference; const ConferenceEvents = JitsiMeetJS.events.conference;
const ConnectionErrors = JitsiMeetJS.errors.connection;
let externalAuthWindow; let externalAuthWindow;
let authRequiredDialog; 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 * Authenticate using external service or just focus
* external auth window if there is one already. * external auth window if there is one already.
@ -23,19 +28,103 @@ function doExternalAuth (room, lockPassword) {
return; return;
} }
if (room.isJoined()) { 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( externalAuthWindow = LoginDialog.showExternalAuthDialog(
url, url,
function () { function () {
externalAuthWindow = null; externalAuthWindow = null;
room.join(lockPassword); if (!isTokenAuthEnabled) {
room.join(lockPassword);
}
} }
); );
}); });
} else { } else {
// If conference has not been started yet // If conference has not been started yet
// then redirect to login page // 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 * @param {string} [lockPassword] password to use if the conference is locked
*/ */
function authenticate (room, lockPassword) { function authenticate (room, lockPassword) {
if (room.isExternalAuthEnabled()) { if (isTokenAuthEnabled || room.isExternalAuthEnabled()) {
doExternalAuth(room, lockPassword); doExternalAuth(room, lockPassword);
} else { } else {
doXmppAuth(room, lockPassword); doXmppAuth(room, lockPassword);
@ -157,10 +246,52 @@ 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<JitsiConnection>}
*/
function requestAuth(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);
}
}
export default { export default {
authenticate, authenticate,
requireAuth, requireAuth,
requestAuth,
closeAuth, closeAuth,
logout logout
}; };