code.gitea.io/gitea@v1.22.3/services/auth/source/smtp/source_authenticate.go (about) 1 // Copyright 2021 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package smtp 5 6 import ( 7 "context" 8 "errors" 9 "net/smtp" 10 "net/textproto" 11 "strings" 12 13 auth_model "code.gitea.io/gitea/models/auth" 14 user_model "code.gitea.io/gitea/models/user" 15 "code.gitea.io/gitea/modules/optional" 16 "code.gitea.io/gitea/modules/util" 17 ) 18 19 // Authenticate queries if the provided login/password is authenticates against the SMTP server 20 // Users will be autoregistered as required 21 func (source *Source) Authenticate(ctx context.Context, user *user_model.User, userName, password string) (*user_model.User, error) { 22 // Verify allowed domains. 23 if len(source.AllowedDomains) > 0 { 24 idx := strings.Index(userName, "@") 25 if idx == -1 { 26 return nil, user_model.ErrUserNotExist{Name: userName} 27 } else if !util.SliceContainsString(strings.Split(source.AllowedDomains, ","), userName[idx+1:], true) { 28 return nil, user_model.ErrUserNotExist{Name: userName} 29 } 30 } 31 32 var auth smtp.Auth 33 switch source.Auth { 34 case PlainAuthentication: 35 auth = smtp.PlainAuth("", userName, password, source.Host) 36 case LoginAuthentication: 37 auth = &loginAuthenticator{userName, password} 38 case CRAMMD5Authentication: 39 auth = smtp.CRAMMD5Auth(userName, password) 40 default: 41 return nil, errors.New("unsupported SMTP auth type") 42 } 43 44 if err := Authenticate(auth, source); err != nil { 45 // Check standard error format first, 46 // then fallback to worse case. 47 tperr, ok := err.(*textproto.Error) 48 if (ok && tperr.Code == 535) || 49 strings.Contains(err.Error(), "Username and Password not accepted") { 50 return nil, user_model.ErrUserNotExist{Name: userName} 51 } 52 if (ok && tperr.Code == 534) || 53 strings.Contains(err.Error(), "Application-specific password required") { 54 return nil, user_model.ErrUserNotExist{Name: userName} 55 } 56 return nil, err 57 } 58 59 if user != nil { 60 return user, nil 61 } 62 63 username := userName 64 idx := strings.Index(userName, "@") 65 if idx > -1 { 66 username = userName[:idx] 67 } 68 69 user = &user_model.User{ 70 LowerName: strings.ToLower(username), 71 Name: strings.ToLower(username), 72 Email: userName, 73 Passwd: password, 74 LoginType: auth_model.SMTP, 75 LoginSource: source.authSource.ID, 76 LoginName: userName, 77 } 78 overwriteDefault := &user_model.CreateUserOverwriteOptions{ 79 IsActive: optional.Some(true), 80 } 81 82 if err := user_model.CreateUser(ctx, user, overwriteDefault); err != nil { 83 return user, err 84 } 85 86 return user, nil 87 } 88 89 // IsSkipLocalTwoFA returns if this source should skip local 2fa for password authentication 90 func (source *Source) IsSkipLocalTwoFA() bool { 91 return source.SkipLocalTwoFA 92 }