203a2f192fbe9e86d00b18df7cf90b1264b1f961
[arvados-workbench2.git] / src / views / login-panel / login-panel.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import * as React from 'react';
6 import { connect, DispatchProp } from 'react-redux';
7 import { Grid, Typography, Button, Select } from '@material-ui/core';
8 import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core/styles';
9 import { login, authActions } from '~/store/auth/auth-action';
10 import { ArvadosTheme } from '~/common/custom-theme';
11 import { RootState } from '~/store/store';
12 import { LoginForm } from '~/views-components/login-form/login-form';
13 import Axios from 'axios';
14
15 type CssRules = 'root' | 'container' | 'title' | 'content' | 'content__bolder' | 'button';
16
17 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
18     root: {
19         position: 'relative',
20         backgroundColor: theme.palette.grey["200"],
21         '&::after': {
22             content: `''`,
23             position: 'absolute',
24             top: 0,
25             left: 0,
26             bottom: 0,
27             right: 0,
28             opacity: 0.2,
29         }
30     },
31     container: {
32         width: '560px',
33         zIndex: 10
34     },
35     title: {
36         marginBottom: theme.spacing.unit * 6,
37         color: theme.palette.grey["800"]
38     },
39     content: {
40         marginBottom: theme.spacing.unit * 3,
41         lineHeight: '1.2rem',
42         color: theme.palette.grey["800"]
43     },
44     'content__bolder': {
45         fontWeight: 'bolder'
46     },
47     button: {
48         boxShadow: 'none'
49     }
50 });
51
52 const doPAMLogin = (url: string) => (username: string, password: string) => {
53     const formData = new FormData();
54     formData.append("username", username);
55     formData.append("password", password);
56     return Axios.post(`${url}/login`, formData, {
57         headers: { 'X-Http-Method-Override': 'GET' },
58     });
59 };
60
61 type LoginPanelProps = DispatchProp<any> & WithStyles<CssRules> & {
62     remoteHosts: { [key: string]: string },
63     homeCluster: string,
64     uuidPrefix: string,
65     loginCluster: string,
66     welcomePage: string,
67     pamLogin: boolean,
68 };
69
70 export const LoginPanel = withStyles(styles)(
71     connect((state: RootState) => ({
72         remoteHosts: state.auth.remoteHosts,
73         homeCluster: state.auth.homeCluster,
74         uuidPrefix: state.auth.localCluster,
75         loginCluster: state.auth.loginCluster,
76         welcomePage: state.auth.config.clusterConfig.Workbench.WelcomePageHTML,
77         pamLogin: state.auth.config.clusterConfig.Login.PAM,
78     }))(({ classes, dispatch, remoteHosts, homeCluster, uuidPrefix, loginCluster, welcomePage, pamLogin }: LoginPanelProps) =>
79         <Grid container justify="center" alignItems="center"
80             className={classes.root}
81             style={{ marginTop: 56, overflowY: "auto", height: "100%" }}>
82             <Grid item className={classes.container}>
83                 <Typography component="div">
84                     <div dangerouslySetInnerHTML={{ __html: welcomePage }} style={{ margin: "1em" }} />
85                 </Typography>
86                 {Object.keys(remoteHosts).length > 1 && loginCluster === "" &&
87
88                     <Typography component="div" align="right">
89                         <label>Please select the cluster that hosts your user account:</label>
90                         <Select native value={homeCluster} style={{ margin: "1em" }}
91                             onChange={(event) => dispatch(authActions.SET_HOME_CLUSTER(event.target.value))}>
92                             {Object.keys(remoteHosts).map((k) => <option key={k} value={k}>{k}</option>)}
93                         </Select>
94                     </Typography>}
95
96                 {pamLogin
97                 ? <Typography component="div">
98                     <LoginForm dispatch={dispatch} handleSubmit={
99                         doPAMLogin(`https://${remoteHosts[homeCluster]}`)}/>
100                 </Typography>
101                 : <Typography component="div" align="right">
102                     <Button variant="contained" color="primary" style={{ margin: "1em" }}
103                         className={classes.button}
104                         onClick={() => dispatch(login(uuidPrefix, homeCluster, loginCluster, remoteHosts))}>
105                         Log in {uuidPrefix !== homeCluster && loginCluster !== homeCluster &&
106                             <span>&nbsp;to {uuidPrefix} with user from {homeCluster}</span>}
107                     </Button>
108                 </Typography>}
109             </Grid>
110         </Grid >
111     ));