15803: Update test
[arvados-workbench2.git] / src / services / auth-service / auth-service.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { getUserFullname, User, UserPrefs } from '~/models/user';
6 import { AxiosInstance } from "axios";
7 import { ApiActions } from "~/services/api/api-actions";
8 import * as uuid from "uuid/v4";
9 import { Session, SessionStatus } from "~/models/session";
10 import { Config } from "~/common/config";
11 import { uniqBy } from "lodash";
12
13 export const API_TOKEN_KEY = 'apiToken';
14 export const USER_EMAIL_KEY = 'userEmail';
15 export const USER_FIRST_NAME_KEY = 'userFirstName';
16 export const USER_LAST_NAME_KEY = 'userLastName';
17 export const USER_UUID_KEY = 'userUuid';
18 export const USER_OWNER_UUID_KEY = 'userOwnerUuid';
19 export const USER_IS_ADMIN = 'isAdmin';
20 export const USER_IS_ACTIVE = 'isActive';
21 export const USER_USERNAME = 'username';
22 export const USER_PREFS = 'prefs';
23 export const HOME_CLUSTER = 'homeCluster';
24
25 export interface UserDetailsResponse {
26     email: string;
27     first_name: string;
28     last_name: string;
29     uuid: string;
30     owner_uuid: string;
31     is_admin: boolean;
32     is_active: boolean;
33     username: string;
34     prefs: UserPrefs;
35 }
36
37 export class AuthService {
38
39     constructor(
40         protected apiClient: AxiosInstance,
41         protected baseUrl: string,
42         protected actions: ApiActions) { }
43
44     public saveApiToken(token: string) {
45         localStorage.setItem(API_TOKEN_KEY, token);
46         const sp = token.split('/');
47         if (sp.length == 3) {
48             localStorage.setItem(HOME_CLUSTER, sp[1].substr(0, 5));
49         }
50     }
51
52     public removeApiToken() {
53         localStorage.removeItem(API_TOKEN_KEY);
54     }
55
56     public getApiToken() {
57         return localStorage.getItem(API_TOKEN_KEY) || undefined;
58     }
59
60     public getHomeCluster() {
61         return localStorage.getItem(HOME_CLUSTER) || undefined;
62     }
63
64     public removeUser() {
65         localStorage.removeItem(USER_EMAIL_KEY);
66         localStorage.removeItem(USER_FIRST_NAME_KEY);
67         localStorage.removeItem(USER_LAST_NAME_KEY);
68         localStorage.removeItem(USER_UUID_KEY);
69         localStorage.removeItem(USER_OWNER_UUID_KEY);
70         localStorage.removeItem(USER_IS_ADMIN);
71         localStorage.removeItem(USER_IS_ACTIVE);
72         localStorage.removeItem(USER_USERNAME);
73         localStorage.removeItem(USER_PREFS);
74     }
75
76     public login(uuidPrefix: string, homeCluster: string, loginCluster: string, remoteHosts: { [key: string]: string }) {
77         const currentUrl = `${window.location.protocol}//${window.location.host}/token`;
78         const homeClusterHost = remoteHosts[homeCluster];
79         window.location.assign(`https://${homeClusterHost}/login?${(uuidPrefix !== homeCluster && homeCluster !== loginCluster) ? "remote=" + uuidPrefix + "&" : ""}return_to=${currentUrl}`);
80     }
81
82     public logout() {
83         const currentUrl = `${window.location.protocol}//${window.location.host}`;
84         window.location.assign(`${this.baseUrl || ""}/logout?return_to=${currentUrl}`);
85     }
86
87     public getUserDetails = (): Promise<User> => {
88         const reqId = uuid();
89         this.actions.progressFn(reqId, true);
90         return this.apiClient
91             .get<UserDetailsResponse>('/users/current')
92             .then(resp => {
93                 this.actions.progressFn(reqId, false);
94                 const prefs = resp.data.prefs.profile ? resp.data.prefs : { profile: {} };
95                 return {
96                     email: resp.data.email,
97                     firstName: resp.data.first_name,
98                     lastName: resp.data.last_name,
99                     uuid: resp.data.uuid,
100                     ownerUuid: resp.data.owner_uuid,
101                     isAdmin: resp.data.is_admin,
102                     isActive: resp.data.is_active,
103                     username: resp.data.username,
104                     prefs
105                 };
106             })
107             .catch(e => {
108                 this.actions.progressFn(reqId, false);
109                 this.actions.errorFn(reqId, e);
110                 throw e;
111             });
112     }
113
114     public getSessions(): Session[] {
115         try {
116             const sessions = JSON.parse(localStorage.getItem("sessions") || '');
117             return sessions;
118         } catch {
119             return [];
120         }
121     }
122
123     public saveSessions(sessions: Session[]) {
124         localStorage.setItem("sessions", JSON.stringify(sessions));
125     }
126
127     public buildSessions(cfg: Config, user?: User) {
128         const currentSession = {
129             clusterId: cfg.uuidPrefix,
130             remoteHost: cfg.rootUrl,
131             baseUrl: cfg.baseUrl,
132             name: getUserFullname(user),
133             email: user ? user.email : '',
134             token: this.getApiToken(),
135             loggedIn: true,
136             active: true,
137             uuid: user ? user.uuid : '',
138             status: SessionStatus.VALIDATED
139         } as Session;
140         const localSessions = this.getSessions().map(s => ({
141             ...s,
142             active: false,
143             status: SessionStatus.INVALIDATED
144         }));
145
146         const cfgSessions = Object.keys(cfg.remoteHosts).map(clusterId => {
147             const remoteHost = cfg.remoteHosts[clusterId];
148             return {
149                 clusterId,
150                 remoteHost,
151                 baseUrl: '',
152                 name: '',
153                 email: '',
154                 token: '',
155                 loggedIn: false,
156                 active: false,
157                 uuid: '',
158                 status: SessionStatus.INVALIDATED
159             } as Session;
160         });
161         const sessions = [currentSession]
162             .concat(cfgSessions)
163             .concat(localSessions)
164             .filter((r: Session) => r.clusterId !== "*");
165
166         const uniqSessions = uniqBy(sessions, 'clusterId');
167
168         return uniqSessions;
169     }
170 }