Security provider for UX-Client-Login
[ccsdk/features.git] / sdnr / wt / odlux / framework / src / views / login.tsx
1 import * as React from 'react';
2 import { withRouter, RouteComponentProps } from 'react-router-dom';
3
4 import Avatar from '@material-ui/core/Avatar';
5 import Button from '@material-ui/core/Button';
6 import Dialog from '@material-ui/core/Dialog';
7 import DialogActions from '@material-ui/core/DialogActions';
8 import DialogContent from '@material-ui/core/DialogContent';
9 import DialogContentText from '@material-ui/core/DialogContentText';
10 import DialogTitle from '@material-ui/core/DialogTitle';
11 import CssBaseline from '@material-ui/core/CssBaseline';
12 import FormControl from '@material-ui/core/FormControl';
13 import FormControlLabel from '@material-ui/core/FormControlLabel';
14 import Checkbox from '@material-ui/core/Checkbox';
15 import Input from '@material-ui/core/Input';
16 import InputLabel from '@material-ui/core/InputLabel';
17 import LockIcon from '@material-ui/icons/LockOutlined';
18 import Paper from '@material-ui/core/Paper';
19 import Typography from '@material-ui/core/Typography';
20 import { withStyles, WithStyles, createStyles, Theme } from '@material-ui/core/styles';
21
22 import connect, { Connect } from '../flux/connect';
23 import authenticationService from '../services/authenticationService';
24
25 import { UpdateAuthentication } from '../actions/authentication';
26
27 const styles = (theme: Theme) => createStyles({
28   layout: {
29     width: 'auto',
30     display: 'block', // Fix IE11 issue.
31     marginLeft: theme.spacing.unit * 3,
32     marginRight: theme.spacing.unit * 3,
33     [theme.breakpoints.up(400 + theme.spacing.unit * 3 * 2)]: {
34       width: 400,
35       marginLeft: 'auto',
36       marginRight: 'auto',
37     },
38   },
39   paper: {
40     marginTop: theme.spacing.unit * 8,
41     display: 'flex',
42     flexDirection: 'column',
43     alignItems: 'center',
44     padding: `${ theme.spacing.unit * 2 }px ${ theme.spacing.unit * 3 }px ${ theme.spacing.unit * 3 }px`,
45   },
46   avatar: {
47     margin: theme.spacing.unit,
48     backgroundColor: theme.palette.secondary.main,
49   },
50   form: {
51     width: '100%', // Fix IE11 issue.
52     marginTop: theme.spacing.unit,
53   },
54   submit: {
55     marginTop: theme.spacing.unit * 3,
56   },
57 });
58
59 type LoginProps = RouteComponentProps<{}> & WithStyles<typeof styles> & Connect ;
60
61 interface ILoginState {
62   busy: boolean;
63   email: string;
64   password: string;
65   scope: string;
66   message: string;
67 }
68
69
70 // todo: ggf. redirect to einbauen
71 class LoginComponent extends React.Component<LoginProps, ILoginState> {
72
73   constructor(props: LoginProps) {
74     super(props);
75
76     this.state = {
77       busy: false,
78       email: '',
79       password: '',
80       scope: 'sdn',
81       message: ''
82     };
83   }
84
85   render(): JSX.Element {
86     const { classes } = this.props;
87     return (
88       <React.Fragment>
89         <CssBaseline />
90         <main className={ classes.layout }>
91           <Paper className={ classes.paper }>
92             <Avatar className={ classes.avatar }>
93               <LockIcon />
94             </Avatar>
95             <Typography variant="caption">Sign in</Typography>
96             <form className={ classes.form }>
97               <FormControl margin="normal" required fullWidth>
98                 <InputLabel htmlFor="email">Email Address</InputLabel>
99                 <Input id="email" name="email" autoComplete="email" autoFocus
100                   disabled={ this.state.busy }
101                   value = {this.state.email }
102                   onChange={ event => { this.setState({ email: event.target.value }) } }/>
103               </FormControl>
104               <FormControl margin="normal" required fullWidth>
105                 <InputLabel htmlFor="password">Password</InputLabel>
106                 <Input
107                   name="password"
108                   type="password"
109                   id="password"
110                   autoComplete="current-password"
111                   disabled={ this.state.busy }
112                   value={ this.state.password }
113                   onChange={ event => { this.setState({ password: event.target.value }) } }
114                 />
115               </FormControl>
116               <FormControl margin="normal" required fullWidth>
117                 <InputLabel htmlFor="password">Scope</InputLabel>
118                 <Input
119                   name="scope"
120                   type="scope"
121                   id="scope"
122                   disabled={this.state.busy}
123                   value={this.state.scope}
124                   onChange={event => { this.setState({ scope: event.target.value }) }}
125                 />
126               </FormControl>
127               <FormControlLabel
128                 control={ <Checkbox value="remember" color="primary" /> }
129                 label="Remember me"
130               />
131               <Button
132                 type="submit"
133                 fullWidth
134                 variant="raised"
135                 color="primary"
136                 disabled = { this.state.busy }
137                 className={ classes.submit }
138                 onClick = { this.onSignIn }
139               >
140                 Sign in
141             </Button>
142             </form>
143           </Paper>
144         </main>
145         <Dialog
146           open={!!this.state.message}
147           onClose={() => { this.setState({message: ''})}}
148           aria-labelledby="alert-dialog-title"
149           aria-describedby="alert-dialog-description"
150         >
151           <DialogTitle id="alert-dialog-title">{"Error"}</DialogTitle>
152           <DialogContent>
153             <DialogContentText id="alert-dialog-description">
154               { this.state.message }
155             </DialogContentText>
156           </DialogContent>
157           <DialogActions>
158             <Button onClick={() => { this.setState({ message: '' }) }} color="secondary" autoFocus>
159               OK
160             </Button>
161           </DialogActions>
162         </Dialog>
163       </React.Fragment>
164     );
165   }
166
167   private onSignIn = async (event: React.MouseEvent<HTMLButtonElement>) => {
168     event.preventDefault();
169
170     this.setState({ busy: true });
171     const token = await authenticationService.authenticateUser(this.state.email, this.state.password, this.state.scope);
172     this.props.dispatch(new UpdateAuthentication(token));
173     this.setState({ busy: false });
174
175     if (token) {
176       const query =
177         this.props.state.framework.navigationState.search &&
178         this.props.state.framework.navigationState.search.replace(/^\?/, "")
179           .split('&').map(e => e.split("="));
180       const returnTo = query && query.find(e => e[0] === "returnTo");
181       this.props.history.replace(returnTo && returnTo[1] || "/");
182     }
183     else {
184       this.setState({
185         message: "Could not log in. Please check your credentials or ask your administrator for assistence.",
186         password: ""
187       })
188     }
189   }
190 }
191
192 export const Login = withStyles(styles)(withRouter(connect()(LoginComponent)));
193 export default Login;