diff options
Diffstat (limited to 'services/auth/signin.go')
-rw-r--r-- | services/auth/signin.go | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/services/auth/signin.go b/services/auth/signin.go new file mode 100644 index 0000000..e116a08 --- /dev/null +++ b/services/auth/signin.go @@ -0,0 +1,128 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package auth + +import ( + "context" + "strings" + + "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/optional" + "code.gitea.io/gitea/services/auth/source/oauth2" + "code.gitea.io/gitea/services/auth/source/smtp" + + _ "code.gitea.io/gitea/services/auth/source/db" // register the sources (and below) + _ "code.gitea.io/gitea/services/auth/source/ldap" // register the ldap source + _ "code.gitea.io/gitea/services/auth/source/pam" // register the pam source + _ "code.gitea.io/gitea/services/auth/source/sspi" // register the sspi source +) + +// UserSignIn validates user name and password. +func UserSignIn(ctx context.Context, username, password string) (*user_model.User, *auth.Source, error) { + var user *user_model.User + isEmail := false + if strings.Contains(username, "@") { + isEmail = true + emailAddress := user_model.EmailAddress{LowerEmail: strings.ToLower(strings.TrimSpace(username))} + // check same email + has, err := db.GetEngine(ctx).Get(&emailAddress) + if err != nil { + return nil, nil, err + } + if has { + if !emailAddress.IsActivated { + return nil, nil, user_model.ErrEmailAddressNotExist{ + Email: username, + } + } + user = &user_model.User{ID: emailAddress.UID} + } + } else { + trimmedUsername := strings.TrimSpace(username) + if len(trimmedUsername) == 0 { + return nil, nil, user_model.ErrUserNotExist{Name: username} + } + + user = &user_model.User{LowerName: strings.ToLower(trimmedUsername)} + } + + if user != nil { + hasUser, err := user_model.GetUser(ctx, user) + if err != nil { + return nil, nil, err + } + + if hasUser { + source, err := auth.GetSourceByID(ctx, user.LoginSource) + if err != nil { + return nil, nil, err + } + + if !source.IsActive { + return nil, nil, oauth2.ErrAuthSourceNotActivated + } + + authenticator, ok := source.Cfg.(PasswordAuthenticator) + if !ok { + return nil, nil, smtp.ErrUnsupportedLoginType + } + + user, err := authenticator.Authenticate(ctx, user, user.LoginName, password) + if err != nil { + 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, nil, user_model.ErrUserProhibitLogin{UID: user.ID, Name: user.Name} + } + + return user, source, nil + } + } + + sources, err := db.Find[auth.Source](ctx, auth.FindSourcesOptions{ + IsActive: optional.Some(true), + }) + if err != nil { + return nil, nil, err + } + + for _, source := range sources { + if !source.IsActive { + // don't try to authenticate non-active sources + continue + } + + authenticator, ok := source.Cfg.(PasswordAuthenticator) + if !ok { + continue + } + + authUser, err := authenticator.Authenticate(ctx, nil, username, password) + + if err == nil { + if !authUser.ProhibitLogin { + return authUser, source, nil + } + err = user_model.ErrUserProhibitLogin{UID: authUser.ID, Name: authUser.Name} + } + + if user_model.IsErrUserNotExist(err) { + log.Debug("Failed to login '%s' via '%s': %v", username, source.Name, err) + } else { + log.Warn("Failed to login '%s' via '%s': %v", username, source.Name, err) + } + } + + if isEmail { + return nil, nil, user_model.ErrEmailAddressNotExist{Email: username} + } + + return nil, nil, user_model.ErrUserNotExist{Name: username} +} |