diff options
author | Aijana Schumann <aijana.schumann@highstreet-technologies.com> | 2021-02-15 18:22:28 +0100 |
---|---|---|
committer | Aijana Schumann <aijana.schumann@highstreet-technologies.com> | 2021-02-15 18:23:57 +0100 |
commit | 8515052e1a6de2de56effbc61c73d3aa80169a93 (patch) | |
tree | 8707b2b587890522b35cd7dd1b54ce4f006f1c3a /sdnr/wt/odlux/framework/src/views | |
parent | db20d36689c011333ed7216b64d3e987e473f1ee (diff) |
Add OAuth support to odlux
Extend odlux to support oauth, support external login provider for sign-in
Issue-ID: CCSDK-3167
Signed-off-by: Aijana Schumann <aijana.schumann@highstreet-technologies.com>
Change-Id: Id5772e0026fa7ebda22c41c2620a7868598f41aa
Diffstat (limited to 'sdnr/wt/odlux/framework/src/views')
-rw-r--r-- | sdnr/wt/odlux/framework/src/views/frame.tsx | 40 | ||||
-rw-r--r-- | sdnr/wt/odlux/framework/src/views/login.tsx | 92 |
2 files changed, 100 insertions, 32 deletions
diff --git a/sdnr/wt/odlux/framework/src/views/frame.tsx b/sdnr/wt/odlux/framework/src/views/frame.tsx index c8e24fdb9..b4cc43e0b 100644 --- a/sdnr/wt/odlux/framework/src/views/frame.tsx +++ b/sdnr/wt/odlux/framework/src/views/frame.tsx @@ -80,32 +80,32 @@ class FrameComponent extends React.Component<FrameProps>{ }
<Switch>
<Route exact path="/" component={() => (
- <AppFrame title={"Home"} icon={faHome} >
- <Home />
- </AppFrame>
+ <AppFrame title={"Home"} icon={faHome} >
+ <Home />
+ </AppFrame>
)} />
<Route path="/about" component={() => (
- <AppFrame title={"About"} icon={faAddressBook} >
- <About />
- </AppFrame>
+ <AppFrame title={"About"} icon={faAddressBook} >
+ <About />
+ </AppFrame>
)} />
{process.env.NODE_ENV === "development" ? <Route path="/test" component={() => (
- <AppFrame title={"Test"} icon={faAddressBook} >
- <Test />
- </AppFrame>
+ <AppFrame title={"Test"} icon={faAddressBook} >
+ <Test />
+ </AppFrame>
)} /> : null}
<Route path="/login" component={() => (
- <AppFrame title={"Login"} icon={faSignInAlt} >
- <Login />
- </AppFrame>
- )} />
- {Object.keys(registrations).map(p => {
- const application = registrations[p];
- return (<Route key={application.name} path={application.path || `/${application.name}`} component={() => (
- <AppFrame title={application.title || (typeof application.menuEntry === 'string' && application.menuEntry) || application.name} icon={application.icon} appId={application.name} >
- <application.rootComponent />
- </AppFrame>
- )} />)
+ <AppFrame title={"Login"} icon={faSignInAlt} >
+ <Login />
+ </AppFrame>
+ )} />
+ { Object.keys(registrations).map(p => {
+ const application = registrations[p];
+ return (<Route key={application.name} path={application.path || `/${application.name}`} component={() => (
+ <AppFrame title={application.title || (typeof application.menuEntry === 'string' && application.menuEntry) || application.name} icon={application.icon} appId={application.name} >
+ <application.rootComponent />
+ </AppFrame>
+ )} />)
})}
<Redirect to="/" />
</Switch>
diff --git a/sdnr/wt/odlux/framework/src/views/login.tsx b/sdnr/wt/odlux/framework/src/views/login.tsx index b06cf7631..be1fb801f 100644 --- a/sdnr/wt/odlux/framework/src/views/login.tsx +++ b/sdnr/wt/odlux/framework/src/views/login.tsx @@ -32,10 +32,16 @@ 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 connect, { Connect, IDispatcher } from '../flux/connect'; import authenticationService from '../services/authenticationService'; -import { UpdateAuthentication } from '../actions/authentication'; +import { updateExternalLoginProviderAsyncActionCreator } from '../actions/loginProvider'; +import { UpdatePolicies, UpdateUser } from '../actions/authentication'; + +import { IApplicationStoreState } from '../store/applicationStore'; +import { AuthPolicy, AuthToken, User } from '../models/authentication'; +import Menu from '@material-ui/core/Menu'; +import { MenuItem } from '@material-ui/core'; const styles = (theme: Theme) => createStyles({ layout: { @@ -69,14 +75,37 @@ const styles = (theme: Theme) => createStyles({ }, }); -type LoginProps = RouteComponentProps<{}> & WithStyles<typeof styles> & Connect; +const mapProps = (state: IApplicationStoreState) => ({ + search: state.framework.navigationState.search, + authentication: state.framework.applicationState.authentication, + externalLoginProviders: state.framework.applicationState.externalLoginProviders , +}); + +const mapDispatch = (dispatcher: IDispatcher) => ({ + updateExternalProviders: () => dispatcher.dispatch(updateExternalLoginProviderAsyncActionCreator()), + updateAuthentication: (token: AuthToken | null) => { + const user = token && new User(token) || undefined; + dispatcher.dispatch(new UpdateUser(user)); + }, + updatePolicies: (policies?: AuthPolicy[]) => { + return dispatcher.dispatch(new UpdatePolicies(policies)); + }, +}); + +type LoginProps = RouteComponentProps<{}> & WithStyles<typeof styles> & Connect<typeof mapProps, typeof mapDispatch>; interface ILoginState { + externalProviderAnchor: HTMLElement | null; busy: boolean; username: string; password: string; scope: string; message: string; + providers: { + id: string; + title: string; + loginUrl: string; + }[] | null; } @@ -87,14 +116,26 @@ class LoginComponent extends React.Component<LoginProps, ILoginState> { super(props); this.state = { + externalProviderAnchor: null, busy: false, username: '', password: '', scope: 'sdn', - message: '' + message: '', + providers: null, }; } + async componentDidMount(){ + if (this.props.authentication === "oauth" && (this.props.externalLoginProviders == null || this.props.externalLoginProviders.length === 0)){ + this.props.updateExternalProviders(); + } + } + + private setExternalProviderAnchor = (el: HTMLElement | null) => { + this.setState({externalProviderAnchor: el }) + } + render(): JSX.Element { const { classes } = this.props; return ( @@ -153,6 +194,33 @@ class LoginComponent extends React.Component<LoginProps, ILoginState> { > Sign in </Button> + { this.props.externalLoginProviders && this.props.externalLoginProviders.length > 0 + ? + [ + <Button + aria-controls="externalLogin" + aria-haspopup="true" + fullWidth + variant="contained" + color="primary" + className={classes.submit} onClick={(ev) => { this.setExternalProviderAnchor(ev.currentTarget); }}> + Use external Login + </Button>, + <Menu + anchorEl={this.state.externalProviderAnchor} + keepMounted + open={Boolean(this.state.externalProviderAnchor)} + onClose={() => { this.setExternalProviderAnchor(null); }} + > + { + this.props.externalLoginProviders.map((provider) => ( + <MenuItem key={provider.id} onClick={() => { window.location = provider.loginUrl as any; } }>{ provider.title} </MenuItem> + )) + } + </Menu> + ] + : null + } </form> {this.state.message && <Alert severity="error">{this.state.message}</Alert>} </Paper> @@ -165,16 +233,16 @@ class LoginComponent extends React.Component<LoginProps, ILoginState> { event.preventDefault(); this.setState({ busy: true }); - // const token = await authenticationService.authenticateUserOAuth(this.state.username, this.state.password, this.state.scope); - const token = await authenticationService.authenticateUserBasicAuth(this.state.username, this.state.password, this.state.scope); - this.props.dispatch(new UpdateAuthentication(token)); + + const token = this.props.authentication === "oauth" + ? await authenticationService.authenticateUserOAuth(this.state.username, this.state.password, this.state.scope) + : await authenticationService.authenticateUserBasicAuth(this.state.username, this.state.password, this.state.scope); + + this.props.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 query = this.props.search && this.props.search.replace(/^\?/, "").split('&').map(e => e.split("=")); const returnTo = query && query.find(e => e[0] === "returnTo"); this.props.history.replace(returnTo && returnTo[1] || "/"); } @@ -187,5 +255,5 @@ class LoginComponent extends React.Component<LoginProps, ILoginState> { } } -export const Login = withStyles(styles)(withRouter(connect()(LoginComponent))); +export const Login = withStyles(styles)(withRouter(connect(mapProps, mapDispatch)(LoginComponent))); export default Login;
\ No newline at end of file |