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
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
3eebd15bf0
Коммит
ff72a126d3
@@ -436,6 +436,7 @@ func login(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
password := props["password"]
|
password := props["password"]
|
||||||
mfaToken := props["token"]
|
mfaToken := props["token"]
|
||||||
deviceId := props["device_id"]
|
deviceId := props["device_id"]
|
||||||
|
ldapOnly := props["ldap_only"] == "true"
|
||||||
|
|
||||||
if len(password) == 0 {
|
if len(password) == 0 {
|
||||||
c.Err = model.NewLocAppError("login", "api.user.login.blank_pwd.app_error", nil, "")
|
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 {
|
} else {
|
||||||
c.LogAudit("attempt")
|
c.LogAudit("attempt")
|
||||||
|
|
||||||
if user, err = getUserForLogin(loginId); err != nil {
|
if user, err = getUserForLogin(loginId, ldapOnly); err != nil {
|
||||||
c.LogAudit("failure")
|
c.LogAudit("failure")
|
||||||
c.Err = err
|
c.Err = err
|
||||||
return
|
return
|
||||||
@@ -485,13 +486,13 @@ func login(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Write([]byte(user.ToJson()))
|
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
|
ldapAvailable := *utils.Cfg.LdapSettings.Enable && einterfaces.GetLdapInterface() != nil
|
||||||
|
|
||||||
if result := <-Srv.Store.User().GetForLogin(
|
if result := <-Srv.Store.User().GetForLogin(
|
||||||
loginId,
|
loginId,
|
||||||
*utils.Cfg.EmailSettings.EnableSignInWithUsername,
|
*utils.Cfg.EmailSettings.EnableSignInWithUsername && !onlyLdap,
|
||||||
*utils.Cfg.EmailSettings.EnableSignInWithEmail,
|
*utils.Cfg.EmailSettings.EnableSignInWithEmail && !onlyLdap,
|
||||||
ldapAvailable,
|
ldapAvailable,
|
||||||
); result.Err != nil {
|
); 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) {
|
func TestLoginWithDeviceId(t *testing.T) {
|
||||||
th := Setup().InitBasic()
|
th := Setup().InitBasic()
|
||||||
Client := th.BasicClient
|
Client := th.BasicClient
|
||||||
|
|||||||
@@ -362,6 +362,14 @@ func (c *Client) Login(loginId string, password string) (*Result, *AppError) {
|
|||||||
return c.login(m)
|
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) {
|
func (c *Client) LoginWithDevice(loginId string, password string, deviceId string) (*Result, *AppError) {
|
||||||
m := make(map[string]string)
|
m := make(map[string]string)
|
||||||
m["login_id"] = loginId
|
m["login_id"] = loginId
|
||||||
|
|||||||
@@ -759,6 +759,12 @@ export default class Client {
|
|||||||
this.track('api', 'api_users_login', '', 'id', id);
|
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) => {
|
doLogin = (outgoingData, success, error) => {
|
||||||
var outer = this; // eslint-disable-line consistent-this
|
var outer = this; // eslint-disable-line consistent-this
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
import FormError from 'components/form_error.jsx';
|
||||||
import LoadingScreen from 'components/loading_screen.jsx';
|
import LoadingScreen from 'components/loading_screen.jsx';
|
||||||
import * as GlobalActions from 'action_creators/global_actions.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';
|
import logoImage from 'images/logo.png';
|
||||||
|
|
||||||
class SignupUserComplete extends React.Component {
|
export default class SignupUserComplete extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.handleSubmit = this.handleSubmit.bind(this);
|
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 = {
|
this.state = {
|
||||||
data: '',
|
data: '',
|
||||||
@@ -35,9 +40,12 @@ class SignupUserComplete extends React.Component {
|
|||||||
teamId: '',
|
teamId: '',
|
||||||
openServer: false,
|
openServer: false,
|
||||||
loading: true,
|
loading: true,
|
||||||
inviteId: ''
|
inviteId: '',
|
||||||
|
ldapId: '',
|
||||||
|
ldapPassword: ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
let data = this.props.location.query.d;
|
let data = this.props.location.query.d;
|
||||||
let hash = this.props.location.query.h;
|
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) {
|
handleSubmit(e) {
|
||||||
e.preventDefault();
|
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() {
|
render() {
|
||||||
Client.track('signup', 'signup_user_01_welcome');
|
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;
|
let emailSignup;
|
||||||
if (global.window.mm_config.EnableSignUpWithEmail === 'true') {
|
if (global.window.mm_config.EnableSignUpWithEmail === 'true') {
|
||||||
emailSignup = (
|
emailSignup = (
|
||||||
@@ -494,7 +635,7 @@ class SignupUserComplete extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signupMessage.length > 0 && emailSignup) {
|
if (signupMessage.length > 0 && (emailSignup || ldapSignup)) {
|
||||||
signupMessage = (
|
signupMessage = (
|
||||||
<div>
|
<div>
|
||||||
{signupMessage}
|
{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 = (
|
emailSignup = (
|
||||||
<div>
|
<div>
|
||||||
<FormattedMessage
|
<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) {
|
if (this.state.noOpenServerError) {
|
||||||
signupMessage = null;
|
signupMessage = null;
|
||||||
emailSignup = null;
|
emailSignup = null;
|
||||||
terms = null;
|
ldapSignup = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -566,6 +724,7 @@ class SignupUserComplete extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</h4>
|
</h4>
|
||||||
{signupMessage}
|
{signupMessage}
|
||||||
|
{ldapSignup}
|
||||||
{emailSignup}
|
{emailSignup}
|
||||||
{serverError}
|
{serverError}
|
||||||
{terms}
|
{terms}
|
||||||
@@ -581,5 +740,3 @@ SignupUserComplete.defaultProps = {
|
|||||||
SignupUserComplete.propTypes = {
|
SignupUserComplete.propTypes = {
|
||||||
location: React.PropTypes.object
|
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();
|
var WebClient = new WebClientClass();
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user