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

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