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 удалений

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

@@ -275,6 +275,10 @@ store-mocks: ## Creates mock files.
go get github.com/vektra/mockery/...
$(GOPATH)/bin/mockery -dir store -all -output store/storetest/mocks -note 'Regenerate this file using `make store-mocks`.'
ldap-mocks: ## Creates mock files for ldap.
go get github.com/vektra/mockery/...
GOPATH=$(shell go env GOPATH) $(shell go env GOPATH)/bin/mockery -dir enterprise/ldap -all -output enterprise/ldap/mocks -note 'Regenerate this file using `make ldap-mocks`.'
update-jira-plugin: ## Updates Jira plugin.
go get github.com/mattermost/go-bindata/...
curl -s https://api.github.com/repos/mattermost/mattermost-plugin-jira/releases/latest | grep browser_download_url | grep darwin-amd64 | cut -d '"' -f 4 | wget -qi - -O plugin.tar.gz

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

@@ -107,7 +107,7 @@ func login(c *Context, w http.ResponseWriter, r *http.Request) {
ldapOnly := props["ldap_only"] == "true"
c.LogAudit("attempt - user_id=" + id + " login_id=" + loginId)
user, err := c.App.AuthenticateUserForLogin(id, loginId, password, mfaToken, deviceId, ldapOnly)
user, err := c.App.AuthenticateUserForLogin(id, loginId, password, mfaToken, ldapOnly)
if err != nil {
c.LogAudit("failure - user_id=" + id + " login_id=" + loginId)
c.Err = err
@@ -1072,7 +1072,7 @@ func checkMfa(c *Context, w http.ResponseWriter, r *http.Request) {
}
rdata := map[string]string{}
if user, err := c.App.GetUserForLogin(loginId, false); err != nil {
if user, err := c.App.GetUserForLogin("", loginId); err != nil {
rdata["mfa_required"] = "false"
} else {
rdata["mfa_required"] = strconv.FormatBool(user.MfaActive)

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

@@ -771,7 +771,7 @@ func checkUserMfa(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
if user, err := c.App.GetUserForLogin(loginId, false); err == nil {
if user, err := c.App.GetUserForLogin("", loginId); err == nil {
resp["mfa_required"] = user.MfaActive
}
@@ -943,7 +943,7 @@ func login(c *Context, w http.ResponseWriter, r *http.Request) {
ldapOnly := props["ldap_only"] == "true"
c.LogAuditWithUserId(id, "attempt - login_id="+loginId)
user, err := c.App.AuthenticateUserForLogin(id, loginId, password, mfaToken, deviceId, ldapOnly)
user, err := c.App.AuthenticateUserForLogin(id, loginId, password, mfaToken, ldapOnly)
if err != nil {
c.LogAuditWithUserId(id, "failure - login_id="+loginId)
c.Err = err
@@ -1167,7 +1167,7 @@ func sendVerificationEmail(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
user, err := c.App.GetUserForLogin(email, false)
user, err := c.App.GetUserForLogin("", email)
if err != nil {
// Don't want to leak whether the email is valid or not
ReturnStatusOK(w)
@@ -1205,7 +1205,7 @@ func switchAccountType(c *Context, w http.ResponseWriter, r *http.Request) {
link, err = c.App.SwitchOAuthToEmail(switchRequest.Email, switchRequest.NewPassword, c.Session.UserId)
} else if switchRequest.EmailToLdap() {
link, err = c.App.SwitchEmailToLdap(switchRequest.Email, switchRequest.Password, switchRequest.MfaCode, switchRequest.LdapId, switchRequest.NewPassword)
link, err = c.App.SwitchEmailToLdap(switchRequest.Email, switchRequest.Password, switchRequest.MfaCode, switchRequest.LdapLoginId, switchRequest.NewPassword)
} else if switchRequest.LdapToEmail() {
link, err = c.App.SwitchLdapToEmail(switchRequest.Password, switchRequest.MfaCode, switchRequest.Email, switchRequest.NewPassword)
} else {

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

@@ -40,7 +40,7 @@ func (a *App) TestLdap() *model.AppError {
return nil
}
func (a *App) SwitchEmailToLdap(email, password, code, ldapId, ldapPassword string) (string, *model.AppError) {
func (a *App) SwitchEmailToLdap(email, password, code, ldapLoginId, ldapPassword string) (string, *model.AppError) {
if a.License() != nil && !*a.Config().ServiceSettings.ExperimentalEnableAuthenticationTransfer {
return "", model.NewAppError("emailToLdap", "api.user.email_to_ldap.not_available.app_error", nil, "", http.StatusForbidden)
}
@@ -63,7 +63,7 @@ func (a *App) SwitchEmailToLdap(email, password, code, ldapId, ldapPassword stri
return "", model.NewAppError("SwitchEmailToLdap", "api.user.email_to_ldap.not_available.app_error", nil, "", http.StatusNotImplemented)
}
if err := ldapInterface.SwitchToLdap(user.Id, ldapId, ldapPassword); err != nil {
if err := ldapInterface.SwitchToLdap(user.Id, ldapLoginId, ldapPassword); err != nil {
return "", err
}
@@ -95,7 +95,7 @@ func (a *App) SwitchLdapToEmail(ldapPassword, code, email, newPassword string) (
return "", model.NewAppError("SwitchLdapToEmail", "api.user.ldap_to_email.not_available.app_error", nil, "", http.StatusNotImplemented)
}
if err := ldapInterface.CheckPassword(*user.AuthData, ldapPassword); err != nil {
if err := ldapInterface.CheckPasswordAuthData(*user.AuthData, ldapPassword); err != nil {
return "", err
}

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

@@ -11,47 +11,69 @@ import (
"github.com/avct/uasurfer"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/store"
)
func (a *App) AuthenticateUserForLogin(id, loginId, password, mfaToken, deviceId string, ldapOnly bool) (*model.User, *model.AppError) {
func (a *App) AuthenticateUserForLogin(id, loginId, password, mfaToken string, ldapOnly bool) (user *model.User, err *model.AppError) {
// Do statistics
defer func() {
if a.Metrics != nil {
if user == nil || err != nil {
a.Metrics.IncrementLoginFail()
} else {
a.Metrics.IncrementLogin()
}
}
}()
if len(password) == 0 {
err := model.NewAppError("AuthenticateUserForLogin", "api.user.login.blank_pwd.app_error", nil, "", http.StatusBadRequest)
return nil, err
}
var user *model.User
var err *model.AppError
if len(id) != 0 {
if user, err = a.GetUser(id); err != nil {
err.StatusCode = http.StatusBadRequest
if a.Metrics != nil {
a.Metrics.IncrementLoginFail()
}
return nil, err
}
} else {
if user, err = a.GetUserForLogin(loginId, ldapOnly); err != nil {
if a.Metrics != nil {
a.Metrics.IncrementLoginFail()
}
return nil, err
}
// Get the MM user we are trying to login
if user, err = a.GetUserForLogin(id, loginId); err != nil {
return nil, err
}
// and then authenticate them
if user, err = a.authenticateUser(user, password, mfaToken); err != nil {
if a.Metrics != nil {
a.Metrics.IncrementLoginFail()
}
return nil, err
}
if a.Metrics != nil {
a.Metrics.IncrementLogin()
return user, nil
}
func (a *App) GetUserForLogin(id, loginId string) (*model.User, *model.AppError) {
enableUsername := *a.Config().EmailSettings.EnableSignInWithUsername
enableEmail := *a.Config().EmailSettings.EnableSignInWithEmail
// If we are given a userID then fail if we can't find a user with that ID
if len(id) != 0 {
if user, err := a.GetUser(id); err != nil {
if err.Id != store.MISSING_ACCOUNT_ERROR {
err.StatusCode = http.StatusInternalServerError
return nil, err
} else {
err.StatusCode = http.StatusBadRequest
return nil, err
}
} else {
return user, nil
}
}
return user, nil
// Try to get the user by username/email
if result := <-a.Srv.Store.User().GetForLogin(loginId, enableUsername, enableEmail); result.Err == nil {
return result.Data.(*model.User), nil
}
// Try to get the user with LDAP
if user, err := a.Ldap.GetUser(loginId); err == nil {
return user, nil
}
return nil, model.NewAppError("GetUserForLogin", "store.sql_user.get_for_login.app_error", nil, "", http.StatusBadRequest)
}
func (a *App) DoLogin(w http.ResponseWriter, r *http.Request, user *model.User, deviceId string) (*model.Session, *model.AppError) {

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

@@ -382,38 +382,6 @@ func (a *App) GetUserByAuth(authData *string, authService string) (*model.User,
}
}
func (a *App) GetUserForLogin(loginId string, onlyLdap bool) (*model.User, *model.AppError) {
license := a.License()
ldapAvailable := *a.Config().LdapSettings.Enable && a.Ldap != nil && license != nil && *license.Features.LDAP
if result := <-a.Srv.Store.User().GetForLogin(
loginId,
*a.Config().EmailSettings.EnableSignInWithUsername && !onlyLdap,
*a.Config().EmailSettings.EnableSignInWithEmail && !onlyLdap,
ldapAvailable,
); result.Err != nil && result.Err.Id == "store.sql_user.get_for_login.multiple_users" {
// don't fall back to LDAP in this case since we already know there's an LDAP user, but that it shouldn't work
result.Err.StatusCode = http.StatusBadRequest
return nil, result.Err
} else if result.Err != nil {
if !ldapAvailable {
// failed to find user and no LDAP server to fall back on
result.Err.StatusCode = http.StatusBadRequest
return nil, result.Err
}
// fall back to LDAP server to see if we can find a user
if ldapUser, ldapErr := a.Ldap.GetUser(loginId); ldapErr != nil {
ldapErr.StatusCode = http.StatusBadRequest
return nil, ldapErr
} else {
return ldapUser, nil
}
} else {
return result.Data.(*model.User), nil
}
}
func (a *App) GetUsers(offset int, limit int) ([]*model.User, *model.AppError) {
if result := <-a.Srv.Store.User().GetAllProfiles(offset, limit); result.Err != nil {
return nil, result.Err

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

@@ -22,9 +22,19 @@ var LdapSyncCmd = &cobra.Command{
RunE: ldapSyncCmdF,
}
var LdapIdMigrate = &cobra.Command{
Use: "idmigrate",
Short: "Migrate LDAP IdAttribute to new value",
Long: "Migrate LDAP IdAttribute to new value. Run this utility then change the IdAttribute to the new value.",
Example: " ldap idmigrate objectGUID",
Args: cobra.ExactArgs(1),
RunE: ldapIdMigrateCmdF,
}
func init() {
LdapCmd.AddCommand(
LdapSyncCmd,
LdapIdMigrate,
)
cmd.RootCmd.AddCommand(LdapCmd)
}
@@ -47,3 +57,22 @@ func ldapSyncCmdF(command *cobra.Command, args []string) error {
return nil
}
func ldapIdMigrateCmdF(command *cobra.Command, args []string) error {
a, err := cmd.InitDBCommandContextCobra(command)
if err != nil {
return err
}
defer a.Shutdown()
toAttribute := args[0]
if ldapI := a.Ldap; ldapI != nil {
if err := ldapI.MigrateIDAttribute(toAttribute); err != nil {
cmd.CommandPrintErrorln("ERROR: AD/LDAP IdAttribute migration failed! Error: " + err.Error())
} else {
cmd.CommandPrettyPrintln("SUCCESS: AD/LDAP IdAttribute migration complete. You can now change your IdAttribute to: " + toAttribute)
}
}
return nil
}

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

@@ -263,6 +263,7 @@
"NicknameAttribute": "",
"IdAttribute": "",
"PositionAttribute": "",
"LoginIdAttribute": "",
"SyncIntervalMinutes": 60,
"SkipCertificateVerification": false,
"QueryTimeout": 60,

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

@@ -4,8 +4,6 @@
package einterfaces
import (
"github.com/go-ldap/ldap"
"github.com/mattermost/mattermost-server/model"
)
@@ -14,12 +12,11 @@ type LdapInterface interface {
GetUser(id string) (*model.User, *model.AppError)
GetUserAttributes(id string, attributes []string) (map[string]string, *model.AppError)
CheckPassword(id string, password string) *model.AppError
CheckPasswordAuthData(authData string, password string) *model.AppError
SwitchToLdap(userId, ldapId, ldapPassword string) *model.AppError
ValidateFilter(filter string) *model.AppError
StartSynchronizeJob(waitForJobToFinish bool) (*model.Job, *model.AppError)
RunTest() *model.AppError
GetAllLdapUsers() ([]*model.User, *model.AppError)
UserFromLdapUser(ldapUser *ldap.Entry) *model.User
UserHasUpdateFromLdap(existingUser *model.User, currentLdapUser *model.User) bool
UpdateLocalLdapUser(existingUser *model.User, currentLdapUser *model.User) *model.User
MigrateIDAttribute(toAttribute string) error
}

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

@@ -5018,6 +5018,10 @@
"id": "model.config.is_valid.ldap_id",
"translation": "AD/LDAP field \"ID Attribute\" is required."
},
{
"id": "model.config.is_valid.ldap_login_id",
"translation": "AD/LDAP field \"Login ID Attribute\" is required."
},
{
"id": "model.config.is_valid.ldap_lastname",
"translation": "AD/LDAP field \"Last Name Attribute\" is required."

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

@@ -29,6 +29,7 @@ type Field = zapcore.Field
var Int64 = zap.Int64
var Int = zap.Int
var String = zap.String
var Any = zap.Any
var Err = zap.Error
type LoggerConfiguration struct {

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

@@ -1144,6 +1144,7 @@ type LdapSettings struct {
NicknameAttribute *string
IdAttribute *string
PositionAttribute *string
LoginIdAttribute *string
// Synchronization
SyncIntervalMinutes *int
@@ -1227,6 +1228,12 @@ func (s *LdapSettings) SetDefaults() {
s.PositionAttribute = NewString(LDAP_SETTINGS_DEFAULT_POSITION_ATTRIBUTE)
}
// For those upgrading to the version when LoginIdAttribute was added
// they need IdAttribute == LoginIdAttribute not to break
if s.LoginIdAttribute == nil {
s.LoginIdAttribute = s.IdAttribute
}
if s.SyncIntervalMinutes == nil {
s.SyncIntervalMinutes = NewInt(60)
}
@@ -2074,6 +2081,10 @@ func (ls *LdapSettings) isValid() *AppError {
if *ls.IdAttribute == "" {
return NewAppError("Config.IsValid", "model.config.is_valid.ldap_id", nil, "", http.StatusBadRequest)
}
if *ls.LoginIdAttribute == "" {
return NewAppError("Config.IsValid", "model.config.is_valid.ldap_login_id", nil, "", http.StatusBadRequest)
}
}
return nil

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

@@ -15,7 +15,7 @@ type SwitchRequest struct {
Password string `json:"password"`
NewPassword string `json:"new_password"`
MfaCode string `json:"mfa_code"`
LdapId string `json:"ldap_id"`
LdapLoginId string `json:"ldap_id"`
}
func (o *SwitchRequest) ToJson() string {

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

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