@geogirafe/lib-geoportal
Version:
GeoGirafe is a flexible application to build online geoportals.
120 lines (119 loc) • 4.46 kB
JavaScript
import { SHORTLINK_PARAMETER } from '../share/iurlshortener.js';
export default class AbstractConnectManager {
storagePath = 'oAuth';
urlParameterForHash = 'hash';
context;
constructor(context) {
this.context = context;
}
get state() {
return this.context.stateManager.state;
}
loggedOutFromBackend() {
this.context.errorManager.pushMessage('You were logged out', 'Your identity is not recognized any more by the backend. Please try to login again, or contact an administrator.', 'warning');
this.loggedOut();
}
handleErrorFromIssuer() {
this.context.errorManager.pushMessage('Login Failed', this.state.oauth.error ?? 'Unknown error', 'error');
this.loggedOut();
}
handleUnknownError(error) {
this.state.oauth.error = error.message;
this.state.oauth.status = 'loginFailed';
}
loggedOut(saveState = true) {
if (saveState) {
this.context.sessionManager.saveStateToSession();
}
this.state.oauth.status = 'loggedOut';
this.state.oauth.tokens = undefined;
this.state.oauth.userInfo = undefined;
this.state.oauth.audience = [];
}
/**
* The RedirectUrl has to be the same for all call to the issuer
* Because the authentication is given for a specific redirectUrl.
* Therefore, we keep it in localStorage.
*/
get redirectUrl() {
return this.loadFromLocalStorage('redirectUrl');
}
set redirectUrl(value) {
this.saveToLocalStorage('redirectUrl', value);
}
getLoginRedirectUrl(silent) {
let url;
if (silent) {
url = new URL(this.context.urlManager.getRootUrl());
url.pathname += 'silentlogincallback.html';
}
else {
url = new URL(this.context.urlManager.getBaseUrlPath());
}
url.searchParams.append('authentified', 'true');
this.preserveUrlHash(url);
return url.toString();
}
getLogoutRedirectUrl() {
if (this.context.configManager.Config.oauth?.issuer.customLogoutRedirectUrl) {
return this.context.configManager.Config.oauth?.issuer.customLogoutRedirectUrl;
}
const url = new URL(this.context.urlManager.getBaseUrlPath());
url.searchParams.append('authentified', 'false');
this.preserveUrlHash(url);
return url.toString();
}
/**
* Save the URL hash to a query parameter since some OIDC providers don't allow URL hashes in the redirect URL
*/
preserveUrlHash(url) {
const hash = this.context.urlManager.getHash();
if (hash?.length && hash !== 'session') {
console.error('App state in URL!!!');
}
if (hash) {
url.searchParams.append(this.urlParameterForHash, hash);
}
}
restoreUrlHash(url) {
const urlHash = this.context.urlManager.getParam(this.urlParameterForHash);
if (urlHash) {
url.hash = urlHash;
}
}
loadFromLocalStorage(path) {
return this.context.userDataManager.getFromLocalStorage(`${this.storagePath}.${path}`) ?? '';
}
saveToLocalStorage(path, value) {
this.context.userDataManager.saveToLocalStorage(`${this.storagePath}.${path}`, value);
}
resetUrl() {
const url = new URL(this.context.urlManager.getBaseUrlPath());
// Keep the short link: the shared state is restored only after the login workflow
const shortId = this.context.urlManager.getParam(SHORTLINK_PARAMETER);
if (shortId) {
url.searchParams.set(SHORTLINK_PARAMETER, shortId);
}
this.restoreUrlHash(url);
this.context.urlManager.updateUrl(url);
}
finalizeLoginWorkflow() {
switch (this.state.oauth.status) {
case 'loggedIn':
this.resetUrl();
break;
case 'loggedOut':
this.resetUrl();
break;
case 'not-initialized':
case 'backend.loggedOut':
case 'issuer.loggedIn':
case 'loginFailed':
case 'logoutFailed':
throw new Error('We should only finalize the login workflow when the user is either loggedIn or loggedOut');
default:
throw new Error('Unmanaged login state');
}
this.state.application.isAuthInitialized = true;
}
}