jiti-meet/modules/UI/authentication/AuthHandler.js

315 lines
9.5 KiB
JavaScript
Raw Normal View History

/* global APP, config, JitsiMeetJS, Promise */
2015-12-17 15:31:11 +00:00
2020-05-20 10:57:03 +00:00
import Logger from 'jitsi-meet-logger';
2017-04-21 10:00:50 +00:00
import { openConnection } from '../../../connection';
2017-10-05 22:54:13 +00:00
import { setJWT } from '../../../react/features/base/jwt';
import {
JitsiConnectionErrors
} from '../../../react/features/base/lib-jitsi-meet';
2016-01-06 22:39:13 +00:00
import UIUtil from '../util/UIUtil';
2017-04-21 10:00:50 +00:00
import LoginDialog from './LoginDialog';
2015-12-17 15:31:11 +00:00
2020-05-20 10:57:03 +00:00
const logger = Logger.getLogger(__filename);
2015-12-17 15:31:11 +00:00
let externalAuthWindow;
let authRequiredDialog;
const isTokenAuthEnabled
= typeof config.tokenAuthUrl === 'string' && config.tokenAuthUrl.length;
const getTokenAuthUrl
2016-07-11 11:46:11 +00:00
= JitsiMeetJS.util.AuthUtil.getTokenAuthUrl.bind(null, config.tokenAuthUrl);
2016-01-15 14:59:35 +00:00
/**
* Authenticate using external service or just focus
* external auth window if there is one already.
*
* @param {JitsiConference} room
* @param {string} [lockPassword] password to use if the conference is locked
*/
function doExternalAuth(room, lockPassword) {
2015-12-17 15:31:11 +00:00
if (externalAuthWindow) {
externalAuthWindow.focus();
2015-12-17 15:31:11 +00:00
return;
}
if (room.isJoined()) {
2016-07-11 11:46:11 +00:00
let getUrl;
2016-07-11 11:46:11 +00:00
if (isTokenAuthEnabled) {
getUrl = Promise.resolve(getTokenAuthUrl(room.getName(), true));
initJWTTokenListener(room);
} else {
getUrl = room.getExternalAuthUrl(true);
}
getUrl.then(url => {
2015-12-17 15:31:11 +00:00
externalAuthWindow = LoginDialog.showExternalAuthDialog(
url,
() => {
2015-12-17 15:31:11 +00:00
externalAuthWindow = null;
2016-07-11 11:46:11 +00:00
if (!isTokenAuthEnabled) {
room.join(lockPassword);
}
2015-12-17 15:31:11 +00:00
}
);
});
} else if (isTokenAuthEnabled) {
redirectToTokenAuthService(room.getName());
2015-12-17 15:31:11 +00:00
} else {
room.getExternalAuthUrl().then(UIUtil.redirect);
2016-07-11 11:46:11 +00:00
}
}
/**
* 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) {
// FIXME: This method will not preserve the other URL params that were
// originally passed.
2016-07-11 11:46:11 +00:00
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) {
/**
*
*/
function listener({ data, source }) {
2017-04-21 10:00:50 +00:00
if (externalAuthWindow !== source) {
logger.warn('Ignored message not coming '
+ 'from external authnetication window');
2016-07-11 11:46:11 +00:00
return;
}
2017-04-21 10:00:50 +00:00
let jwt;
if (data && (jwt = data.jwtToken)) {
logger.info('Received JSON Web Token (JWT):', jwt);
2017-04-21 10:00:50 +00:00
APP.store.dispatch(setJWT(jwt));
const roomName = room.getName();
openConnection({
retry: false,
roomName
}).then(connection => {
// Start new connection
const 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(() => {
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(() => {
logger.info('User role upgrade done !');
// eslint-disable-line no-use-before-define
unregister();
})
.catch((err, errCode) => {
logger.error('Authentication failed: ',
err, errCode);
unregister();
});
})
.catch((error, code) => {
2016-07-11 11:46:11 +00:00
unregister();
connection.disconnect();
logger.error(
'Authentication failed on the new connection',
error, code);
2016-07-11 11:46:11 +00:00
});
}, err => {
unregister();
logger.error('Failed to open new connection', err);
});
2016-07-11 11:46:11 +00:00
}
}
/**
*
*/
function unregister() {
window.removeEventListener('message', listener);
}
2016-07-11 11:46:11 +00:00
if (window.addEventListener) {
window.addEventListener('message', listener, false);
2015-12-17 15:31:11 +00:00
}
}
2016-01-15 14:59:35 +00:00
/**
* Authenticate on the server.
* @param {JitsiConference} room
* @param {string} [lockPassword] password to use if the conference is locked
*/
2017-09-18 07:09:43 +00:00
function doXmppAuth(room, lockPassword) {
const loginDialog = LoginDialog.showAuthDialog(
/* successCallback */ (id, password) => {
room.authenticateAndUpgradeRole({
2017-09-08 13:36:42 +00:00
id,
password,
roomPassword: lockPassword,
2017-09-18 07:09:43 +00:00
/** Called when the XMPP login succeeds. */
onLoginSuccessful() {
2017-09-08 13:36:42 +00:00
loginDialog.displayConnectionStatus(
'connection.FETCH_SESSION_ID');
}
})
2017-09-18 07:09:43 +00:00
.then(
/* onFulfilled */ () => {
loginDialog.displayConnectionStatus(
'connection.GOT_SESSION_ID');
loginDialog.close();
},
/* onRejected */ error => {
logger.error('authenticateAndUpgradeRole failed', error);
const { authenticationError, connectionError } = error;
if (authenticationError) {
loginDialog.displayError(
'connection.GET_SESSION_ID_ERROR',
{ msg: authenticationError });
} else if (connectionError) {
loginDialog.displayError(connectionError);
}
});
},
/* cancelCallback */ () => loginDialog.close());
2015-12-17 15:31:11 +00:00
}
2016-01-15 14:59:35 +00:00
/**
* Authenticate for the conference.
* Uses external service for auth if conference supports that.
* @param {JitsiConference} room
* @param {string} [lockPassword] password to use if the conference is locked
*/
function authenticate(room, lockPassword) {
2016-07-11 11:46:11 +00:00
if (isTokenAuthEnabled || room.isExternalAuthEnabled()) {
2015-12-17 15:31:11 +00:00
doExternalAuth(room, lockPassword);
} else {
2016-02-16 15:42:28 +00:00
doXmppAuth(room, lockPassword);
2015-12-17 15:31:11 +00:00
}
}
2016-02-25 13:52:15 +00:00
/**
* De-authenticate local user.
*
* @param {JitsiConference} room
* @param {string} [lockPassword] password to use if the conference is locked
* @returns {Promise}
*/
function logout(room) {
return new Promise(resolve => {
2016-02-25 13:52:15 +00:00
room.room.moderator.logout(resolve);
}).then(url => {
2016-02-25 13:52:15 +00:00
// de-authenticate conference on the fly
if (room.isJoined()) {
room.join();
}
return url;
});
}
2016-01-15 14:59:35 +00:00
/**
* Notify user that authentication is required to create the conference.
2016-02-16 15:42:28 +00:00
* @param {JitsiConference} room
* @param {string} [lockPassword] password to use if the conference is locked
2016-01-15 14:59:35 +00:00
*/
2016-02-16 15:42:28 +00:00
function requireAuth(room, lockPassword) {
2015-12-17 15:31:11 +00:00
if (authRequiredDialog) {
return;
}
authRequiredDialog = LoginDialog.showAuthRequiredDialog(
2016-02-16 15:42:28 +00:00
room.getName(), authenticate.bind(null, room, lockPassword)
2015-12-17 15:31:11 +00:00
);
}
2016-01-15 14:59:35 +00:00
/**
* Close auth-related dialogs if there are any.
*/
2015-12-17 15:31:11 +00:00
function closeAuth() {
if (externalAuthWindow) {
externalAuthWindow.close();
externalAuthWindow = null;
}
if (authRequiredDialog) {
authRequiredDialog.close();
authRequiredDialog = null;
}
}
/**
*
*/
function showXmppPasswordPrompt(roomName, connect) {
return new Promise((resolve, reject) => {
const authDialog = LoginDialog.showAuthDialog(
(id, password) => {
connect(id, password, roomName).then(connection => {
authDialog.close();
resolve(connection);
}, err => {
if (err === JitsiConnectionErrors.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
* JitsiConnectionErrors.
* @returns {Promise<JitsiConnection>}
*/
function requestAuth(roomName, connect) {
2016-07-11 11:46:11 +00:00
if (isTokenAuthEnabled) {
// This Promise never resolves as user gets redirected to another URL
return new Promise(() => redirectToTokenAuthService(roomName));
2016-07-11 11:46:11 +00:00
}
return showXmppPasswordPrompt(roomName, connect);
}
2015-12-17 15:31:11 +00:00
export default {
authenticate,
requireAuth,
requestAuth,
2016-02-25 13:52:15 +00:00
closeAuth,
logout
2015-12-17 15:31:11 +00:00
};