Oidc now working

This commit is contained in:
Romaric Mourgues
2023-04-06 11:36:23 +02:00
parent 2f335418c3
commit 52ddd82252
@@ -14,6 +14,7 @@ import LocalStorage from 'app/features/global/framework/local-storage-service';
const OIDC_CALLBACK_URL = '/oidccallback'; const OIDC_CALLBACK_URL = '/oidccallback';
const OIDC_SIGNOUT_URL = '/signout'; const OIDC_SIGNOUT_URL = '/signout';
const OIDC_SILENT_URL = '/oidcsilent';
@TwakeService('OIDCAuthProvider') @TwakeService('OIDCAuthProvider')
export default class OIDCAuthProviderService export default class OIDCAuthProviderService
@@ -50,13 +51,15 @@ export default class OIDCAuthProviderService
client_id: this.configuration?.client_id, client_id: this.configuration?.client_id,
redirect_uri: getAsFrontUrl(OIDC_CALLBACK_URL), redirect_uri: getAsFrontUrl(OIDC_CALLBACK_URL),
response_type: 'code', response_type: 'code',
response_mode: 'query',
scope: 'openid profile email address phone offline_access', scope: 'openid profile email address phone offline_access',
post_logout_redirect_uri: getAsFrontUrl(OIDC_SIGNOUT_URL), post_logout_redirect_uri: getAsFrontUrl(OIDC_SIGNOUT_URL),
//silent_redirect_uri: getAsFrontUrl(OIDC_SILENT_URL), silent_redirect_uri: getAsFrontUrl(OIDC_SILENT_URL),
automaticSilentRenew: true, automaticSilentRenew: true,
loadUserInfo: true, loadUserInfo: true,
accessTokenExpiringNotificationTime: 60, accessTokenExpiringNotificationTime: 10,
filterProtocolClaims: true, filterProtocolClaims: true,
monitorSession: false,
}); });
// For logout if signout or logout endpoint called // For logout if signout or logout endpoint called
@@ -66,129 +69,59 @@ export default class OIDCAuthProviderService
this.signOut(); this.signOut();
} }
this.userManager.events.addUserLoaded(user => { this.userManager.events.addUserLoaded((user: any) => {
// fires each time the user is loaded or updated console.log('New User Loaded', arguments);
this.logger.debug('OIDC user loaded listener', user); console.log('Acess_token: ', user.access_token);
this.user = user; });
this.getJWTFromOidcToken(user, (err, jwt) => { this.userManager.events.addAccessTokenExpiring(function () {
if (err) { console.log('AccessToken Expiring', arguments);
this.logger.error(
'OIDC user loaded listener, error while getting the JWT from OIDC token',
err,
);
this.signinRedirect();
// FIXME: Should we return?
//return;
}
if (!this.initialized) {
// FIXME: Do we need to send back the user?
this.onInitialized();
this.initialized = true;
} else {
jwt && params.onNewToken(jwt);
}
});
}); });
this.userManager.events.addAccessTokenExpired(() => { this.userManager.events.addAccessTokenExpired(() => {
this.logger.debug('OIDC access token expired listener'); console.log('AccessToken Expired', arguments);
this.silentLogin();
// FIXME: use params.onSessionExpired() if we can not renew
}); });
this.userManager.events.addAccessTokenExpiring(() => { this.userManager.events.addSilentRenewError(function () {
this.logger.debug('OIDC access token is expiring'); console.error('Silent Renew Error', arguments);
this.silentLogin();
}); });
this.userManager.events.addSilentRenewError(error => { (async () => {
// in case the renew failed, ask for login try {
// since we have set automaticSilentRenew to true, this will be called when silentSignin raise error when token is expiring await this.userManager!.signinRedirectCallback();
this.logger.error('OIDC silent renew error', error); } catch (e) {}
this.signOut();
});
//This even listener is temporary disabled because of this issue: https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/-/issues/2358 const user = await this.userManager?.getUser();
this.userManager.events.addUserSignedOut(() => {
this.logger.info('OIDC Signed out listener');
//this.signOut();
});
//This manage the initial sign-in when loading the app if (user) {
if (this.enforceFrontendUrl()) { this.getJWTFromOidcToken(user, (err, jwt) => {
this.silentLogin(); if (err) {
} this.logger.error(
'OIDC user loaded listener, error while getting the JWT from OIDC token',
err,
);
this.signinRedirect();
}
if (!this.initialized) {
this.onInitialized();
this.initialized = true;
} else {
jwt && params.onNewToken(jwt);
}
});
} else {
this.userManager?.signinRedirect();
}
})();
} }
return this; return this;
} }
//Redirect to valid frontend url to make sure oidc will work as expected
private enforceFrontendUrl() {
const frontUrl = (getDomain(environment.front_root_url || '') || '').toLocaleLowerCase();
if (frontUrl && document.location.host.toLocaleLowerCase() !== frontUrl) {
document.location.replace(
document.location.protocol +
'//' +
getDomain(environment.front_root_url) +
'/' +
document.location.pathname +
document.location.search +
document.location.hash,
);
return false;
}
return true;
}
private async silentLogin(): Promise<void> {
if (!this.userManager) {
this.logger.debug('silentLogin, no auth provider');
return;
}
//Try to use the in-url sign-in response from oidc if exists
try {
this.logger.debug('silentLogin, trying to get user from redirect callback');
// This has to be called when we are in a redirect callback, not on other URLs
// if so, we catch the error which will be 'No state in response' and we try to silently signin
await this.userManager.signinRedirectCallback();
// calling this will fire the userloaded event listener above
await this.userManager.getUser();
} catch (e) {
this.logger.debug('silentLogin, not a signin response, trying to signin now', e);
//There is no sign-in response, so we can try to silent login and use refresh token
try {
//First we try to see if we know this user
let user = await this.userManager.getUser();
if (user) {
this.logger.debug('silentLogin, user is already defined, launching silent signin', user);
// If user is defined, we try a silent signin
// This will raise a userLoaded event, and so call some code in the listener above...
user = await this.userManager.signinSilent();
this.logger.debug('silentLogin, user from silent signin', user);
// Note: the userloaded listener above should be called from the signinSilent call
// if not get the JWT from the user and store the result in the JWT service with the help of callbacks
} else {
//If no user defined, we try a redirect signin
this.logger.debug('silentLogin, user not defined, launching a signin redirect');
this.signinRedirect();
}
} catch (e) {
this.logger.debug('silentLogin error, launching a signin redirect', e);
// FIXME: We should also be able to show a message to the user with the onSessionExpired listener
// In any case if it doesn't work we do a redirect signin
this.signinRedirect();
}
}
}
async signIn(): Promise<void> { async signIn(): Promise<void> {
this.logger.info('Signin'); this.logger.info('Signin');
await this.silentLogin(); this.signinRedirect();
} }
async signUp(): Promise<void> { async signUp(): Promise<void> {
@@ -267,7 +200,3 @@ export default class OIDCAuthProviderService
this.params?.onInitialized(); this.params?.onInitialized();
} }
} }
function getDomain(str: string): string {
return ((str || '').split('//').pop() || '').split('/').shift() || '';
}