You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AuthHandler.js 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // @flow
  2. import Logger from '@jitsi/logger';
  3. import { openConnection } from '../../../connection';
  4. import {
  5. openAuthDialog,
  6. openLoginDialog } from '../../../react/features/authentication/actions.web';
  7. import {
  8. LoginDialog,
  9. WaitForOwnerDialog
  10. } from '../../../react/features/authentication/components';
  11. import {
  12. isTokenAuthEnabled,
  13. getTokenAuthUrl
  14. } from '../../../react/features/authentication/functions';
  15. import { getReplaceParticipant } from '../../../react/features/base/config/functions';
  16. import { isDialogOpen } from '../../../react/features/base/dialog';
  17. import { setJWT } from '../../../react/features/base/jwt';
  18. import UIUtil from '../util/UIUtil';
  19. import ExternalLoginDialog from './LoginDialog';
  20. let externalAuthWindow;
  21. declare var APP: Object;
  22. const logger = Logger.getLogger(__filename);
  23. /**
  24. * Authenticate using external service or just focus
  25. * external auth window if there is one already.
  26. *
  27. * @param {JitsiConference} room
  28. * @param {string} [lockPassword] password to use if the conference is locked
  29. */
  30. function doExternalAuth(room, lockPassword) {
  31. const config = APP.store.getState()['features/base/config'];
  32. if (externalAuthWindow) {
  33. externalAuthWindow.focus();
  34. return;
  35. }
  36. if (room.isJoined()) {
  37. let getUrl;
  38. if (isTokenAuthEnabled(config)) {
  39. getUrl = Promise.resolve(getTokenAuthUrl(config)(room.getName(), true));
  40. initJWTTokenListener(room);
  41. } else {
  42. getUrl = room.getExternalAuthUrl(true);
  43. }
  44. getUrl.then(url => {
  45. externalAuthWindow = ExternalLoginDialog.showExternalAuthDialog(
  46. url,
  47. () => {
  48. externalAuthWindow = null;
  49. if (!isTokenAuthEnabled(config)) {
  50. room.join(lockPassword);
  51. }
  52. }
  53. );
  54. });
  55. } else if (isTokenAuthEnabled(config)) {
  56. redirectToTokenAuthService(room.getName());
  57. } else {
  58. room.getExternalAuthUrl().then(UIUtil.redirect);
  59. }
  60. }
  61. /**
  62. * Redirect the user to the token authentication service for the login to be
  63. * performed. Once complete it is expected that the service will bring the user
  64. * back with "?jwt={the JWT token}" query parameter added.
  65. * @param {string} [roomName] the name of the conference room.
  66. */
  67. export function redirectToTokenAuthService(roomName: string) {
  68. const config = APP.store.getState()['features/base/config'];
  69. // FIXME: This method will not preserve the other URL params that were
  70. // originally passed.
  71. UIUtil.redirect(getTokenAuthUrl(config)(roomName, false));
  72. }
  73. /**
  74. * Initializes 'message' listener that will wait for a JWT token to be received
  75. * from the token authentication service opened in a popup window.
  76. * @param room the name of the conference room.
  77. */
  78. function initJWTTokenListener(room) {
  79. /**
  80. *
  81. */
  82. function listener({ data, source }) {
  83. if (externalAuthWindow !== source) {
  84. logger.warn('Ignored message not coming '
  85. + 'from external authnetication window');
  86. return;
  87. }
  88. let jwt;
  89. if (data && (jwt = data.jwtToken)) {
  90. logger.info('Received JSON Web Token (JWT):', jwt);
  91. APP.store.dispatch(setJWT(jwt));
  92. const roomName = room.getName();
  93. openConnection({
  94. retry: false,
  95. roomName
  96. }).then(connection => {
  97. // Start new connection
  98. const newRoom = connection.initJitsiConference(
  99. roomName, APP.conference._getConferenceOptions());
  100. // Authenticate from the new connection to get
  101. // the session-ID from the focus, which will then be used
  102. // to upgrade current connection's user role
  103. newRoom.room.moderator.authenticate()
  104. .then(() => {
  105. connection.disconnect();
  106. // At this point we'll have session-ID stored in
  107. // the settings. It will be used in the call below
  108. // to upgrade user's role
  109. room.room.moderator.authenticate()
  110. .then(() => {
  111. logger.info('User role upgrade done !');
  112. // eslint-disable-line no-use-before-define
  113. unregister();
  114. })
  115. .catch((err, errCode) => {
  116. logger.error('Authentication failed: ',
  117. err, errCode);
  118. unregister();
  119. });
  120. })
  121. .catch((error, code) => {
  122. unregister();
  123. connection.disconnect();
  124. logger.error(
  125. 'Authentication failed on the new connection',
  126. error, code);
  127. });
  128. }, err => {
  129. unregister();
  130. logger.error('Failed to open new connection', err);
  131. });
  132. }
  133. }
  134. /**
  135. *
  136. */
  137. function unregister() {
  138. window.removeEventListener('message', listener);
  139. }
  140. if (window.addEventListener) {
  141. window.addEventListener('message', listener, false);
  142. }
  143. }
  144. /**
  145. * Authenticate for the conference.
  146. * Uses external service for auth if conference supports that.
  147. * @param {JitsiConference} room
  148. * @param {string} [lockPassword] password to use if the conference is locked
  149. */
  150. function authenticate(room: Object, lockPassword: string) {
  151. const config = APP.store.getState()['features/base/config'];
  152. if (isTokenAuthEnabled(config) || room.isExternalAuthEnabled()) {
  153. doExternalAuth(room, lockPassword);
  154. } else {
  155. APP.store.dispatch(openLoginDialog());
  156. }
  157. }
  158. /**
  159. * Notify user that authentication is required to create the conference.
  160. * @param {JitsiConference} room
  161. * @param {string} [lockPassword] password to use if the conference is locked
  162. */
  163. function requireAuth(room: Object, lockPassword: string) {
  164. if (isDialogOpen(APP.store, WaitForOwnerDialog) || isDialogOpen(APP.store, LoginDialog)) {
  165. return;
  166. }
  167. APP.store.dispatch(
  168. openAuthDialog(
  169. room.getName(), authenticate.bind(null, room, lockPassword))
  170. );
  171. }
  172. /**
  173. * De-authenticate local user.
  174. *
  175. * @param {JitsiConference} room
  176. * @param {string} [lockPassword] password to use if the conference is locked
  177. * @returns {Promise}
  178. */
  179. function logout(room: Object) {
  180. return new Promise(resolve => {
  181. room.room.moderator.logout(resolve);
  182. }).then(url => {
  183. // de-authenticate conference on the fly
  184. if (room.isJoined()) {
  185. const replaceParticipant = getReplaceParticipant(APP.store.getState());
  186. room.join(null, replaceParticipant);
  187. }
  188. return url;
  189. });
  190. }
  191. export default {
  192. authenticate,
  193. logout,
  194. requireAuth
  195. };