2562dc6af779bff9e9f6f7650e4b4eef731adf0b
[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         localStorage.setItem(HOME_CLUSTER, token.split('/')[1].substr(0, 5));
47     }
48
49     public removeApiToken() {
50         localStorage.removeItem(API_TOKEN_KEY);
51     }
52
53     public getApiToken() {
54         return localStorage.getItem(API_TOKEN_KEY) || undefined;
55     }
56
57     public getHomeCluster() {
58         return localStorage.getItem(HOME_CLUSTER) || undefined;
59     }
60
61     public removeUser() {
62         localStorage.removeItem(USER_EMAIL_KEY);
63         localStorage.removeItem(USER_FIRST_NAME_KEY);
64         localStorage.removeItem(USER_LAST_NAME_KEY);
65         localStorage.removeItem(USER_UUID_KEY);
66         localStorage.removeItem(USER_OWNER_UUID_KEY);
67         localStorage.removeItem(USER_IS_ADMIN);
68         localStorage.removeItem(USER_IS_ACTIVE);
69         localStorage.removeItem(USER_USERNAME);
70         localStorage.removeItem(USER_PREFS);
71     }
72
73     public login(uuidPrefix: string, homeCluster: string, loginCluster: string, remoteHosts: { [key: string]: string }) {
74         const currentUrl = `${window.location.protocol}//${window.location.host}/token`;
75         const homeClusterHost = remoteHosts[homeCluster];
76         window.location.assign(`https://${homeClusterHost}/login?${(uuidPrefix !== homeCluster && homeCluster !== loginCluster) ? "remote=" + uuidPrefix + "&" : ""}return_to=${currentUrl}`);
77     }
78
79     public logout() {
80         const currentUrl = `${window.location.protocol}//${window.location.host}`;
81         window.location.assign(`${this.baseUrl || ""}/logout?return_to=${currentUrl}`);
82     }
83
84     public getUserDetails = (): Promise<User> => {
85         const reqId = uuid();
86         this.actions.progressFn(reqId, true);
87         return this.apiClient
88             .get<UserDetailsResponse>('/users/current')
89             .then(resp => {
90                 this.actions.progressFn(reqId, false);
91                 const prefs = resp.data.prefs.profile ? resp.data.prefs : { profile: {} };
92                 return {
93                     email: resp.data.email,
94                     firstName: resp.data.first_name,
95                     lastName: resp.data.last_name,
96                     uuid: resp.data.uuid,
97                     ownerUuid: resp.data.owner_uuid,
98                     isAdmin: resp.data.is_admin,
99                     isActive: resp.data.is_active,
100                     username: resp.data.username,
101                     prefs
102                 };
103             })
104             .catch(e => {
105                 this.actions.progressFn(reqId, false);
106                 this.actions.errorFn(reqId, e);
107                 throw e;
108             });
109     }
110
111     public getSessions(): Session[] {
112         try {
113             const sessions = JSON.parse(localStorage.getItem("sessions") || '');
114             return sessions;
115         } catch {
116             return [];
117         }
118     }
119
120     public saveSessions(sessions: Session[]) {
121         localStorage.setItem("sessions", JSON.stringify(sessions));
122     }
123
124     public buildSessions(cfg: Config, user?: User) {
125         const currentSession = {
126             clusterId: cfg.uuidPrefix,
127             remoteHost: cfg.rootUrl,
128             baseUrl: cfg.baseUrl,
129             name: getUserFullname(user),
130             email: user ? user.email : '',
131             token: this.getApiToken(),
132             loggedIn: true,
133             active: true,
134             uuid: user ? user.uuid : '',
135             status: SessionStatus.VALIDATED
136         } as Session;
137         const localSessions = this.getSessions().map(s => ({
138             ...s,
139             active: false,
140             status: SessionStatus.INVALIDATED
141         }));
142
143         const cfgSessions = Object.keys(cfg.remoteHosts).map(clusterId => {
144             const remoteHost = cfg.remoteHosts[clusterId];
145             return {
146                 clusterId,
147                 remoteHost,
148                 baseUrl: '',
149                 name: '',
150                 email: '',
151                 token: '',
152                 loggedIn: false,
153                 active: false,
154                 uuid: '',
155                 status: SessionStatus.INVALIDATED
156             } as Session;
157         });
158         const sessions = [currentSession]
159             .concat(cfgSessions)
160             .concat(localSessions)
161             .filter((r: Session) => r.clusterId !== "*");
162
163         const uniqSessions = uniqBy(sessions, 'clusterId');
164
165         return uniqSessions;
166     }
167 }