mirror of
https://github.com/go-gitea/gitea
synced 2025-07-22 18:28:37 +00:00
Make LDAP be able to skip local 2FA (#16954)
This PR extends #16594 to allow LDAP to be able to be set to skip local 2FA too. The technique used here would be extensible to PAM and SMTP sources. Signed-off-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
@@ -107,7 +107,7 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore
|
||||
}
|
||||
|
||||
log.Trace("Basic Authorization: Attempting SignIn for %s", uname)
|
||||
u, err := UserSignIn(uname, passwd)
|
||||
u, source, err := UserSignIn(uname, passwd)
|
||||
if err != nil {
|
||||
if !models.IsErrUserNotExist(err) {
|
||||
log.Error("UserSignIn: %v", err)
|
||||
@@ -115,6 +115,10 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore
|
||||
return nil
|
||||
}
|
||||
|
||||
if skipper, ok := source.Cfg.(LocalTwoFASkipper); ok && skipper.IsSkipLocalTwoFA() {
|
||||
store.GetData()["SkipLocalTwoFA"] = true
|
||||
}
|
||||
|
||||
log.Trace("Basic Authorization: Logged in user %-v", u)
|
||||
|
||||
return u
|
||||
|
@@ -54,6 +54,11 @@ type PasswordAuthenticator interface {
|
||||
Authenticate(user *models.User, login, password string) (*models.User, error)
|
||||
}
|
||||
|
||||
// LocalTwoFASkipper represents a source of authentication that can skip local 2fa
|
||||
type LocalTwoFASkipper interface {
|
||||
IsSkipLocalTwoFA() bool
|
||||
}
|
||||
|
||||
// SynchronizableSource represents a source that can synchronize users
|
||||
type SynchronizableSource interface {
|
||||
Sync(ctx context.Context, updateExisting bool) error
|
||||
|
@@ -20,24 +20,24 @@ import (
|
||||
)
|
||||
|
||||
// UserSignIn validates user name and password.
|
||||
func UserSignIn(username, password string) (*models.User, error) {
|
||||
func UserSignIn(username, password string) (*models.User, *models.LoginSource, error) {
|
||||
var user *models.User
|
||||
if strings.Contains(username, "@") {
|
||||
user = &models.User{Email: strings.ToLower(strings.TrimSpace(username))}
|
||||
// check same email
|
||||
cnt, err := models.Count(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
if cnt > 1 {
|
||||
return nil, models.ErrEmailAlreadyUsed{
|
||||
return nil, nil, models.ErrEmailAlreadyUsed{
|
||||
Email: user.Email,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
trimmedUsername := strings.TrimSpace(username)
|
||||
if len(trimmedUsername) == 0 {
|
||||
return nil, models.ErrUserNotExist{Name: username}
|
||||
return nil, nil, models.ErrUserNotExist{Name: username}
|
||||
}
|
||||
|
||||
user = &models.User{LowerName: strings.ToLower(trimmedUsername)}
|
||||
@@ -45,41 +45,41 @@ func UserSignIn(username, password string) (*models.User, error) {
|
||||
|
||||
hasUser, err := models.GetUser(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if hasUser {
|
||||
source, err := models.GetLoginSourceByID(user.LoginSource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if !source.IsActive {
|
||||
return nil, models.ErrLoginSourceNotActived
|
||||
return nil, nil, models.ErrLoginSourceNotActived
|
||||
}
|
||||
|
||||
authenticator, ok := source.Cfg.(PasswordAuthenticator)
|
||||
if !ok {
|
||||
return nil, models.ErrUnsupportedLoginType
|
||||
return nil, nil, models.ErrUnsupportedLoginType
|
||||
}
|
||||
|
||||
user, err := authenticator.Authenticate(user, username, password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// WARN: DON'T check user.IsActive, that will be checked on reqSign so that
|
||||
// user could be hint to resend confirm email.
|
||||
if user.ProhibitLogin {
|
||||
return nil, models.ErrUserProhibitLogin{UID: user.ID, Name: user.Name}
|
||||
return nil, nil, models.ErrUserProhibitLogin{UID: user.ID, Name: user.Name}
|
||||
}
|
||||
|
||||
return user, nil
|
||||
return user, source, nil
|
||||
}
|
||||
|
||||
sources, err := models.AllActiveLoginSources()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
for _, source := range sources {
|
||||
@@ -97,7 +97,7 @@ func UserSignIn(username, password string) (*models.User, error) {
|
||||
|
||||
if err == nil {
|
||||
if !authUser.ProhibitLogin {
|
||||
return authUser, nil
|
||||
return authUser, source, nil
|
||||
}
|
||||
err = models.ErrUserProhibitLogin{UID: authUser.ID, Name: authUser.Name}
|
||||
}
|
||||
@@ -109,5 +109,5 @@ func UserSignIn(username, password string) (*models.User, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return nil, models.ErrUserNotExist{Name: username}
|
||||
return nil, nil, models.ErrUserNotExist{Name: username}
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@ import (
|
||||
type sourceInterface interface {
|
||||
auth.PasswordAuthenticator
|
||||
auth.SynchronizableSource
|
||||
auth.LocalTwoFASkipper
|
||||
models.SSHKeyProvider
|
||||
models.LoginConfig
|
||||
models.SkipVerifiable
|
||||
|
@@ -52,6 +52,7 @@ type Source struct {
|
||||
GroupFilter string // Group Name Filter
|
||||
GroupMemberUID string // Group Attribute containing array of UserUID
|
||||
UserUID string // User Attribute listed in Group
|
||||
SkipLocalTwoFA bool // Skip Local 2fa for users authenticated with this source
|
||||
|
||||
// reference to the loginSource
|
||||
loginSource *models.LoginSource
|
||||
|
@@ -97,3 +97,8 @@ func (source *Source) Authenticate(user *models.User, login, password string) (*
|
||||
|
||||
return user, err
|
||||
}
|
||||
|
||||
// IsSkipLocalTwoFA returns if this source should skip local 2fa for password authentication
|
||||
func (source *Source) IsSkipLocalTwoFA() bool {
|
||||
return source.SkipLocalTwoFA
|
||||
}
|
||||
|
@@ -13,3 +13,6 @@ import (
|
||||
func (source *Source) Authenticate(user *models.User, login, password string) (*models.User, error) {
|
||||
return db.Authenticate(user, login, password)
|
||||
}
|
||||
|
||||
// NB: Oauth2 does not implement LocalTwoFASkipper for password authentication
|
||||
// as its password authentication drops to db authentication
|
||||
|
Reference in New Issue
Block a user