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.8KB

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