code.gitea.io/gitea@v1.21.7/services/auth/signin.go (about)

     1  // Copyright 2021 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package auth
     5  
     6  import (
     7  	"context"
     8  	"strings"
     9  
    10  	"code.gitea.io/gitea/models/auth"
    11  	"code.gitea.io/gitea/models/db"
    12  	user_model "code.gitea.io/gitea/models/user"
    13  	"code.gitea.io/gitea/modules/log"
    14  	"code.gitea.io/gitea/services/auth/source/oauth2"
    15  	"code.gitea.io/gitea/services/auth/source/smtp"
    16  
    17  	_ "code.gitea.io/gitea/services/auth/source/db"   // register the sources (and below)
    18  	_ "code.gitea.io/gitea/services/auth/source/ldap" // register the ldap source
    19  	_ "code.gitea.io/gitea/services/auth/source/pam"  // register the pam source
    20  	_ "code.gitea.io/gitea/services/auth/source/sspi" // register the sspi source
    21  )
    22  
    23  // UserSignIn validates user name and password.
    24  func UserSignIn(ctx context.Context, username, password string) (*user_model.User, *auth.Source, error) {
    25  	var user *user_model.User
    26  	isEmail := false
    27  	if strings.Contains(username, "@") {
    28  		isEmail = true
    29  		emailAddress := user_model.EmailAddress{LowerEmail: strings.ToLower(strings.TrimSpace(username))}
    30  		// check same email
    31  		has, err := db.GetEngine(ctx).Get(&emailAddress)
    32  		if err != nil {
    33  			return nil, nil, err
    34  		}
    35  		if has {
    36  			if !emailAddress.IsActivated {
    37  				return nil, nil, user_model.ErrEmailAddressNotExist{
    38  					Email: username,
    39  				}
    40  			}
    41  			user = &user_model.User{ID: emailAddress.UID}
    42  		}
    43  	} else {
    44  		trimmedUsername := strings.TrimSpace(username)
    45  		if len(trimmedUsername) == 0 {
    46  			return nil, nil, user_model.ErrUserNotExist{Name: username}
    47  		}
    48  
    49  		user = &user_model.User{LowerName: strings.ToLower(trimmedUsername)}
    50  	}
    51  
    52  	if user != nil {
    53  		hasUser, err := user_model.GetUser(ctx, user)
    54  		if err != nil {
    55  			return nil, nil, err
    56  		}
    57  
    58  		if hasUser {
    59  			source, err := auth.GetSourceByID(user.LoginSource)
    60  			if err != nil {
    61  				return nil, nil, err
    62  			}
    63  
    64  			if !source.IsActive {
    65  				return nil, nil, oauth2.ErrAuthSourceNotActivated
    66  			}
    67  
    68  			authenticator, ok := source.Cfg.(PasswordAuthenticator)
    69  			if !ok {
    70  				return nil, nil, smtp.ErrUnsupportedLoginType
    71  			}
    72  
    73  			user, err := authenticator.Authenticate(ctx, user, user.LoginName, password)
    74  			if err != nil {
    75  				return nil, nil, err
    76  			}
    77  
    78  			// WARN: DON'T check user.IsActive, that will be checked on reqSign so that
    79  			// user could be hint to resend confirm email.
    80  			if user.ProhibitLogin {
    81  				return nil, nil, user_model.ErrUserProhibitLogin{UID: user.ID, Name: user.Name}
    82  			}
    83  
    84  			return user, source, nil
    85  		}
    86  	}
    87  
    88  	sources, err := auth.AllActiveSources()
    89  	if err != nil {
    90  		return nil, nil, err
    91  	}
    92  
    93  	for _, source := range sources {
    94  		if !source.IsActive {
    95  			// don't try to authenticate non-active sources
    96  			continue
    97  		}
    98  
    99  		authenticator, ok := source.Cfg.(PasswordAuthenticator)
   100  		if !ok {
   101  			continue
   102  		}
   103  
   104  		authUser, err := authenticator.Authenticate(ctx, nil, username, password)
   105  
   106  		if err == nil {
   107  			if !authUser.ProhibitLogin {
   108  				return authUser, source, nil
   109  			}
   110  			err = user_model.ErrUserProhibitLogin{UID: authUser.ID, Name: authUser.Name}
   111  		}
   112  
   113  		if user_model.IsErrUserNotExist(err) {
   114  			log.Debug("Failed to login '%s' via '%s': %v", username, source.Name, err)
   115  		} else {
   116  			log.Warn("Failed to login '%s' via '%s': %v", username, source.Name, err)
   117  		}
   118  	}
   119  
   120  	if isEmail {
   121  		return nil, nil, user_model.ErrEmailAddressNotExist{Email: username}
   122  	}
   123  
   124  	return nil, nil, user_model.ErrUserNotExist{Name: username}
   125  }