-
Notifications
You must be signed in to change notification settings - Fork 58
/
Copy pathlogin-oidc.js
128 lines (107 loc) · 4.46 KB
/
login-oidc.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import Route from '@ember/routing/route';
import { service } from '@ember/service';
import fetch from 'fetch';
import get from 'lodash/get';
import ENV from 'mon-pix/config/environment';
import { createTranslatedApplicationError } from 'mon-pix/errors/factories/create-application-error';
import JSONApiError from 'mon-pix/errors/json-api-error';
import { SessionStorageEntry } from '../../utils/session-storage-entry';
const oidcUserAuthenticationStorage = new SessionStorageEntry('oidcUserAuthentication');
export default class LoginOidcRoute extends Route {
@service intl;
@service location;
@service oidcIdentityProviders;
@service router;
@service session;
beforeModel(transition) {
const queryParams = transition.to.queryParams;
if (queryParams.error) {
const error = createTranslatedApplicationError.withCodeAndDescription({
code: queryParams.error,
description: queryParams.error_description,
intl: this.intl,
});
throw error;
}
const identityProviderSlug = transition.to.params.identity_provider_slug.toString();
// Preventing OIDC authentication replay errors when doing history back and reload
// when the user is already authenticated with the same OIDC Provider.
if (this.session.isAuthenticated) {
const identityProvider = this.oidcIdentityProviders[identityProviderSlug];
if (identityProvider.code == this.session.data.identityProviderCode) {
return this.router.replaceWith('authenticated');
}
}
if (!queryParams.code) {
this._cleanSession();
if (this.oidcIdentityProviders.isProviderEnabled(identityProviderSlug)) {
return this._handleRedirectRequest(identityProviderSlug);
}
return this.router.replaceWith('authentication.login');
}
}
async model(params, transition) {
const queryParams = transition.to.queryParams;
if (queryParams.code) {
const identityProviderSlug = params.identity_provider_slug;
return this._handleCallbackRequest(queryParams.code, queryParams.state, queryParams.iss, identityProviderSlug);
}
}
afterModel({ shouldValidateCgu, identityProviderSlug } = {}) {
const shouldCreateAnAccountForUser = shouldValidateCgu && oidcUserAuthenticationStorage.get().authenticationKey;
if (!shouldCreateAnAccountForUser) return;
return this.router.replaceWith('authentication.login-or-register-oidc', {
queryParams: {
identityProviderSlug,
},
});
}
_cleanSession() {
this.session.set('data.nextURL', undefined);
}
async _handleCallbackRequest(code, state, iss, identityProviderSlug) {
try {
await this.session.authenticate('authenticator:oidc', {
code,
state,
iss,
identityProviderSlug,
hostSlug: 'token',
});
} catch (response) {
const apiError = get(response, 'errors[0]');
const error = new JSONApiError(apiError.detail, apiError);
const shouldValidateCgu = error.code === 'SHOULD_VALIDATE_CGU';
if (shouldValidateCgu && error.meta.authenticationKey) {
oidcUserAuthenticationStorage.set(error.meta);
return { shouldValidateCgu, identityProviderSlug };
}
throw error;
}
}
async _handleRedirectRequest(identityProviderSlug) {
/**
* Store the `attemptedTransition` in the localstorage so when the user returns after
* the login he can be sent to the initial destination.
*/
if (this.session.get('attemptedTransition')) {
/**
* There is two types of intent in transition (see: https://github.com/tildeio/router.js/blob/9b3d00eb923e0bbc34c44f08c6de1e05684b907a/ARCHITECTURE.md#transitionintent)
* When the route is accessed by url (/campagnes/:code), the url is provided
* When the route is accessed by the submit of the campaign code, the route name (campaigns.access) and contexts ([Campaign]) are provided
*/
let { url } = this.session.get('attemptedTransition.intent');
const { name, contexts } = this.session.get('attemptedTransition.intent');
if (!url) {
url = this.router.urlFor(name, contexts[0]);
}
this.session.set('data.nextURL', url);
}
const identityProvider = this.oidcIdentityProviders[identityProviderSlug]?.code;
const response = await fetch(
`${ENV.APP.API_HOST}/api/oidc/authorization-url?identity_provider=${identityProvider}`,
);
const { redirectTarget } = await response.json();
this.location.replace(redirectTarget);
}
}