1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const tslib_1 = require("tslib");
|
4 | const common_1 = require("@nestjs/common");
|
5 | const jsonwebtoken_1 = require("jsonwebtoken");
|
6 | const lodash_1 = require("lodash");
|
7 | const passport = require("passport");
|
8 | const passport_1 = require("passport");
|
9 | const passport_auth0_1 = require("passport-auth0");
|
10 | const passport_google_oauth20_1 = require("passport-google-oauth20");
|
11 | const passport_local_1 = require("passport-local");
|
12 | const passport_openidconnect_1 = require("passport-openidconnect");
|
13 | const passport_saml_1 = require("passport-saml");
|
14 | const context_1 = require("../datastore/context");
|
15 | const datastore_provider_1 = require("../datastore/datastore.provider");
|
16 | const logging_1 = require("../gcloud/logging");
|
17 | const auth_service_1 = require("./auth.service");
|
18 | const user_service_1 = require("./user.service");
|
19 | const GOOGLE_SIGNIN = 'google';
|
20 | const SAML_SIGNIN = 'saml';
|
21 | const AUTH0_SIGNIN = 'auth0';
|
22 | const OIDC_SIGNIN = 'oidc';
|
23 | const LOCAL_SIGNIN = 'local-signin';
|
24 | const FAKE_SIGNIN = 'fake-signin';
|
25 | const DEFAULT_FAILURE_REDIRECT = '/';
|
26 | let AuthConfigurer = class AuthConfigurer {
|
27 | constructor(datastoreProvider, configuration, userService, authService) {
|
28 | this.configuration = configuration;
|
29 | this.userService = userService;
|
30 | this.authService = authService;
|
31 | this.validate = async (username, password, done) => this.validateAuth(done, () => this.authService.validateUser(context_1.newContext(this.datastore), username, password));
|
32 | this.validateFakeLogin = async (req, username, password, done) => this.validateAuth(done, () => this.authService.validateFakeLogin(context_1.newContext(this.datastore), req.headers['x-fake-secret'], username, lodash_1.get(req, 'body.name', ''), lodash_1.get(req, 'body.roles', []), lodash_1.get(req, 'body.orgId', ''), lodash_1.get(req, 'body.props', {})));
|
33 | this.validateGmail = async (accessToken, refreshToken, profile, done) => this.validateAuth(done, () => this.authService.validateUserGoogle(context_1.newContext(this.datastore), profile));
|
34 | this.validateSaml = (profile, done) => this.validateAuth(done, () => this.authService.validateUserSaml(context_1.newContext(this.datastore), profile));
|
35 | this.validateOidc = (_issuer, _sub, profile, _accessToken, _refreshToken, done) => this.validateAuth(done, () => this.authService.validateUserOidc(context_1.newContext(this.datastore), profile, !!this.configuration.auth.oidc.replaceAuth));
|
36 | this.validateAuth0 = (accessToken, refreshToken, extraParams, profile, done) => this.validateAuth(done, () => {
|
37 | const decoded = jsonwebtoken_1.decode(extraParams.id_token);
|
38 | const { email, name } = decoded;
|
39 | const namespace = this.configuration.auth.auth0.namespace;
|
40 | const roles = decoded[`${namespace}roles`];
|
41 | const orgId = decoded[`${namespace}orgId`];
|
42 | const props = decoded[`${namespace}props`];
|
43 | if (!roles || !roles.length) {
|
44 | this.logger.warn(`No roles were provided by auth0 for ${email}`);
|
45 | }
|
46 | return this.authService.validateUserAuth0(context_1.newContext(this.datastore), email, name, orgId, roles, props);
|
47 | });
|
48 | this.validateAuth = async (done, auth) => {
|
49 | try {
|
50 | const user = await auth();
|
51 | if (!user) {
|
52 | return done(null, false, new common_1.UnauthorizedException());
|
53 | }
|
54 | done(null, user);
|
55 | }
|
56 | catch (ex) {
|
57 | this.logger.error(ex);
|
58 | if (ex instanceof auth_service_1.AuthenticationFailedException) {
|
59 | done(null, false, ex);
|
60 | }
|
61 | else {
|
62 | done(new common_1.UnauthorizedException('Internal error', ex), false);
|
63 | }
|
64 | }
|
65 | };
|
66 | this.datastore = datastoreProvider.datastore;
|
67 | this.logger = logging_1.createLogger('auth');
|
68 | this.init();
|
69 | }
|
70 | init() {
|
71 | passport.serializeUser((user, done) => {
|
72 | done(null, { id: user.id });
|
73 | });
|
74 | passport.deserializeUser(async (user, done) => {
|
75 | done(null, { id: user.id });
|
76 | });
|
77 | if (this.configuration.auth.local && this.configuration.auth.local.enabled) {
|
78 | passport_1.use(LOCAL_SIGNIN, new passport_local_1.Strategy({}, this.validate));
|
79 | }
|
80 | if (this.configuration.auth.fake && this.configuration.auth.fake.enabled) {
|
81 | if (!this.configuration.isDevelopment()) {
|
82 | if (!this.configuration.auth.fake.secret) {
|
83 | throw new Error('Fake login must have secret configured in non-development environments');
|
84 | }
|
85 | this.logger.warn('Fake login is enabled');
|
86 | }
|
87 | passport_1.use(FAKE_SIGNIN, new passport_local_1.Strategy({ passReqToCallback: true }, this.validateFakeLogin));
|
88 | }
|
89 | if (this.configuration.auth.google && this.configuration.auth.google.enabled) {
|
90 | passport_1.use(new passport_google_oauth20_1.Strategy({
|
91 | clientID: this.configuration.auth.google.clientId,
|
92 | clientSecret: this.configuration.auth.google.secret,
|
93 | callbackURL: `${this.configuration.host}/auth/signin/google/callback`,
|
94 | userProfileURL: 'https://www.googleapis.com/oauth2/v3/userinfo',
|
95 | }, this.validateGmail));
|
96 | }
|
97 | if (this.configuration.auth.saml && this.configuration.auth.saml.enabled) {
|
98 | passport_1.use(SAML_SIGNIN, new passport_saml_1.Strategy({
|
99 | entryPoint: this.configuration.auth.saml.identityProviderUrl,
|
100 | callbackUrl: `${this.configuration.host}/auth/signin/saml/acs`,
|
101 | issuer: this.configuration.host,
|
102 | acceptedClockSkewMs: 5000,
|
103 | cert: this.configuration.auth.saml.cert,
|
104 | }, this.validateSaml));
|
105 | }
|
106 | if (this.configuration.auth.auth0 && this.configuration.auth.auth0.enabled) {
|
107 | passport_1.use(AUTH0_SIGNIN, new passport_auth0_1.Strategy({
|
108 | domain: this.configuration.auth.auth0.domain,
|
109 | clientID: this.configuration.auth.auth0.clientId,
|
110 | clientSecret: this.configuration.auth.auth0.secret,
|
111 | callbackURL: `${this.configuration.host}/auth/signin/auth0/callback`,
|
112 | }, this.validateAuth0));
|
113 | }
|
114 | if (this.configuration.auth.oidc && this.configuration.auth.oidc.enabled) {
|
115 | const { authUrl, clientId, enabled, issuer, secret, tokenUrl, userInfoUrl } = this.configuration.auth.oidc;
|
116 | passport_1.use(OIDC_SIGNIN, new passport_openidconnect_1.Strategy({
|
117 | issuer,
|
118 | authorizationURL: authUrl,
|
119 | tokenURL: tokenUrl,
|
120 | userInfoURL: userInfoUrl,
|
121 | clientID: clientId,
|
122 | clientSecret: secret,
|
123 | callbackURL: `${this.configuration.host}/auth/signin/oidc/callback`,
|
124 | scope: 'profile email',
|
125 | }, this.validateOidc));
|
126 | this.logger.info(`Configured ${OIDC_SIGNIN} authentication strategy`);
|
127 | }
|
128 | }
|
129 | beginAuthenticateGoogle() {
|
130 | const options = {
|
131 | scope: ['profile', 'email'],
|
132 | };
|
133 | return passport.authenticate(GOOGLE_SIGNIN, options);
|
134 | }
|
135 | completeAuthenticateGoogle() {
|
136 | return passport.authenticate(GOOGLE_SIGNIN, {
|
137 | failureRedirect: this.configuration.auth.google.failureRedirect || DEFAULT_FAILURE_REDIRECT,
|
138 | });
|
139 | }
|
140 | beginAuthenticateSaml() {
|
141 | return passport.authenticate(SAML_SIGNIN, {
|
142 | failureRedirect: this.configuration.auth.saml.failureRedirect || DEFAULT_FAILURE_REDIRECT,
|
143 | });
|
144 | }
|
145 | completeAuthenticateSaml() {
|
146 | return passport.authenticate(SAML_SIGNIN, {
|
147 | failureRedirect: this.configuration.auth.saml.failureRedirect || DEFAULT_FAILURE_REDIRECT,
|
148 | });
|
149 | }
|
150 | beginAuthenticateOidc() {
|
151 | return passport.authenticate(OIDC_SIGNIN, {
|
152 | scope: ['openid', 'profile', 'email'],
|
153 | });
|
154 | }
|
155 | completeAuthenticateOidc() {
|
156 | return passport.authenticate(OIDC_SIGNIN, {
|
157 | failureRedirect: this.configuration.auth.oidc.failureRedirect || DEFAULT_FAILURE_REDIRECT,
|
158 | });
|
159 | }
|
160 | beginAuthenticateAuth0() {
|
161 | const options = {
|
162 | scope: ['openid', 'email', 'profile'],
|
163 | };
|
164 | return passport.authenticate(AUTH0_SIGNIN, options);
|
165 | }
|
166 | completeAuthenticateAuth0() {
|
167 | return passport.authenticate(AUTH0_SIGNIN, {
|
168 | failureRedirect: this.configuration.auth.auth0.failureRedirect || DEFAULT_FAILURE_REDIRECT,
|
169 | });
|
170 | }
|
171 | getSignoutUrlAuth0() {
|
172 | const clientId = this.configuration.auth.auth0.clientId;
|
173 | const domain = this.configuration.auth.auth0.domain;
|
174 | const host = this.configuration.host;
|
175 | return `https://${domain}/v2/logout?client_id=${clientId}&returnTo=${host}`;
|
176 | }
|
177 | authenticateLocal() {
|
178 | return passport.authenticate(LOCAL_SIGNIN, {});
|
179 | }
|
180 | authenticateFake() {
|
181 | return passport.authenticate(FAKE_SIGNIN, {});
|
182 | }
|
183 | };
|
184 | AuthConfigurer = tslib_1.__decorate([
|
185 | common_1.Injectable(),
|
186 | tslib_1.__param(1, common_1.Inject('Configuration')),
|
187 | tslib_1.__param(2, common_1.Inject(user_service_1.USER_SERVICE)),
|
188 | tslib_1.__metadata("design:paramtypes", [datastore_provider_1.DatastoreProvider, Object, Object, auth_service_1.AuthService])
|
189 | ], AuthConfigurer);
|
190 | exports.AuthConfigurer = AuthConfigurer;
|
191 |
|
\ | No newline at end of file |