aboutsummaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorzeripath <art27@cantab.net>2021-09-17 12:43:47 +0100
committerGitHub <noreply@github.com>2021-09-17 12:43:47 +0100
commit27b351aba564804f65e5574919a88d6194c75256 (patch)
treefa4857e05e344693e629aa14b05b7f8ffba42cfc /services
parentf96d0d3d5b2acb3545c3a2ced7972879a9750c9d (diff)
downloadgitea-27b351aba564804f65e5574919a88d6194c75256.tar.gz
gitea-27b351aba564804f65e5574919a88d6194c75256.zip
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>
Diffstat (limited to 'services')
-rw-r--r--services/auth/basic.go6
-rw-r--r--services/auth/interface.go5
-rw-r--r--services/auth/signin.go28
-rw-r--r--services/auth/source/ldap/assert_interface_test.go1
-rw-r--r--services/auth/source/ldap/source.go1
-rw-r--r--services/auth/source/ldap/source_authenticate.go5
-rw-r--r--services/auth/source/oauth2/source_authenticate.go3
7 files changed, 34 insertions, 15 deletions
diff --git a/services/auth/basic.go b/services/auth/basic.go
index 244f63d2f7..0c400b6b53 100644
--- a/services/auth/basic.go
+++ b/services/auth/basic.go
@@ -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
diff --git a/services/auth/interface.go b/services/auth/interface.go
index 51c7043370..a198fbe5b8 100644
--- a/services/auth/interface.go
+++ b/services/auth/interface.go
@@ -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
diff --git a/services/auth/signin.go b/services/auth/signin.go
index 2c4bf9b35b..0ac2634c80 100644
--- a/services/auth/signin.go
+++ b/services/auth/signin.go
@@ -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}
}
diff --git a/services/auth/source/ldap/assert_interface_test.go b/services/auth/source/ldap/assert_interface_test.go
index 4cf3eafe76..a0425d2f76 100644
--- a/services/auth/source/ldap/assert_interface_test.go
+++ b/services/auth/source/ldap/assert_interface_test.go
@@ -16,6 +16,7 @@ import (
type sourceInterface interface {
auth.PasswordAuthenticator
auth.SynchronizableSource
+ auth.LocalTwoFASkipper
models.SSHKeyProvider
models.LoginConfig
models.SkipVerifiable
diff --git a/services/auth/source/ldap/source.go b/services/auth/source/ldap/source.go
index 79f118f784..d1228d41ae 100644
--- a/services/auth/source/ldap/source.go
+++ b/services/auth/source/ldap/source.go
@@ -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
diff --git a/services/auth/source/ldap/source_authenticate.go b/services/auth/source/ldap/source_authenticate.go
index ecc95fbd56..46478e6029 100644
--- a/services/auth/source/ldap/source_authenticate.go
+++ b/services/auth/source/ldap/source_authenticate.go
@@ -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
+}
diff --git a/services/auth/source/oauth2/source_authenticate.go b/services/auth/source/oauth2/source_authenticate.go
index 2e39f245df..be2ff05356 100644
--- a/services/auth/source/oauth2/source_authenticate.go
+++ b/services/auth/source/oauth2/source_authenticate.go
@@ -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