diff options
author | 2019-03-12 18:00:21 +0100 | |
---|---|---|
committer | 2019-03-12 18:01:06 +0100 | |
commit | 2d4424c28ac35763ef44c42ae2f01664d42b268c (patch) | |
tree | 4e6ebdc2e57c1c8f2c91d3ec094b340c89dfe5c5 /sdnr/wt/odlux/framework/src/views | |
parent | caf781999351fc6a3e2acb5b2fe47fe04a291d2d (diff) |
Security provider for UX-Client-Login
Use ODL provided oauth2/token for UX clients
Change-Id: I9f9ae931fc5e74dc13076bd23551d163c0685606
Issue-ID: SDNC-648
Signed-off-by: Herbert Eiselt <herbert.eiselt@highstreet-technologies.com>
Diffstat (limited to 'sdnr/wt/odlux/framework/src/views')
-rw-r--r-- | sdnr/wt/odlux/framework/src/views/login.tsx | 336 |
1 files changed, 192 insertions, 144 deletions
diff --git a/sdnr/wt/odlux/framework/src/views/login.tsx b/sdnr/wt/odlux/framework/src/views/login.tsx index 6fa24e4ab..513e24712 100644 --- a/sdnr/wt/odlux/framework/src/views/login.tsx +++ b/sdnr/wt/odlux/framework/src/views/login.tsx @@ -1,145 +1,193 @@ -import * as React from 'react';
-import { withRouter, RouteComponentProps } from 'react-router-dom';
-
-import Avatar from '@material-ui/core/Avatar';
-import Button from '@material-ui/core/Button';
-import CssBaseline from '@material-ui/core/CssBaseline';
-import FormControl from '@material-ui/core/FormControl';
-import FormControlLabel from '@material-ui/core/FormControlLabel';
-import Checkbox from '@material-ui/core/Checkbox';
-import Input from '@material-ui/core/Input';
-import InputLabel from '@material-ui/core/InputLabel';
-import LockIcon from '@material-ui/icons/LockOutlined';
-import Paper from '@material-ui/core/Paper';
-import Typography from '@material-ui/core/Typography';
-import { withStyles, WithStyles, createStyles, Theme } from '@material-ui/core/styles';
-
-import connect, { Connect } from '../flux/connect';
-import authenticationService from '../services/authenticationService';
-
-import { UpdateAuthentication } from '../actions/authentication';
-
-const styles = (theme: Theme) => createStyles({
- layout: {
- width: 'auto',
- display: 'block', // Fix IE11 issue.
- marginLeft: theme.spacing.unit * 3,
- marginRight: theme.spacing.unit * 3,
- [theme.breakpoints.up(400 + theme.spacing.unit * 3 * 2)]: {
- width: 400,
- marginLeft: 'auto',
- marginRight: 'auto',
- },
- },
- paper: {
- marginTop: theme.spacing.unit * 8,
- display: 'flex',
- flexDirection: 'column',
- alignItems: 'center',
- padding: `${ theme.spacing.unit * 2 }px ${ theme.spacing.unit * 3 }px ${ theme.spacing.unit * 3 }px`,
- },
- avatar: {
- margin: theme.spacing.unit,
- backgroundColor: theme.palette.secondary.main,
- },
- form: {
- width: '100%', // Fix IE11 issue.
- marginTop: theme.spacing.unit,
- },
- submit: {
- marginTop: theme.spacing.unit * 3,
- },
-});
-
-type LoginProps = RouteComponentProps<{}> & WithStyles<typeof styles> & Connect ;
-
-interface ILoginState {
- busy: boolean;
- email: string;
- password: string;
-}
-
-
-// todo: ggf. redirect to einbauen
-class LoginComponent extends React.Component<LoginProps, ILoginState> {
-
- constructor(props: LoginProps) {
- super(props);
-
- this.state = {
- busy: false,
- email: '',
- password: ''
- };
- }
-
- render(): JSX.Element {
- const { classes } = this.props;
- return (
- <React.Fragment>
- <CssBaseline />
- <main className={ classes.layout }>
- <Paper className={ classes.paper }>
- <Avatar className={ classes.avatar }>
- <LockIcon />
- </Avatar>
- <Typography variant="caption">Sign in</Typography>
- <form className={ classes.form }>
- <FormControl margin="normal" required fullWidth>
- <InputLabel htmlFor="email">Email Address</InputLabel>
- <Input id="email" name="email" autoComplete="email" autoFocus
- disabled={ this.state.busy }
- value = {this.state.email }
- onChange={ event => { this.setState({ email: event.target.value }) } }/>
- </FormControl>
- <FormControl margin="normal" required fullWidth>
- <InputLabel htmlFor="password">Password</InputLabel>
- <Input
- name="password"
- type="password"
- id="password"
- autoComplete="current-password"
- disabled={ this.state.busy }
- value={ this.state.password }
- onChange={ event => { this.setState({ password: event.target.value }) } }
- />
- </FormControl>
- <FormControlLabel
- control={ <Checkbox value="remember" color="primary" /> }
- label="Remember me"
- />
- <Button
- type="submit"
- fullWidth
- variant="raised"
- color="primary"
- disabled = { this.state.busy }
- className={ classes.submit }
- onClick = { this.onSignIn }
- >
- Sign in
- </Button>
- </form>
- </Paper>
- </main>
- </React.Fragment>
- );
- }
-
- private onSignIn = async (event: React.MouseEvent<HTMLButtonElement>) => {
- event.preventDefault();
-
- this.setState({ busy: true });
- const token = await authenticationService.authenticateUser(this.state.email, this.state.password);
- this.props.dispatch(new UpdateAuthentication(token));
- this.setState({ busy: false });
-
- if (token) {
- this.props.history.replace("/");
- }
-
- }
-}
-
-export const Login = withStyles(styles)(withRouter(connect()(LoginComponent)));
+import * as React from 'react'; +import { withRouter, RouteComponentProps } from 'react-router-dom'; + +import Avatar from '@material-ui/core/Avatar'; +import Button from '@material-ui/core/Button'; +import Dialog from '@material-ui/core/Dialog'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogContentText from '@material-ui/core/DialogContentText'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import CssBaseline from '@material-ui/core/CssBaseline'; +import FormControl from '@material-ui/core/FormControl'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import Checkbox from '@material-ui/core/Checkbox'; +import Input from '@material-ui/core/Input'; +import InputLabel from '@material-ui/core/InputLabel'; +import LockIcon from '@material-ui/icons/LockOutlined'; +import Paper from '@material-ui/core/Paper'; +import Typography from '@material-ui/core/Typography'; +import { withStyles, WithStyles, createStyles, Theme } from '@material-ui/core/styles'; + +import connect, { Connect } from '../flux/connect'; +import authenticationService from '../services/authenticationService'; + +import { UpdateAuthentication } from '../actions/authentication'; + +const styles = (theme: Theme) => createStyles({ + layout: { + width: 'auto', + display: 'block', // Fix IE11 issue. + marginLeft: theme.spacing.unit * 3, + marginRight: theme.spacing.unit * 3, + [theme.breakpoints.up(400 + theme.spacing.unit * 3 * 2)]: { + width: 400, + marginLeft: 'auto', + marginRight: 'auto', + }, + }, + paper: { + marginTop: theme.spacing.unit * 8, + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + padding: `${ theme.spacing.unit * 2 }px ${ theme.spacing.unit * 3 }px ${ theme.spacing.unit * 3 }px`, + }, + avatar: { + margin: theme.spacing.unit, + backgroundColor: theme.palette.secondary.main, + }, + form: { + width: '100%', // Fix IE11 issue. + marginTop: theme.spacing.unit, + }, + submit: { + marginTop: theme.spacing.unit * 3, + }, +}); + +type LoginProps = RouteComponentProps<{}> & WithStyles<typeof styles> & Connect ; + +interface ILoginState { + busy: boolean; + email: string; + password: string; + scope: string; + message: string; +} + + +// todo: ggf. redirect to einbauen +class LoginComponent extends React.Component<LoginProps, ILoginState> { + + constructor(props: LoginProps) { + super(props); + + this.state = { + busy: false, + email: '', + password: '', + scope: 'sdn', + message: '' + }; + } + + render(): JSX.Element { + const { classes } = this.props; + return ( + <React.Fragment> + <CssBaseline /> + <main className={ classes.layout }> + <Paper className={ classes.paper }> + <Avatar className={ classes.avatar }> + <LockIcon /> + </Avatar> + <Typography variant="caption">Sign in</Typography> + <form className={ classes.form }> + <FormControl margin="normal" required fullWidth> + <InputLabel htmlFor="email">Email Address</InputLabel> + <Input id="email" name="email" autoComplete="email" autoFocus + disabled={ this.state.busy } + value = {this.state.email } + onChange={ event => { this.setState({ email: event.target.value }) } }/> + </FormControl> + <FormControl margin="normal" required fullWidth> + <InputLabel htmlFor="password">Password</InputLabel> + <Input + name="password" + type="password" + id="password" + autoComplete="current-password" + disabled={ this.state.busy } + value={ this.state.password } + onChange={ event => { this.setState({ password: event.target.value }) } } + /> + </FormControl> + <FormControl margin="normal" required fullWidth> + <InputLabel htmlFor="password">Scope</InputLabel> + <Input + name="scope" + type="scope" + id="scope" + disabled={this.state.busy} + value={this.state.scope} + onChange={event => { this.setState({ scope: event.target.value }) }} + /> + </FormControl> + <FormControlLabel + control={ <Checkbox value="remember" color="primary" /> } + label="Remember me" + /> + <Button + type="submit" + fullWidth + variant="raised" + color="primary" + disabled = { this.state.busy } + className={ classes.submit } + onClick = { this.onSignIn } + > + Sign in + </Button> + </form> + </Paper> + </main> + <Dialog + open={!!this.state.message} + onClose={() => { this.setState({message: ''})}} + aria-labelledby="alert-dialog-title" + aria-describedby="alert-dialog-description" + > + <DialogTitle id="alert-dialog-title">{"Error"}</DialogTitle> + <DialogContent> + <DialogContentText id="alert-dialog-description"> + { this.state.message } + </DialogContentText> + </DialogContent> + <DialogActions> + <Button onClick={() => { this.setState({ message: '' }) }} color="secondary" autoFocus> + OK + </Button> + </DialogActions> + </Dialog> + </React.Fragment> + ); + } + + private onSignIn = async (event: React.MouseEvent<HTMLButtonElement>) => { + event.preventDefault(); + + this.setState({ busy: true }); + const token = await authenticationService.authenticateUser(this.state.email, this.state.password, this.state.scope); + this.props.dispatch(new UpdateAuthentication(token)); + this.setState({ busy: false }); + + if (token) { + const query = + this.props.state.framework.navigationState.search && + this.props.state.framework.navigationState.search.replace(/^\?/, "") + .split('&').map(e => e.split("=")); + const returnTo = query && query.find(e => e[0] === "returnTo"); + this.props.history.replace(returnTo && returnTo[1] || "/"); + } + else { + this.setState({ + message: "Could not log in. Please check your credentials or ask your administrator for assistence.", + password: "" + }) + } + } +} + +export const Login = withStyles(styles)(withRouter(connect()(LoginComponent))); export default Login;
\ No newline at end of file |