Merge branch '19504-breadcrumbs' into main. Closes #19504
[arvados.git] / src / store / auth / auth-middleware.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { Middleware } from "redux";
6 import { authActions, } from "./auth-action";
7 import { ServiceRepository, setAuthorizationHeader, removeAuthorizationHeader } from "services/services";
8 import { initSessions } from "store/auth/auth-action-session";
9 import { User } from "models/user";
10 import { RootState } from 'store/store';
11 import { progressIndicatorActions } from "store/progress-indicator/progress-indicator-actions";
12 import { WORKBENCH_LOADING_SCREEN } from 'store/workbench/workbench-actions';
13
14 export const authMiddleware = (services: ServiceRepository): Middleware => store => next => action => {
15     // Middleware to update external state (local storage, window
16     // title) to ensure that they stay in sync with redux state.
17
18     authActions.match(action, {
19         INIT_USER: ({ user, token }) => {
20             // The "next" method passes the action to the next
21             // middleware in the chain, or the reducer.  That means
22             // after next() returns, the action has (presumably) been
23             // applied by the reducer to update the state.
24             next(action);
25
26             const state: RootState = store.getState();
27
28             if (state.auth.apiToken) {
29                 services.authService.saveApiToken(state.auth.apiToken);
30                 setAuthorizationHeader(services, state.auth.apiToken);
31             } else {
32                 services.authService.removeApiToken();
33                 services.authService.removeSessions();
34                 removeAuthorizationHeader(services);
35             }
36
37             store.dispatch<any>(initSessions(services.authService, state.auth.remoteHostsConfig[state.auth.localCluster], user));
38             if (!user.isActive) {
39                 // As a special case, if the user is inactive, they
40                 // may be able to self-activate using the "activate"
41                 // method.  Note, for this to work there can't be any
42                 // unsigned user agreements, we assume the API server is just going to
43                 // rubber-stamp our activation request.  At some point in the future we'll
44                 // want to either add support for displaying/signing user
45                 // agreements or get rid of self-activation.
46                 // For more details, see:
47                 // https://doc.arvados.org/main/admin/user-management.html
48
49                 store.dispatch(progressIndicatorActions.START_WORKING(WORKBENCH_LOADING_SCREEN));
50                 services.userService.activate(user.uuid).then((user: User) => {
51                     store.dispatch(authActions.INIT_USER({ user, token }));
52                     store.dispatch(progressIndicatorActions.STOP_WORKING(WORKBENCH_LOADING_SCREEN));
53                 }).catch(() => {
54                     store.dispatch(progressIndicatorActions.STOP_WORKING(WORKBENCH_LOADING_SCREEN));
55                 });
56             }
57         },
58         SET_CONFIG: ({ config }) => {
59             document.title = `Arvados Workbench (${config.uuidPrefix})`;
60             next(action);
61         },
62         LOGOUT: ({ deleteLinkData }) => {
63             next(action);
64             if (deleteLinkData) {
65                 services.linkAccountService.removeAccountToLink();
66             }
67             const token = services.authService.getApiToken();
68             services.authService.removeApiToken();
69             services.authService.removeSessions();
70             services.authService.removeUser();
71             removeAuthorizationHeader(services);
72             services.authService.logout(token || '');
73         },
74         default: () => next(action)
75     });
76 };