From 06f509b4756c00a86f2a4ea3a8366edbcee55bc8 Mon Sep 17 00:00:00 2001 From: damencho Date: Thu, 27 Jul 2023 16:37:52 -0500 Subject: [PATCH] feat: Adds auto redirect config for token auth URL. Option that enables auto redirect, so once a user has authenticated we will use that authentication on next join. --- config.js | 1 + react/features/authentication/actionTypes.ts | 10 ++++ react/features/authentication/actions.any.ts | 14 +++++ react/features/authentication/middleware.ts | 63 +++++++++++++++++--- react/features/authentication/reducer.ts | 14 +++++ react/features/base/config/configType.ts | 1 + 6 files changed, 95 insertions(+), 8 deletions(-) diff --git a/config.js b/config.js index 10920696ca..31c25436dd 100644 --- a/config.js +++ b/config.js @@ -1447,6 +1447,7 @@ var config = { peopleSearchUrl requireDisplayName tokenAuthUrl + tokenAuthUrlAutoRedirect tokenLogoutUrl */ diff --git a/react/features/authentication/actionTypes.ts b/react/features/authentication/actionTypes.ts index b8c526f32b..9f7e404deb 100644 --- a/react/features/authentication/actionTypes.ts +++ b/react/features/authentication/actionTypes.ts @@ -26,6 +26,16 @@ export const LOGIN = 'LOGIN'; */ export const LOGOUT = 'LOGOUT'; +/** + * The type of (redux) action which signals that we have authenticated successful when + * tokenAuthUrl is set. + * + * { + * type: SET_TOKEN_AUTH_URL_SUCCESS + * } + */ +export const SET_TOKEN_AUTH_URL_SUCCESS = 'SET_TOKEN_AUTH_URL_SUCCESS'; + /** * The type of (redux) action which signals that the cyclic operation of waiting * for conference owner has been aborted. diff --git a/react/features/authentication/actions.any.ts b/react/features/authentication/actions.any.ts index 27a1d7599e..09e70d483a 100644 --- a/react/features/authentication/actions.any.ts +++ b/react/features/authentication/actions.any.ts @@ -4,6 +4,7 @@ import { IJitsiConference } from '../base/conference/reducer'; import { hideDialog, openDialog } from '../base/dialog/actions'; import { + SET_TOKEN_AUTH_URL_SUCCESS, STOP_WAIT_FOR_OWNER, UPGRADE_ROLE_FINISHED, UPGRADE_ROLE_STARTED, WAIT_FOR_OWNER @@ -185,3 +186,16 @@ export function waitForOwner() { export function openLoginDialog() { return openDialog(LoginDialog); } + +/** + * Updates the config with new options. + * + * @param {boolean} value - The new value. + * @returns {Function} + */ +export function setTokenAuthUrlSuccess(value: boolean) { + return { + type: SET_TOKEN_AUTH_URL_SUCCESS, + value + }; +} diff --git a/react/features/authentication/middleware.ts b/react/features/authentication/middleware.ts index f1ce754fcb..fd50b3d319 100644 --- a/react/features/authentication/middleware.ts +++ b/react/features/authentication/middleware.ts @@ -2,7 +2,8 @@ import { IStore } from '../app/types'; import { CONFERENCE_FAILED, CONFERENCE_JOINED, - CONFERENCE_LEFT + CONFERENCE_LEFT, + SET_ROOM } from '../base/conference/actionTypes'; import { CONNECTION_ESTABLISHED, CONNECTION_FAILED } from '../base/connection/actionTypes'; import { hangup } from '../base/connection/actions'; @@ -31,8 +32,10 @@ import { openLoginDialog, openWaitForOwnerDialog, redirectToDefaultLocation, + setTokenAuthUrlSuccess, stopWaitForOwner, - waitForOwner } from './actions'; + waitForOwner +} from './actions'; import { LoginDialog, WaitForOwnerDialog } from './components'; import { getTokenAuthUrl, isTokenAuthEnabled } from './functions'; @@ -107,12 +110,25 @@ MiddlewareRegistry.register(store => next => action => { break; } - case CONFERENCE_JOINED: + case CONFERENCE_JOINED: { + const { dispatch, getState } = store; + const state = getState(); + const config = state['features/base/config']; + + if (isTokenAuthEnabled(config) + && config.tokenAuthUrlAutoRedirect + && state['features/base/jwt'].jwt) { + // auto redirect is turned on and we have succesfully logged in + // let's mark that + dispatch(setTokenAuthUrlSuccess(true)); + } + if (_isWaitingForOwner(store)) { store.dispatch(stopWaitForOwner()); } store.dispatch(hideLoginDialog()); break; + } case CONFERENCE_LEFT: store.dispatch(stopWaitForOwner()); @@ -146,14 +162,24 @@ MiddlewareRegistry.register(store => next => action => { } case LOGOUT: { + const { dispatch, getState } = store; + const state = getState(); + const config = state['features/base/config']; const { conference } = store.getState()['features/base/conference']; if (!conference) { break; } - store.dispatch(openLogoutDialog(() => { - const logoutUrl = store.getState()['features/base/config'].tokenLogoutUrl; + dispatch(openLogoutDialog(() => { + const logoutUrl = config.tokenLogoutUrl; + + if (isTokenAuthEnabled(config) + && config.tokenAuthUrlAutoRedirect + && state['features/base/jwt'].jwt) { + // user is logging out remove auto redirect indication + dispatch(setTokenAuthUrlSuccess(false)); + } if (logoutUrl) { window.location.href = logoutUrl; @@ -161,12 +187,31 @@ MiddlewareRegistry.register(store => next => action => { return; } - conference.room.moderator.logout(() => store.dispatch(hangup(true))); + conference.room.moderator.logout(() => dispatch(hangup(true))); })); break; } + case SET_ROOM: { + const { dispatch, getState } = store; + const state = getState(); + const config = state['features/base/config']; + + if (isTokenAuthEnabled(config) && config.tokenAuthUrlAutoRedirect + && state['features/authentication'].tokenAuthUrlSuccessful) { + // if we have auto redirect enabled, and we have previously logged in successfully + // let's redirect to the auth url to get the token and login again + dispatch(setTokenAuthUrlSuccess(false)); + + const { room } = action; + + window.location.href = getTokenAuthUrl(config)(room, false); + } + + break; + } + case STOP_WAIT_FOR_OWNER: _clearExistingWaitForOwnerTimeout(store); store.dispatch(hideDialog(WaitForOwnerDialog)); @@ -248,8 +293,10 @@ function _handleLogin({ dispatch, getState }: IStore) { } // FIXME: This method will not preserve the other URL params that were originally passed. - // redirectToTokenAuthService - window.location.href = getTokenAuthUrl(config)(room, false); + const tokenAuthServiceUrl = getTokenAuthUrl(config)(room, false); + + // we have already shown the prejoin screen so no need to show it again(if enabled) after obtaining the token + window.location.href = `${tokenAuthServiceUrl}${tokenAuthServiceUrl.includes('#') ? '&' : '#'}skipPrejoin=true`; } else { dispatch(openLoginDialog()); } diff --git a/react/features/authentication/reducer.ts b/react/features/authentication/reducer.ts index 41a6e52204..958344fbea 100644 --- a/react/features/authentication/reducer.ts +++ b/react/features/authentication/reducer.ts @@ -1,8 +1,10 @@ +import PersistenceRegistry from '../base/redux/PersistenceRegistry'; import ReducerRegistry from '../base/redux/ReducerRegistry'; import { assign } from '../base/redux/functions'; import { CANCEL_LOGIN, + SET_TOKEN_AUTH_URL_SUCCESS, STOP_WAIT_FOR_OWNER, UPGRADE_ROLE_FINISHED, UPGRADE_ROLE_STARTED, @@ -15,9 +17,17 @@ export interface IAuthenticationState { thenableWithCancel?: { cancel: Function; }; + tokenAuthUrlSuccessful?: boolean; waitForOwnerTimeoutID?: number; } +/** + * Sets up the persistence of the feature {@code authentication}. + */ +PersistenceRegistry.register('features/authentication', { + tokenAuthUrlSuccessful: true +}); + /** * Listens for actions which change the state of the authentication feature. * @@ -35,6 +45,10 @@ ReducerRegistry.register('features/authentication', progress: undefined, thenableWithCancel: undefined }); + case SET_TOKEN_AUTH_URL_SUCCESS: + return assign(state, { + tokenAuthUrlSuccessful: action.value + }); case STOP_WAIT_FOR_OWNER: return assign(state, { diff --git a/react/features/base/config/configType.ts b/react/features/base/config/configType.ts index 3305042c6c..67170ae917 100644 --- a/react/features/base/config/configType.ts +++ b/react/features/base/config/configType.ts @@ -576,6 +576,7 @@ export interface IConfig { numberOfVisibleTiles?: number; }; tokenAuthUrl?: string; + tokenAuthUrlAutoRedirect?: string; tokenLogoutUrl?: string; toolbarButtons?: Array; toolbarConfig?: {