code.gitea.io/gitea@v1.22.3/services/auth/source/pam/source_authenticate.go (about)

     1  // Copyright 2021 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package pam
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"strings"
    10  
    11  	"code.gitea.io/gitea/models/auth"
    12  	user_model "code.gitea.io/gitea/models/user"
    13  	"code.gitea.io/gitea/modules/auth/pam"
    14  	"code.gitea.io/gitea/modules/optional"
    15  	"code.gitea.io/gitea/modules/setting"
    16  
    17  	"github.com/google/uuid"
    18  )
    19  
    20  // Authenticate queries if login/password is valid against the PAM,
    21  // and create a local user if success when enabled.
    22  func (source *Source) Authenticate(ctx context.Context, user *user_model.User, userName, password string) (*user_model.User, error) {
    23  	pamLogin, err := pam.Auth(source.ServiceName, userName, password)
    24  	if err != nil {
    25  		if strings.Contains(err.Error(), "Authentication failure") {
    26  			return nil, user_model.ErrUserNotExist{Name: userName}
    27  		}
    28  		return nil, err
    29  	}
    30  
    31  	if user != nil {
    32  		return user, nil
    33  	}
    34  
    35  	// Allow PAM sources with `@` in their name, like from Active Directory
    36  	username := pamLogin
    37  	email := pamLogin
    38  	idx := strings.Index(pamLogin, "@")
    39  	if idx > -1 {
    40  		username = pamLogin[:idx]
    41  	}
    42  	if user_model.ValidateEmail(email) != nil {
    43  		if source.EmailDomain != "" {
    44  			email = fmt.Sprintf("%s@%s", username, source.EmailDomain)
    45  		} else {
    46  			email = fmt.Sprintf("%s@%s", username, setting.Service.NoReplyAddress)
    47  		}
    48  		if user_model.ValidateEmail(email) != nil {
    49  			email = uuid.New().String() + "@localhost"
    50  		}
    51  	}
    52  
    53  	user = &user_model.User{
    54  		LowerName:   strings.ToLower(username),
    55  		Name:        username,
    56  		Email:       email,
    57  		Passwd:      password,
    58  		LoginType:   auth.PAM,
    59  		LoginSource: source.authSource.ID,
    60  		LoginName:   userName, // This is what the user typed in
    61  	}
    62  	overwriteDefault := &user_model.CreateUserOverwriteOptions{
    63  		IsActive: optional.Some(true),
    64  	}
    65  
    66  	if err := user_model.CreateUser(ctx, user, overwriteDefault); err != nil {
    67  		return user, err
    68  	}
    69  
    70  	return user, nil
    71  }
    72  
    73  // IsSkipLocalTwoFA returns if this source should skip local 2fa for password authentication
    74  func (source *Source) IsSkipLocalTwoFA() bool {
    75  	return source.SkipLocalTwoFA
    76  }