MM-4998 Adding LoginIdAttribute to allow LDAP users to change their login ID without losing their account (#8756)

* Adding LoginIdAttribute

* Modifying LDAP to use loginIDAttribute.

* Adding IDAttribute migration and AD objectGUID support.

* Removing unused idea.

* Fix typo.
Этот коммит содержится в:
Christopher Speller
2018-05-10 09:46:09 -07:00
коммит произвёл GitHub
родитель db6b8f6238
Коммит d8dd271e43
45 изменённых файлов: 150 добавлений и 153 удалений

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

@@ -819,13 +819,12 @@ func (us SqlUserStore) GetByUsername(username string) store.StoreChannel {
})
}
func (us SqlUserStore) GetForLogin(loginId string, allowSignInWithUsername, allowSignInWithEmail, ldapEnabled bool) store.StoreChannel {
func (us SqlUserStore) GetForLogin(loginId string, allowSignInWithUsername, allowSignInWithEmail bool) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
params := map[string]interface{}{
"LoginId": loginId,
"AllowSignInWithUsername": allowSignInWithUsername,
"AllowSignInWithEmail": allowSignInWithEmail,
"LdapEnabled": ldapEnabled,
}
users := []*model.User{}
@@ -837,8 +836,7 @@ func (us SqlUserStore) GetForLogin(loginId string, allowSignInWithUsername, allo
Users
WHERE
(:AllowSignInWithUsername AND Username = :LoginId)
OR (:AllowSignInWithEmail AND Email = :LoginId)
OR (:LdapEnabled AND AuthService = '`+model.USER_AUTH_SERVICE_LDAP+`' AND AuthData = :LoginId)`,
OR (:AllowSignInWithEmail AND Email = :LoginId)`,
params); err != nil {
result.Err = model.NewAppError("SqlUserStore.GetForLogin", "store.sql_user.get_for_login.app_error", nil, err.Error(), http.StatusInternalServerError)
} else if len(users) == 1 {

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

@@ -228,7 +228,7 @@ type UserStore interface {
GetByAuth(authData *string, authService string) StoreChannel
GetAllUsingAuthService(authService string) StoreChannel
GetByUsername(username string) StoreChannel
GetForLogin(loginId string, allowSignInWithUsername, allowSignInWithEmail, ldapEnabled bool) StoreChannel
GetForLogin(loginId string, allowSignInWithUsername, allowSignInWithEmail bool) StoreChannel
VerifyEmail(userId string) StoreChannel
GetEtagForAllProfiles() StoreChannel
GetEtagForProfiles(teamId string) StoreChannel

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.
@@ -258,13 +258,13 @@ func (_m *UserStore) GetEtagForProfilesNotInTeam(teamId string) store.StoreChann
return r0
}
// GetForLogin provides a mock function with given fields: loginId, allowSignInWithUsername, allowSignInWithEmail, ldapEnabled
func (_m *UserStore) GetForLogin(loginId string, allowSignInWithUsername bool, allowSignInWithEmail bool, ldapEnabled bool) store.StoreChannel {
ret := _m.Called(loginId, allowSignInWithUsername, allowSignInWithEmail, ldapEnabled)
// GetForLogin provides a mock function with given fields: loginId, allowSignInWithUsername, allowSignInWithEmail
func (_m *UserStore) GetForLogin(loginId string, allowSignInWithUsername bool, allowSignInWithEmail bool) store.StoreChannel {
ret := _m.Called(loginId, allowSignInWithUsername, allowSignInWithEmail)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string, bool, bool, bool) store.StoreChannel); ok {
r0 = rf(loginId, allowSignInWithUsername, allowSignInWithEmail, ldapEnabled)
if rf, ok := ret.Get(0).(func(string, bool, bool) store.StoreChannel); ok {
r0 = rf(loginId, allowSignInWithUsername, allowSignInWithEmail)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)

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

@@ -1,4 +1,4 @@
// Code generated by mockery v1.0.0
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.

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

@@ -1091,64 +1091,26 @@ func testUserStoreGetForLogin(t *testing.T, ss store.Store) {
}
store.Must(ss.User().Save(u2))
if result := <-ss.User().GetForLogin(u1.Username, true, true, true); result.Err != nil {
if result := <-ss.User().GetForLogin(u1.Username, true, true); result.Err != nil {
t.Fatal("Should have gotten user by username", result.Err)
} else if result.Data.(*model.User).Id != u1.Id {
t.Fatal("Should have gotten user1 by username")
}
if result := <-ss.User().GetForLogin(u1.Email, true, true, true); result.Err != nil {
if result := <-ss.User().GetForLogin(u1.Email, true, true); result.Err != nil {
t.Fatal("Should have gotten user by email", result.Err)
} else if result.Data.(*model.User).Id != u1.Id {
t.Fatal("Should have gotten user1 by email")
}
if result := <-ss.User().GetForLogin(*u2.AuthData, true, true, true); result.Err != nil {
t.Fatal("Should have gotten user by AD/LDAP AuthData", result.Err)
} else if result.Data.(*model.User).Id != u2.Id {
t.Fatal("Should have gotten user2 by AD/LDAP AuthData")
}
// prevent getting user by AuthData when they're not an LDAP user
if result := <-ss.User().GetForLogin(*u1.AuthData, true, true, true); result.Err == nil {
t.Fatal("Should not have gotten user by non-AD/LDAP AuthData")
}
// prevent getting user when different login methods are disabled
if result := <-ss.User().GetForLogin(u1.Username, false, true, true); result.Err == nil {
if result := <-ss.User().GetForLogin(u1.Username, false, true); result.Err == nil {
t.Fatal("Should have failed to get user1 by username")
}
if result := <-ss.User().GetForLogin(u1.Email, true, false, true); result.Err == nil {
if result := <-ss.User().GetForLogin(u1.Email, true, false); result.Err == nil {
t.Fatal("Should have failed to get user1 by email")
}
if result := <-ss.User().GetForLogin(*u2.AuthData, true, true, false); result.Err == nil {
t.Fatal("Should have failed to get user3 by AD/LDAP AuthData")
}
auth3 := model.NewId()
// test a special case where two users will have conflicting login information so we throw a special error
u3 := &model.User{
Email: model.NewId(),
Username: model.NewId(),
AuthService: model.USER_AUTH_SERVICE_LDAP,
AuthData: &auth3,
}
store.Must(ss.User().Save(u3))
u4 := &model.User{
Email: model.NewId(),
Username: model.NewId(),
AuthService: model.USER_AUTH_SERVICE_LDAP,
AuthData: &u3.Username,
}
store.Must(ss.User().Save(u4))
if err := (<-ss.User().GetForLogin(u3.Username, true, true, true)).Err; err == nil {
t.Fatal("Should have failed to get users with conflicting login information")
}
}
func testUserStoreUpdatePassword(t *testing.T, ss store.Store) {