UNPKG

@geogirafe/lib-geoportal

Version:

GeoGirafe is a flexible application to build online geoportals.

146 lines (145 loc) 6.17 kB
// SPDX-License-Identifier: Apache-2.0 import OpenIdConnectManager from './openidconnectmanager.js'; import GirafeSingleton from '../../base/GirafeSingleton.js'; import GMFConnectManager from './gmfconnectmanager.js'; import ServiceWorkerHelper from '../utils/swhelper.js'; import GMFManager from './gmfmanager.js'; export default class AuthManager extends GirafeSingleton { serviceWorkerHelper; issuerManager; gmfManager; get state() { return this.context.stateManager.state; } constructor(context) { super(context); this.gmfManager = new GMFManager(this.context); } initializeSingleton() { this.context.stateManager.subscribe('oauth.status', () => this.loginStateChanged()); this.context.stateManager.subscribe('oauth.tokens', () => this.tokensChanged()); } async initialize(sw) { if (!sw) { console.warn("ServiceWorker cannot be initialized. Authentication won't work properly."); return; } this.serviceWorkerHelper = new ServiceWorkerHelper(sw); const oauthIssuerConfig = this.context.configManager.Config.oauth?.issuer; const gmfauthConfig = this.context.configManager.Config.gmfauth; if (oauthIssuerConfig) { // Standard oAuth workflow await this.initializeOAuth(oauthIssuerConfig); } else if (gmfauthConfig) { await this.initializeGmfAuth(gmfauthConfig); } else { // No auth configured this.state.application.isAuthInitialized = true; } } async initializeOAuth(config) { await this.serviceWorkerHelper.sendMessageToServiceWorker({ clear_access_token: true }); this.issuerManager = new OpenIdConnectManager(this.context); await this.issuerManager.initialize(); // No silent login if user is in the process of being logged in ('issuer.loggedIn' is second step of login process) if (config.checkSessionOnLoad && this.state.oauth.status !== 'issuer.loggedIn') { await this.silentLogin(); } if (config.loginRequired && this.state.oauth.status === 'loggedOut') { await this.login(); } } async initializeGmfAuth(config) { this.issuerManager = new GMFConnectManager(this.context, this.gmfManager); await this.issuerManager.initialize(); // For GMF, the silent login is actually the same as checkin if the userinfos are already defined if (config.checkSessionOnLoad) { await this.silentLogin(); } if (config.loginRequired && this.state.oauth.status === 'loggedOut') { await this.login(); } } async loginStateChanged() { // The serviceWorkerHelper is instantiated in the initialize() method and not in the constructor // of AuthManager. Yet this method (.loginStateChanged()) is expected to be called from the constructor // as a propagation of subscribing to a change of 'oauth.status' with an already non-empty status. // To prevent unnecessary error login in console: if (!this.serviceWorkerHelper) { return; } try { console.log('Login state changed:', this.state.oauth.status); // Notify the service worker about the login state change await this.serviceWorkerHelper.sendMessageToServiceWorker({ loginState: this.state.oauth.status }); if (this.state.oauth.status === 'issuer.loggedIn') { // We are logged in to the identity provider // We must now login to GMF (for GMF < 2.9 only) // If we got a token from the issuer, we first call the GMF login route with Token if (this.state.oauth.tokens) { await this.gmfManager.loginWithToken(); } // And then we get the UserInfos const previousUsername = this.state.oauth.userInfo?.username; await this.gmfManager.getUserInfo(); if (this.state.oauth.userInfo?.username) { // TODO REG : At the moment we just test if the username has changed, // but actually we should test if some of the rights have changed this.state.oauth.somethingChanged = this.state.oauth.userInfo.username !== previousUsername; this.state.oauth.status = 'loggedIn'; } else { this.state.oauth.error = 'No user found in the token'; this.state.oauth.status = 'loginFailed'; } } else if (this.state.oauth.status === 'loggedIn' || this.state.oauth.status === 'loggedOut') { this.issuerManager.finalizeLoginWorkflow(); } else if (this.state.oauth.status === 'loginFailed') { this.issuerManager.handleErrorFromIssuer(); } } catch (error) { this.issuerManager.handleUnknownError(error); throw error; } } async tokensChanged() { await this.serviceWorkerHelper.sendMessageToServiceWorker({ access_token: this.state.oauth.tokens?.access_token }); } async login() { // Login to the issuer. // The login to the backend will automatically be done // when coming back from the issuer try { await this.issuerManager.login(); } catch (e) { this.state.oauth.status = 'loginFailed'; throw e; } } async silentLogin() { try { console.log('silentLogin'); await this.issuerManager.silentLogin(); } catch { this.state.oauth.status = 'loggedOut'; } } async logout() { // Logout from backend and then from the issuer try { await this.gmfManager.logout(); await this.issuerManager.logout(); } catch (e) { this.state.oauth.status = 'loginFailed'; throw e; } } }