Fixing LDAP editing of attributes (#2824)
Этот коммит содержится в:
2
Makefile
2
Makefile
@@ -145,7 +145,7 @@ test: start-docker
|
|||||||
|
|
||||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=340s ./api || exit 1
|
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=340s ./api || exit 1
|
||||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=12s ./model || exit 1
|
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=12s ./model || exit 1
|
||||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./store || exit 1
|
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=180s ./store || exit 1
|
||||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./utils || exit 1
|
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./utils || exit 1
|
||||||
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./web || exit 1
|
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./web || exit 1
|
||||||
ifeq ($(BUILD_ENTERPRISE_READY),true)
|
ifeq ($(BUILD_ENTERPRISE_READY),true)
|
||||||
|
|||||||
@@ -3495,6 +3495,10 @@
|
|||||||
"id": "store.sql_user.update.app_error",
|
"id": "store.sql_user.update.app_error",
|
||||||
"translation": "We couldn't update the account"
|
"translation": "We couldn't update the account"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "store.sql_user.update.can_not_change_ldap.app_error",
|
||||||
|
"translation": "Can not change fields set by LDAP"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "store.sql_user.update.email_taken.app_error",
|
"id": "store.sql_user.update.email_taken.app_error",
|
||||||
"translation": "This email is already taken. Please choose another."
|
"translation": "This email is already taken. Please choose another."
|
||||||
|
|||||||
@@ -136,7 +136,17 @@ func (us SqlUserStore) Update(user *model.User, allowActiveUpdate bool) StoreCha
|
|||||||
|
|
||||||
if user.IsOAuthUser() {
|
if user.IsOAuthUser() {
|
||||||
user.Email = oldUser.Email
|
user.Email = oldUser.Email
|
||||||
} else if !user.IsLDAPUser() && user.Email != oldUser.Email {
|
} else if user.IsLDAPUser() {
|
||||||
|
if user.Username != oldUser.Username ||
|
||||||
|
user.FirstName != oldUser.FirstName ||
|
||||||
|
user.LastName != oldUser.LastName ||
|
||||||
|
user.Email != oldUser.Email {
|
||||||
|
result.Err = model.NewLocAppError("SqlUserStore.Update", "store.sql_user.update.can_not_change_ldap.app_error", nil, "user_id="+user.Id)
|
||||||
|
storeChannel <- result
|
||||||
|
close(storeChannel)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if user.Email != oldUser.Email {
|
||||||
user.EmailVerified = false
|
user.EmailVerified = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,12 @@ func TestUserStoreUpdate(t *testing.T) {
|
|||||||
Must(store.User().Save(u1))
|
Must(store.User().Save(u1))
|
||||||
Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}))
|
Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}))
|
||||||
|
|
||||||
|
u2 := &model.User{}
|
||||||
|
u2.Email = model.NewId()
|
||||||
|
u2.AuthService = "ldap"
|
||||||
|
Must(store.User().Save(u2))
|
||||||
|
Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u2.Id}))
|
||||||
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
if err := (<-store.User().Update(u1, false)).Err; err != nil {
|
if err := (<-store.User().Update(u1, false)).Err; err != nil {
|
||||||
@@ -92,6 +98,11 @@ func TestUserStoreUpdate(t *testing.T) {
|
|||||||
if err := (<-store.User().Update(u1, false)).Err; err == nil {
|
if err := (<-store.User().Update(u1, false)).Err; err == nil {
|
||||||
t.Fatal("Update should have faile because id change")
|
t.Fatal("Update should have faile because id change")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u2.Email = model.NewId()
|
||||||
|
if err := (<-store.User().Update(u2, false)).Err; err == nil {
|
||||||
|
t.Fatal("Update should have failed because you can't modify LDAP fields")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUserStoreUpdateLastPingAt(t *testing.T) {
|
func TestUserStoreUpdateLastPingAt(t *testing.T) {
|
||||||
|
|||||||
@@ -259,6 +259,7 @@ func getClientConfig(c *model.Config) map[string]string {
|
|||||||
props["EnableLdap"] = strconv.FormatBool(*c.LdapSettings.Enable)
|
props["EnableLdap"] = strconv.FormatBool(*c.LdapSettings.Enable)
|
||||||
props["LdapLoginFieldName"] = *c.LdapSettings.LoginFieldName
|
props["LdapLoginFieldName"] = *c.LdapSettings.LoginFieldName
|
||||||
props["LdapPasswordFieldName"] = *c.LdapSettings.PasswordFieldName
|
props["LdapPasswordFieldName"] = *c.LdapSettings.PasswordFieldName
|
||||||
|
props["NicknameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.NicknameAttribute != "")
|
||||||
}
|
}
|
||||||
|
|
||||||
if *License.Features.MFA {
|
if *License.Features.MFA {
|
||||||
|
|||||||
@@ -513,85 +513,100 @@ class UserSettingsGeneralTab extends React.Component {
|
|||||||
const inputs = [];
|
const inputs = [];
|
||||||
|
|
||||||
if (this.props.activeSection === 'name') {
|
if (this.props.activeSection === 'name') {
|
||||||
inputs.push(
|
let extraInfo;
|
||||||
<div
|
let submit = null;
|
||||||
key='firstNameSetting'
|
if (this.props.user.auth_service === '') {
|
||||||
className='form-group'
|
inputs.push(
|
||||||
>
|
<div
|
||||||
<label className='col-sm-5 control-label'>
|
key='firstNameSetting'
|
||||||
<FormattedMessage
|
className='form-group'
|
||||||
id='user.settings.general.firstName'
|
>
|
||||||
defaultMessage='First Name'
|
<label className='col-sm-5 control-label'>
|
||||||
/>
|
<FormattedMessage
|
||||||
</label>
|
id='user.settings.general.firstName'
|
||||||
<div className='col-sm-7'>
|
defaultMessage='First Name'
|
||||||
<input
|
/>
|
||||||
className='form-control'
|
</label>
|
||||||
type='text'
|
<div className='col-sm-7'>
|
||||||
onChange={this.updateFirstName}
|
<input
|
||||||
value={this.state.firstName}
|
className='form-control'
|
||||||
/>
|
type='text'
|
||||||
|
onChange={this.updateFirstName}
|
||||||
|
value={this.state.firstName}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
|
||||||
|
|
||||||
inputs.push(
|
inputs.push(
|
||||||
<div
|
<div
|
||||||
key='lastNameSetting'
|
key='lastNameSetting'
|
||||||
className='form-group'
|
className='form-group'
|
||||||
>
|
>
|
||||||
<label className='col-sm-5 control-label'>
|
<label className='col-sm-5 control-label'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='user.settings.general.lastName'
|
id='user.settings.general.lastName'
|
||||||
defaultMessage='Last Name'
|
defaultMessage='Last Name'
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<div className='col-sm-7'>
|
<div className='col-sm-7'>
|
||||||
<input
|
<input
|
||||||
className='form-control'
|
className='form-control'
|
||||||
type='text'
|
type='text'
|
||||||
onChange={this.updateLastName}
|
onChange={this.updateLastName}
|
||||||
value={this.state.lastName}
|
value={this.state.lastName}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
|
||||||
|
|
||||||
function notifClick(e) {
|
function notifClick(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.updateSection('');
|
this.updateSection('');
|
||||||
this.props.updateTab('notifications');
|
this.props.updateTab('notifications');
|
||||||
|
}
|
||||||
|
|
||||||
|
const notifLink = (
|
||||||
|
<a
|
||||||
|
href='#'
|
||||||
|
onClick={notifClick.bind(this)}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.general.notificationsLink'
|
||||||
|
defaultMessage='Notifications'
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
|
||||||
|
extraInfo = (
|
||||||
|
<span>
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.general.notificationsExtra'
|
||||||
|
defaultMessage='By default, you will receive mention notifications when someone types your first name. Go to {notify} settings to change this default.'
|
||||||
|
values={{
|
||||||
|
notify: (notifLink)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
submit = this.submitName;
|
||||||
|
} else {
|
||||||
|
extraInfo = (
|
||||||
|
<span>
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.general.field_handled_externally'
|
||||||
|
defaultMessage='This field is handled through your login provider. If you want to change it, you need to do so though your login provider.'
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const notifLink = (
|
|
||||||
<a
|
|
||||||
href='#'
|
|
||||||
onClick={notifClick.bind(this)}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.general.notificationsLink'
|
|
||||||
defaultMessage='Notifications'
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
|
|
||||||
const extraInfo = (
|
|
||||||
<span>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.general.notificationsExtra'
|
|
||||||
defaultMessage='By default, you will receive mention notifications when someone types your first name. Go to {notify} settings to change this default.'
|
|
||||||
values={{
|
|
||||||
notify: (notifLink)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
|
|
||||||
nameSection = (
|
nameSection = (
|
||||||
<SettingItemMax
|
<SettingItemMax
|
||||||
title={formatMessage(holders.fullName)}
|
title={formatMessage(holders.fullName)}
|
||||||
inputs={inputs}
|
inputs={inputs}
|
||||||
submit={this.submitName}
|
submit={submit}
|
||||||
server_error={serverError}
|
server_error={serverError}
|
||||||
client_error={clientError}
|
client_error={clientError}
|
||||||
updateSection={(e) => {
|
updateSection={(e) => {
|
||||||
@@ -632,47 +647,62 @@ class UserSettingsGeneralTab extends React.Component {
|
|||||||
|
|
||||||
let nicknameSection;
|
let nicknameSection;
|
||||||
if (this.props.activeSection === 'nickname') {
|
if (this.props.activeSection === 'nickname') {
|
||||||
let nicknameLabel = (
|
let extraInfo;
|
||||||
<FormattedMessage
|
let submit = null;
|
||||||
id='user.settings.general.nickname'
|
if (this.props.user.auth_service === 'ldap' && global.window.mm_config.NicknameAttributeSet) {
|
||||||
defaultMessage='Nickname'
|
extraInfo = (
|
||||||
/>
|
<span>
|
||||||
);
|
<FormattedMessage
|
||||||
if (Utils.isMobile()) {
|
id='user.settings.general.field_handled_externally'
|
||||||
nicknameLabel = '';
|
defaultMessage='This field is handled through your login provider. If you want to change it, you need to do so though your login provider.'
|
||||||
}
|
|
||||||
|
|
||||||
inputs.push(
|
|
||||||
<div
|
|
||||||
key='nicknameSetting'
|
|
||||||
className='form-group'
|
|
||||||
>
|
|
||||||
<label className='col-sm-5 control-label'>{nicknameLabel}</label>
|
|
||||||
<div className='col-sm-7'>
|
|
||||||
<input
|
|
||||||
className='form-control'
|
|
||||||
type='text'
|
|
||||||
onChange={this.updateNickname}
|
|
||||||
value={this.state.nickname}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</span>
|
||||||
</div>
|
);
|
||||||
);
|
} else {
|
||||||
|
let nicknameLabel = (
|
||||||
const extraInfo = (
|
|
||||||
<span>
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='user.settings.general.nicknameExtra'
|
id='user.settings.general.nickname'
|
||||||
defaultMessage='Use Nickname for a name you might be called that is different from your first name and username. This is most often used when two or more people have similar sounding names and usernames.'
|
defaultMessage='Nickname'
|
||||||
/>
|
/>
|
||||||
</span>
|
);
|
||||||
);
|
if (Utils.isMobile()) {
|
||||||
|
nicknameLabel = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
inputs.push(
|
||||||
|
<div
|
||||||
|
key='nicknameSetting'
|
||||||
|
className='form-group'
|
||||||
|
>
|
||||||
|
<label className='col-sm-5 control-label'>{nicknameLabel}</label>
|
||||||
|
<div className='col-sm-7'>
|
||||||
|
<input
|
||||||
|
className='form-control'
|
||||||
|
type='text'
|
||||||
|
onChange={this.updateNickname}
|
||||||
|
value={this.state.nickname}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
extraInfo = (
|
||||||
|
<span>
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.general.nicknameExtra'
|
||||||
|
defaultMessage='Use Nickname for a name you might be called that is different from your first name and username. This is most often used when two or more people have similar sounding names and usernames.'
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
submit = this.submitNickname;
|
||||||
|
}
|
||||||
|
|
||||||
nicknameSection = (
|
nicknameSection = (
|
||||||
<SettingItemMax
|
<SettingItemMax
|
||||||
title={formatMessage(holders.nickname)}
|
title={formatMessage(holders.nickname)}
|
||||||
inputs={inputs}
|
inputs={inputs}
|
||||||
submit={this.submitNickname}
|
submit={submit}
|
||||||
server_error={serverError}
|
server_error={serverError}
|
||||||
client_error={clientError}
|
client_error={clientError}
|
||||||
updateSection={(e) => {
|
updateSection={(e) => {
|
||||||
@@ -708,48 +738,63 @@ class UserSettingsGeneralTab extends React.Component {
|
|||||||
|
|
||||||
let usernameSection;
|
let usernameSection;
|
||||||
if (this.props.activeSection === 'username') {
|
if (this.props.activeSection === 'username') {
|
||||||
let usernameLabel = (
|
let extraInfo;
|
||||||
<FormattedMessage
|
let submit = null;
|
||||||
id='user.settings.general.username'
|
if (this.props.user.auth_service === '') {
|
||||||
defaultMessage='Username'
|
let usernameLabel = (
|
||||||
/>
|
|
||||||
);
|
|
||||||
if (Utils.isMobile()) {
|
|
||||||
usernameLabel = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
inputs.push(
|
|
||||||
<div
|
|
||||||
key='usernameSetting'
|
|
||||||
className='form-group'
|
|
||||||
>
|
|
||||||
<label className='col-sm-5 control-label'>{usernameLabel}</label>
|
|
||||||
<div className='col-sm-7'>
|
|
||||||
<input
|
|
||||||
maxLength={Constants.MAX_USERNAME_LENGTH}
|
|
||||||
className='form-control'
|
|
||||||
type='text'
|
|
||||||
onChange={this.updateUsername}
|
|
||||||
value={this.state.username}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
const extraInfo = (
|
|
||||||
<span>
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='user.settings.general.usernameInfo'
|
id='user.settings.general.username'
|
||||||
defaultMessage='Pick something easy for teammates to recognize and recall.'
|
defaultMessage='Username'
|
||||||
/>
|
/>
|
||||||
</span>
|
);
|
||||||
);
|
if (Utils.isMobile()) {
|
||||||
|
usernameLabel = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
inputs.push(
|
||||||
|
<div
|
||||||
|
key='usernameSetting'
|
||||||
|
className='form-group'
|
||||||
|
>
|
||||||
|
<label className='col-sm-5 control-label'>{usernameLabel}</label>
|
||||||
|
<div className='col-sm-7'>
|
||||||
|
<input
|
||||||
|
maxLength={Constants.MAX_USERNAME_LENGTH}
|
||||||
|
className='form-control'
|
||||||
|
type='text'
|
||||||
|
onChange={this.updateUsername}
|
||||||
|
value={this.state.username}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
extraInfo = (
|
||||||
|
<span>
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.general.usernameInfo'
|
||||||
|
defaultMessage='Pick something easy for teammates to recognize and recall.'
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
submit = this.submitUsername;
|
||||||
|
} else {
|
||||||
|
extraInfo = (
|
||||||
|
<span>
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.general.field_handled_externally'
|
||||||
|
defaultMessage='This field is handled through your login provider. If you want to change it, you need to do so though your login provider.'
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
usernameSection = (
|
usernameSection = (
|
||||||
<SettingItemMax
|
<SettingItemMax
|
||||||
title={formatMessage(holders.username)}
|
title={formatMessage(holders.username)}
|
||||||
inputs={inputs}
|
inputs={inputs}
|
||||||
submit={this.submitUsername}
|
submit={submit}
|
||||||
server_error={serverError}
|
server_error={serverError}
|
||||||
client_error={clientError}
|
client_error={clientError}
|
||||||
updateSection={(e) => {
|
updateSection={(e) => {
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user