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
Этот коммит содержится в:
Harrison Healey
2016-05-09 15:56:50 -04:00
коммит произвёл Christopher Speller
родитель 3eebd15bf0
Коммит ff72a126d3
6 изменённых файлов: 234 добавлений и 23 удалений

Просмотреть файл

@@ -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 {

Просмотреть файл

@@ -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

Просмотреть файл

@@ -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

Просмотреть файл

@@ -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

Просмотреть файл

@@ -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;

Просмотреть файл

@@ -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();