diff --git a/frontend/src/component/user/authentication-component.jsx b/frontend/src/component/user/authentication-component.jsx index 8259d228b9..a9f684861d 100644 --- a/frontend/src/component/user/authentication-component.jsx +++ b/frontend/src/component/user/authentication-component.jsx @@ -4,8 +4,10 @@ import { Card, CardTitle, CardText } from 'react-mdl'; import Modal from 'react-modal'; import AuthenticationSimpleComponent from './authentication-simple-component'; import AuthenticationCustomComponent from './authentication-custom-component'; +import AuthenticationPasswordComponent from './authentication-password-component'; const SIMPLE_TYPE = 'unsecure'; +const PASSWORD_TYPE = 'password'; const customStyles = { overlay: { @@ -34,7 +36,9 @@ class AuthComponent extends React.Component { static propTypes = { user: PropTypes.object.isRequired, unsecureLogin: PropTypes.func.isRequired, + passwordLogin: PropTypes.func.isRequired, fetchFeatureToggles: PropTypes.func.isRequired, + fetchUIConfig: PropTypes.func.isRequired, history: PropTypes.object.isRequired, }; @@ -43,7 +47,17 @@ class AuthComponent extends React.Component { if (!authDetails) return null; let content; - if (authDetails.type === SIMPLE_TYPE) { + if (authDetails.type === PASSWORD_TYPE) { + content = ( + + ); + } else if (authDetails.type === SIMPLE_TYPE) { content = ( - Action required! + Action Required {content} diff --git a/frontend/src/component/user/authentication-container.jsx b/frontend/src/component/user/authentication-container.jsx index edc26c530e..1dee4e0885 100644 --- a/frontend/src/component/user/authentication-container.jsx +++ b/frontend/src/component/user/authentication-container.jsx @@ -1,11 +1,14 @@ import { connect } from 'react-redux'; import AuthenticationComponent from './authentication-component'; -import { unsecureLogin } from '../../store/user/actions'; +import { unsecureLogin, passwordLogin } from '../../store/user/actions'; import { fetchFeatureToggles } from '../../store/feature-actions'; +import { fetchUIConfig } from '../../store/ui-config/actions'; const mapDispatchToProps = { unsecureLogin, + passwordLogin, fetchFeatureToggles, + fetchUIConfig, }; const mapStateToProps = state => ({ diff --git a/frontend/src/component/user/authentication-password-component.jsx b/frontend/src/component/user/authentication-password-component.jsx new file mode 100644 index 0000000000..dd1c1c4ce3 --- /dev/null +++ b/frontend/src/component/user/authentication-password-component.jsx @@ -0,0 +1,87 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { CardActions, Button, Textfield } from 'react-mdl'; + +class EnterpriseAuthenticationComponent extends React.Component { + static propTypes = { + authDetails: PropTypes.object.isRequired, + passwordLogin: PropTypes.func.isRequired, + fetchFeatureToggles: PropTypes.func.isRequired, + fetchUIConfig: PropTypes.func.isRequired, + history: PropTypes.object.isRequired, + }; + + constructor() { + super(); + this.state = {}; + } + + handleSubmit = async evt => { + evt.preventDefault(); + const { username, password } = this.state; + + if (!username) { + this.setState({ usernameError: 'This is a required field' }); + return; + } + if (!password) { + this.setState({ passwordError: 'This is a required field' }); + return; + } + const user = { username, password }; + const path = evt.target.action; + + try { + await this.props.passwordLogin(path, user); + await this.props.fetchFeatureToggles(); + await this.props.fetchUIConfig(); + this.props.history.push(`/`); + } catch (error) { + if (error.statusCode === 404) { + this.setState({ error: 'User not found', password: '' }); + } else if (error.statusCode === 400) { + this.setState({ error: 'Wrong password', password: '' }); + } else { + this.setState({ error: 'Could not sign in at the moment.' }); + } + } + }; + + render() { + const authDetails = this.props.authDetails; + const { username, usernameError, password, passwordError, error } = this.state; + return ( +
+

{authDetails.message}

+

{error}

+ this.setState({ username: evt.target.value })} + value={username} + error={usernameError} + /> + this.setState({ password: evt.target.value })} + floatingLabel + name="password" + type="password" + value={password} + error={passwordError} + /> +
+ + + + + + ); + } +} + +export default EnterpriseAuthenticationComponent; diff --git a/frontend/src/data/helper.js b/frontend/src/data/helper.js index 00d18e8fde..31d3874ae4 100644 --- a/frontend/src/data/helper.js +++ b/frontend/src/data/helper.js @@ -8,9 +8,10 @@ function extractLegacyMsg(body) { } class ServiceError extends Error { - constructor() { + constructor(statusCode = 500) { super(defaultErrorMessage); this.name = 'ServiceError'; + this.statusCode = statusCode; } } @@ -52,7 +53,7 @@ export function throwIfNotSuccess(response) { }); }); } else { - return Promise.reject(new ServiceError()); + return Promise.reject(new ServiceError(response.status)); } } return Promise.resolve(response); diff --git a/frontend/src/data/user-api.js b/frontend/src/data/user-api.js index ccab844390..4463f166ac 100644 --- a/frontend/src/data/user-api.js +++ b/frontend/src/data/user-api.js @@ -20,8 +20,18 @@ function unsecureLogin(path, user) { .then(response => response.json()); } +function passwordLogin(path, data) { + return fetch(path, { + method: 'POST', + credentials: 'include', + headers, + body: JSON.stringify(data), + }).then(throwIfNotSuccess); +} + export default { fetchUser, unsecureLogin, logoutUser, + passwordLogin, }; diff --git a/frontend/src/store/user/actions.js b/frontend/src/store/user/actions.js index 67ee98d574..cd47bf68d6 100644 --- a/frontend/src/store/user/actions.js +++ b/frontend/src/store/user/actions.js @@ -38,6 +38,14 @@ export function unsecureLogin(path, user) { }; } +export function passwordLogin(path, user) { + return dispatch => { + dispatch({ type: START_FETCH_USER }); + + return api.passwordLogin(path, user).then(json => dispatch(updateUser(json))); + }; +} + export function logoutUser() { return dispatch => { dispatch({ type: USER_LOGOUT }); diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js index 60244e5585..274c8dc0a4 100644 --- a/frontend/webpack.config.js +++ b/frontend/webpack.config.js @@ -115,6 +115,11 @@ module.exports = { changeOrigin: true, secure: false, }, + '/auth': { + target: process.env.UNLEASH_API || 'http://localhost:4242', + changeOrigin: true, + secure: false, + }, }, port: process.env.PORT || 3000, },