summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarrison Healey <harrisonmhealey@gmail.com>2016-05-09 15:56:50 -0400
committerChristopher Speller <crspeller@gmail.com>2016-05-09 15:56:50 -0400
commitff72a126d3f6a45da8968ddc0a8e79721fe64e64 (patch)
tree7d20a7e64d1c003f349b498e9e2d3e831a43076c
parent3eebd15bf02fc767dfec816f2cd785068e8c5f80 (diff)
downloadchat-ff72a126d3f6a45da8968ddc0a8e79721fe64e64.tar.gz
chat-ff72a126d3f6a45da8968ddc0a8e79721fe64e64.tar.bz2
chat-ff72a126d3f6a45da8968ddc0a8e79721fe64e64.zip
PLT-2862 Re-added LDAP login boxes as part of signup flow (#2937)
* Added ldap_only parameter for login API * Re-added LDAP login boxes as part of signup flow
-rw-r--r--api/user.go9
-rw-r--r--api/user_test.go17
-rw-r--r--model/client.go8
-rw-r--r--webapp/client/client.jsx6
-rw-r--r--webapp/components/signup_user_complete.jsx195
-rw-r--r--webapp/utils/web_client.jsx22
6 files changed, 234 insertions, 23 deletions
diff --git a/api/user.go b/api/user.go
index 60162d8f1..c53a643c7 100644
--- a/api/user.go
+++ b/api/user.go
@@ -436,6 +436,7 @@ func login(c *Context, w http.ResponseWriter, r *http.Request) {
password := props["password"]
mfaToken := props["token"]
deviceId := props["device_id"]
+ ldapOnly := props["ldap_only"] == "true"
if len(password) == 0 {
c.Err = model.NewLocAppError("login", "api.user.login.blank_pwd.app_error", nil, "")
@@ -460,7 +461,7 @@ func login(c *Context, w http.ResponseWriter, r *http.Request) {
} else {
c.LogAudit("attempt")
- if user, err = getUserForLogin(loginId); err != nil {
+ if user, err = getUserForLogin(loginId, ldapOnly); err != nil {
c.LogAudit("failure")
c.Err = err
return
@@ -485,13 +486,13 @@ func login(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write([]byte(user.ToJson()))
}
-func getUserForLogin(loginId string) (*model.User, *model.AppError) {
+func getUserForLogin(loginId string, onlyLdap bool) (*model.User, *model.AppError) {
ldapAvailable := *utils.Cfg.LdapSettings.Enable && einterfaces.GetLdapInterface() != nil
if result := <-Srv.Store.User().GetForLogin(
loginId,
- *utils.Cfg.EmailSettings.EnableSignInWithUsername,
- *utils.Cfg.EmailSettings.EnableSignInWithEmail,
+ *utils.Cfg.EmailSettings.EnableSignInWithUsername && !onlyLdap,
+ *utils.Cfg.EmailSettings.EnableSignInWithEmail && !onlyLdap,
ldapAvailable,
); result.Err != nil {
diff --git a/api/user_test.go b/api/user_test.go
index 1a3b36d4b..9dd57dc20 100644
--- a/api/user_test.go
+++ b/api/user_test.go
@@ -204,6 +204,23 @@ func TestLogin(t *testing.T) {
}
}
+func TestLoginByLdap(t *testing.T) {
+ th := Setup()
+ Client := th.CreateClient()
+
+ team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
+ rteam, _ := Client.CreateTeam(&team)
+
+ user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Username: "corey" + model.NewId(), Password: "pwd"}
+ ruser, _ := Client.CreateUser(&user, "")
+ LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
+ store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
+
+ if _, err := Client.LoginByLdap(ruser.Data.(*model.User).Id, user.Password); err == nil {
+ t.Fatal("should've failed to log in with non-ldap user")
+ }
+}
+
func TestLoginWithDeviceId(t *testing.T) {
th := Setup().InitBasic()
Client := th.BasicClient
diff --git a/model/client.go b/model/client.go
index 1575df9e0..152aaa706 100644
--- a/model/client.go
+++ b/model/client.go
@@ -362,6 +362,14 @@ func (c *Client) Login(loginId string, password string) (*Result, *AppError) {
return c.login(m)
}
+func (c *Client) LoginByLdap(loginId string, password string) (*Result, *AppError) {
+ m := make(map[string]string)
+ m["login_id"] = loginId
+ m["password"] = password
+ m["ldap_only"] = "true"
+ return c.login(m)
+}
+
func (c *Client) LoginWithDevice(loginId string, password string, deviceId string) (*Result, *AppError) {
m := make(map[string]string)
m["login_id"] = loginId
diff --git a/webapp/client/client.jsx b/webapp/client/client.jsx
index 5d0dd07c9..c81c5a1d7 100644
--- a/webapp/client/client.jsx
+++ b/webapp/client/client.jsx
@@ -759,6 +759,12 @@ export default class Client {
this.track('api', 'api_users_login', '', 'id', id);
}
+ loginByLdap = (loginId, password, mfaToken, success, error) => {
+ this.doLogin({login_id: loginId, password, token: mfaToken, ldap_only: 'true'}, success, error);
+
+ this.track('api', 'api_users_login', '', 'login_id', loginId);
+ }
+
doLogin = (outgoingData, success, error) => {
var outer = this; // eslint-disable-line consistent-this
diff --git a/webapp/components/signup_user_complete.jsx b/webapp/components/signup_user_complete.jsx
index 6dd26f391..5c06cefed 100644
--- a/webapp/components/signup_user_complete.jsx
+++ b/webapp/components/signup_user_complete.jsx
@@ -1,6 +1,7 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
+import FormError from 'components/form_error.jsx';
import LoadingScreen from 'components/loading_screen.jsx';
import * as GlobalActions from 'action_creators/global_actions.jsx';
@@ -19,11 +20,15 @@ import ReactDOM from 'react-dom';
import logoImage from 'images/logo.png';
-class SignupUserComplete extends React.Component {
+export default class SignupUserComplete extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
+ this.handleLdapSignup = this.handleLdapSignup.bind(this);
+
+ this.handleLdapIdChange = this.handleLdapIdChange.bind(this);
+ this.handleLdapPasswordChange = this.handleLdapPasswordChange.bind(this);
this.state = {
data: '',
@@ -35,9 +40,12 @@ class SignupUserComplete extends React.Component {
teamId: '',
openServer: false,
loading: true,
- inviteId: ''
+ inviteId: '',
+ ldapId: '',
+ ldapPassword: ''
};
}
+
componentWillMount() {
let data = this.props.location.query.d;
let hash = this.props.location.query.h;
@@ -148,6 +156,48 @@ class SignupUserComplete extends React.Component {
});
}
+ handleLdapSignup(e) {
+ e.preventDefault();
+
+ this.setState({ldapError: ''});
+
+ Client.webLoginByLdap(
+ this.state.ldapId,
+ this.state.ldapPassword,
+ null,
+ () => {
+ GlobalActions.emitInitialLoad(
+ () => {
+ browserHistory.push('/select_team');
+ }
+ );
+ },
+ (err) => {
+ if (err.id === 'ent.ldap.do_login.user_not_registered.app_error' || err.id === 'ent.ldap.do_login.user_filtered.app_error') {
+ this.setState({
+ ldapError: (
+ <FormattedMessage
+ id='login.userNotFound'
+ defaultMessage="We couldn't find an account matching your login credentials."
+ />
+ )
+ });
+ } else if (err.id === 'ent.ldap.do_login.invalid_password.app_error') {
+ this.setState({
+ ldapError: (
+ <FormattedMessage
+ id='login.invalidPassword'
+ defaultMessage='Your password is incorrect.'
+ />
+ )
+ });
+ } else {
+ this.setState({ldapError: err.message});
+ }
+ }
+ );
+ }
+
handleSubmit(e) {
e.preventDefault();
@@ -277,6 +327,80 @@ class SignupUserComplete extends React.Component {
}
);
}
+
+ handleLdapIdChange(e) {
+ e.preventDefault();
+
+ this.setState({
+ ldapId: e.target.value
+ });
+ }
+
+ handleLdapPasswordChange(e) {
+ e.preventDefault();
+
+ this.setState({
+ ldapPassword: e.target.value
+ });
+ }
+
+ renderLdapLogin() {
+ let ldapIdPlaceholder;
+ if (global.window.mm_config.LdapLoginFieldName) {
+ ldapIdPlaceholder = global.window.mm_config.LdapLoginFieldName;
+ } else {
+ ldapIdPlaceholder = Utils.localizeMessage('login.ldap_username', 'LDAP Username');
+ }
+
+ let errorClass = '';
+ if (this.state.ldapError) {
+ errorClass += ' has-error';
+ }
+
+ return (
+ <form
+ onSubmit={this.handleLdapSignup}
+ >
+ <div className='signup__email-container'>
+ <FormError error={this.state.ldapError}/>
+ <div className={'form-group' + errorClass}>
+ <input
+ className='form-control'
+ name='ldapId'
+ value={this.state.ldapId}
+ onChange={this.handleLdapIdChange}
+ placeholder={ldapIdPlaceholder}
+ spellCheck='false'
+ />
+ </div>
+ <div className={'form-group' + errorClass}>
+ <input
+ type='password'
+ className='form-control'
+ name='password'
+ value={this.state.ldapPassword}
+ onChange={this.handleLdapPasswordChange}
+ placeholder={Utils.localizeMessage('login.password', 'Password')}
+ spellCheck='false'
+ />
+ </div>
+ <div className='form-group'>
+ <button
+ type='submit'
+ className='btn btn-primary'
+ disabled={!this.state.ldapId || !this.state.ldapPassword}
+ >
+ <FormattedMessage
+ id='login.signIn'
+ defaultMessage='Sign in'
+ />
+ </button>
+ </div>
+ </div>
+ </form>
+ );
+ }
+
render() {
Client.track('signup', 'signup_user_01_welcome');
@@ -431,6 +555,23 @@ class SignupUserComplete extends React.Component {
);
}
+ let ldapSignup;
+ if (global.window.mm_config.EnableLdap === 'true' && global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.LDAP) {
+ ldapSignup = (
+ <div className='inner__content'>
+ <h5>
+ <strong>
+ <FormattedMessage
+ id='signup_user_completed.withLdap'
+ defaultMessage='With your LDAP credentials'
+ />
+ </strong>
+ </h5>
+ {this.renderLdapLogin()}
+ </div>
+ );
+ }
+
let emailSignup;
if (global.window.mm_config.EnableSignUpWithEmail === 'true') {
emailSignup = (
@@ -494,7 +635,7 @@ class SignupUserComplete extends React.Component {
);
}
- if (signupMessage.length > 0 && emailSignup) {
+ if (signupMessage.length > 0 && (emailSignup || ldapSignup)) {
signupMessage = (
<div>
{signupMessage}
@@ -508,7 +649,36 @@ class SignupUserComplete extends React.Component {
);
}
- if (signupMessage.length === 0 && !emailSignup) {
+ if (ldapSignup && emailSignup) {
+ ldapSignup = (
+ <div>
+ {ldapSignup}
+ <div className='or__container'>
+ <FormattedMessage
+ id='signup_user_completed.or'
+ defaultMessage='or'
+ />
+ </div>
+ </div>
+ );
+ }
+
+ let terms = null;
+ if (!this.state.noOpenServerError && (emailSignup || ldapSignup)) {
+ terms = (
+ <p>
+ <FormattedHTMLMessage
+ id='create_team.agreement'
+ defaultMessage="By proceeding to create your account and use {siteName}, you agree to our <a href='/static/help/terms.html'>Terms of Service</a> and <a href='/static/help/privacy.html'>Privacy Policy</a>. If you do not agree, you cannot use {siteName}."
+ values={{
+ siteName: global.window.mm_config.SiteName
+ }}
+ />
+ </p>
+ );
+ }
+
+ if (signupMessage.length === 0 && !emailSignup && !ldapSignup) {
emailSignup = (
<div>
<FormattedMessage
@@ -519,22 +689,10 @@ class SignupUserComplete extends React.Component {
);
}
- let terms = (
- <p>
- <FormattedHTMLMessage
- id='create_team.agreement'
- defaultMessage="By proceeding to create your account and use {siteName}, you agree to our <a href='/static/help/terms.html'>Terms of Service</a> and <a href='/static/help/privacy.html'>Privacy Policy</a>. If you do not agree, you cannot use {siteName}."
- values={{
- siteName: global.window.mm_config.SiteName
- }}
- />
- </p>
- );
-
if (this.state.noOpenServerError) {
signupMessage = null;
emailSignup = null;
- terms = null;
+ ldapSignup = null;
}
return (
@@ -566,6 +724,7 @@ class SignupUserComplete extends React.Component {
/>
</h4>
{signupMessage}
+ {ldapSignup}
{emailSignup}
{serverError}
{terms}
@@ -581,5 +740,3 @@ SignupUserComplete.defaultProps = {
SignupUserComplete.propTypes = {
location: React.PropTypes.object
};
-
-export default SignupUserComplete;
diff --git a/webapp/utils/web_client.jsx b/webapp/utils/web_client.jsx
index 3efb32806..642e523b7 100644
--- a/webapp/utils/web_client.jsx
+++ b/webapp/utils/web_client.jsx
@@ -60,6 +60,28 @@ class WebClientClass extends Client {
}
);
}
+
+ webLoginByLdap(loginId, password, token, success, error) {
+ this.loginByLdap(
+ loginId,
+ password,
+ token,
+ (data) => {
+ this.track('api', 'api_users_login_success', '', 'login_id', loginId);
+ BrowserStore.signalLogin();
+
+ if (success) {
+ success(data);
+ }
+ },
+ (err) => {
+ this.track('api', 'api_users_login_fail', name, 'login_id', loginId);
+ if (error) {
+ error(err);
+ }
+ }
+ );
+ }
}
var WebClient = new WebClientClass();