gitea/services/auth/signin.go

116 lines
2.9 KiB
Go

// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package auth
import (
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/login"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
_ "code.gitea.io/gitea/services/auth/source/db" // register the sources (and below)
_ "code.gitea.io/gitea/services/auth/source/ldap"
_ "code.gitea.io/gitea/services/auth/source/oauth2"
_ "code.gitea.io/gitea/services/auth/source/pam"
_ "code.gitea.io/gitea/services/auth/source/smtp"
_ "code.gitea.io/gitea/services/auth/source/sspi"
)
// UserSignIn validates user name and password.
func UserSignIn(username, password string) (*models.User, *login.Source, error) {
var user *models.User
if strings.Contains(username, "@") {
user = &models.User{Email: strings.ToLower(strings.TrimSpace(username))}
// check same email
cnt, err := db.Count(user)
if err != nil {
return nil, nil, err
}
if cnt > 1 {
return nil, nil, user_model.ErrEmailAlreadyUsed{
Email: user.Email,
}
}
} else {
trimmedUsername := strings.TrimSpace(username)
if len(trimmedUsername) == 0 {
return nil, nil, models.ErrUserNotExist{Name: username}
}
user = &models.User{LowerName: strings.ToLower(trimmedUsername)}
}
hasUser, err := models.GetUser(user)
if err != nil {
return nil, nil, err
}
if hasUser {
source, err := login.GetSourceByID(user.LoginSource)
if err != nil {
return nil, nil, err
}
if !source.IsActive {
return nil, nil, models.ErrLoginSourceNotActived
}
authenticator, ok := source.Cfg.(PasswordAuthenticator)
if !ok {
return nil, nil, models.ErrUnsupportedLoginType
}
user, err := authenticator.Authenticate(user, username, 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, models.ErrUserProhibitLogin{UID: user.ID, Name: user.Name}
}
return user, source, nil
}
sources, err := login.AllActiveSources()
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(nil, username, password)
if err == nil {
if !authUser.ProhibitLogin {
return authUser, source, nil
}
err = models.ErrUserProhibitLogin{UID: authUser.ID, Name: authUser.Name}
}
if models.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)
}
}
return nil, nil, models.ErrUserNotExist{Name: username}
}