From 87989b8afd4666a72940389db716b6500d0a9ec3 Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Tue, 3 May 2016 14:10:36 -0400 Subject: PLT-2258 Unified login screen and related APIs (#2820) * Unified login screen and related APIs * Refactored login API call to be less convoluted * Removed LDAP login prompt from invite process * Fixed existing LDAP users being able to log in if LDAP was configured, but disabled * Gofmt * Future proofed login API * Updated login APIs based on feedback * Added additional auditing to login API * Actually removed loginById --- webapp/components/login/login.jsx | 320 ++++++++++++++++++++------------------ 1 file changed, 170 insertions(+), 150 deletions(-) (limited to 'webapp/components/login/login.jsx') diff --git a/webapp/components/login/login.jsx b/webapp/components/login/login.jsx index f6c02f6a3..64ef72995 100644 --- a/webapp/components/login/login.jsx +++ b/webapp/components/login/login.jsx @@ -1,13 +1,11 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -import LoginEmail from './components/login_email.jsx'; -import LoginUsername from './components/login_username.jsx'; -import LoginLdap from './components/login_ldap.jsx'; import LoginMfa from './components/login_mfa.jsx'; import ErrorBar from 'components/error_bar.jsx'; +import FormError from 'components/form_error.jsx'; -import * as GlobalActions from '../../action_creators/global_actions.jsx'; +import * as GlobalActions from 'action_creators/global_actions.jsx'; import UserStore from 'stores/user_store.jsx'; import Client from 'utils/web_client.jsx'; @@ -30,10 +28,16 @@ export default class Login extends React.Component { this.submit = this.submit.bind(this); this.finishSignin = this.finishSignin.bind(this); - const state = {}; - state.showMfa = false; - this.state = state; + this.handleLoginIdChange = this.handleLoginIdChange.bind(this); + this.handlePasswordChange = this.handlePasswordChange.bind(this); + + this.state = { + loginId: '', // the browser will set a default for this + password: '', + showMfa: false + }; } + componentDidMount() { document.title = global.window.mm_config.SiteName; @@ -41,31 +45,97 @@ export default class Login extends React.Component { browserHistory.push('/select_team'); } } - preSubmit(method, loginId, password) { + + preSubmit(e) { + e.preventDefault(); + + const loginId = this.state.loginId.trim(); + if (!loginId) { + const ldapEnabled = global.window.mm_config.EnableLdap === 'true'; + const usernameSigninEnabled = global.window.mm_config.EnableSignInWithUsername === 'true'; + const emailSigninEnabled = global.window.mm_config.EnableSignInWithEmail === 'true'; + + this.setState({ + serverError: ( + + ) + }); + + return; + } + + const password = this.state.password.trim(); + if (!password) { + this.setState({ + serverError: ( + + ) + }); + + return; + } + if (global.window.mm_config.EnableMultifactorAuthentication !== 'true') { - this.submit(method, loginId, password, ''); + this.submit(loginId, password, ''); return; } - Client.checkMfa(method, loginId, + Client.checkMfa( + loginId, (data) => { if (data.mfa_required === 'true') { - this.setState({showMfa: true, method, loginId, password}); + this.setState({showMfa: true}); } else { - this.submit(method, loginId, password, ''); + this.submit(loginId, password, ''); } }, (err) => { - if (method === Constants.EMAIL_SERVICE) { - this.setState({serverEmailError: err.message}); - } else if (method === Constants.USERNAME_SERVICE) { - this.setState({serverUsernameError: err.message}); - } else if (method === Constants.LDAP_SERVICE) { - this.setState({serverLdapError: err.message}); + this.setState({serverError: err.message}); + } + ); + } + + submit(loginId, password, token) { + this.setState({showMfa: false, serverError: null}); + + Client.webLogin( + loginId, + password, + token, + () => { + this.finishSignin(); + }, + (err) => { + if (err.id === 'api.user.login.not_verified.app_error') { + browserHistory.push('/should_verify_email?&email=' + encodeURIComponent(loginId)); + return; + } else if (err.id === 'store.sql_user.get_for_login.app_error' || + err.id === 'ent.ldap.do_login.user_not_registered.app_error' || + err.id === 'ent.ldap.do_login.user_filtered.app_error') { + this.setState({ + serverError: ( + + ) + }); + } else { + this.setState({serverError: err.message}); } } ); } + finishSignin() { GlobalActions.emitInitialLoad( () => { @@ -74,72 +144,18 @@ export default class Login extends React.Component { ); } - submit(method, loginId, password, token) { - this.setState({showMfa: false, serverEmailError: null, serverUsernameError: null, serverLdapError: null}); - - if (method === Constants.EMAIL_SERVICE) { - Client.webLogin( - loginId, - null, - password, - token, - () => { - UserStore.setLastEmail(loginId); - this.finishSignin(); - }, - (err) => { - if (err.id === 'api.user.login.not_verified.app_error') { - browserHistory.push('/should_verify_email?&email=' + encodeURIComponent(loginId)); - return; - } - this.setState({serverEmailError: err.message}); - } - ); - } else if (method === Constants.USERNAME_SERVICE) { - Client.webLogin( - null, - loginId, - password, - token, - () => { - UserStore.setLastUsername(loginId); - - const redirect = Utils.getUrlParameter('redirect'); - if (redirect) { - browserHistory.push(decodeURIComponent(redirect)); - } else { - this.finishSignin(); - } - }, - (err) => { - if (err.id === 'api.user.login.not_verified.app_error') { - this.setState({serverUsernameError: Utils.localizeMessage('login_username.verifyEmailError', 'Please verify your email address. Check your inbox for an email.')}); - } else if (err.id === 'store.sql_user.get_by_username.app_error') { - this.setState({serverUsernameError: Utils.localizeMessage('login_username.userNotFoundError', 'We couldn\'t find an existing account matching your username for this team.')}); - } else { - this.setState({serverUsernameError: err.message}); - } - } - ); - } else if (method === Constants.LDAP_SERVICE) { - Client.loginByLdap( - loginId, - password, - token, - () => { - const redirect = Utils.getUrlParameter('redirect'); - if (redirect) { - browserHistory.push(decodeURIComponent(redirect)); - } else { - this.finishSignin(); - } - }, - (err) => { - this.setState({serverLdapError: err.message}); - } - ); - } + handleLoginIdChange(e) { + this.setState({ + loginId: e.target.value + }); + } + + handlePasswordChange(e) { + this.setState({ + password: e.target.value + }); } + createCustomLogin() { if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.CustomBrand === 'true' && @@ -158,6 +174,36 @@ export default class Login extends React.Component { return null; } + + createLoginPlaceholder(emailSigninEnabled, usernameSigninEnabled, ldapEnabled) { + const loginPlaceholders = []; + if (emailSigninEnabled) { + loginPlaceholders.push(Utils.localizeMessage('login.email', 'Email')); + } + + if (usernameSigninEnabled) { + loginPlaceholders.push(Utils.localizeMessage('login.username', 'Username')); + } + + if (ldapEnabled) { + if (global.window.mm_config.LdapLoginFieldName) { + loginPlaceholders.push(global.window.mm_config.LdapLoginFieldName); + } else { + loginPlaceholders.push(Utils.localizeMessage('login.ldap_username', 'LDAP Username')); + } + } + + if (loginPlaceholders.length >= 2) { + return loginPlaceholders.slice(0, loginPlaceholders.length - 1).join(', ') + + Utils.localizeMessage('login.placeholderOr', ' or ') + + loginPlaceholders[loginPlaceholders.length - 1]; + } else if (loginPlaceholders.length === 1) { + return loginPlaceholders[0]; + } + + return ''; + } + createLoginOptions() { const extraParam = Utils.getUrlParameter('extra'); let extraBox = ''; @@ -248,76 +294,52 @@ export default class Login extends React.Component { ); } - let emailLogin; - if (emailSigninEnabled) { - emailLogin = ( - - ); - - if (oauthLogins.length > 0) { - emailLogin = ( -
-
- -
- {emailLogin} -
- ); + let login = null; + if (emailSigninEnabled || usernameSigninEnabled || ldapEnabled) { + let errorClass = ''; + if (this.state.serverError) { + errorClass = ' has-error'; } - } - - let usernameLogin; - if (usernameSigninEnabled) { - usernameLogin = ( - - ); - if (emailSigninEnabled || oauthLogins.length > 0) { - usernameLogin = ( -
-
- +
+ +
+
- {usernameLogin} -
- ); - } - } - - let ldapLogin; - if (ldapEnabled) { - ldapLogin = ( - - ); - - if (emailSigninEnabled || usernameSigninEnabled || oauthLogins.length > 0) { - ldapLogin = ( -
-
- +
- {ldapLogin} +
+ +
- ); - } + + ); } const userSignUp = ( @@ -358,14 +380,13 @@ export default class Login extends React.Component {
{extraBox} {oauthLogins} - {emailLogin} - {usernameLogin} - {ldapLogin} + {login} {userSignUp} {forgotPassword}
); } + render() { let content; let customContent; @@ -373,7 +394,6 @@ export default class Login extends React.Component { if (this.state.showMfa) { content = (