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.
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
db6b8f6238
Коммит
d8dd271e43
@@ -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) {
|
||||
|
||||
Ссылка в новой задаче
Block a user