Various fixes in login sources (#10428)
This commit is contained in:
		
							parent
							
								
									542bd59239
								
							
						
					
					
						commit
						09dbd85a3a
					
				
					 15 changed files with 66 additions and 21 deletions
				
			
		|  | @ -57,6 +57,21 @@ func (err ErrNamePatternNotAllowed) Error() string { | |||
| 	return fmt.Sprintf("name pattern is not allowed [pattern: %s]", err.Pattern) | ||||
| } | ||||
| 
 | ||||
| // ErrNameCharsNotAllowed represents a "character not allowed in name" error.
 | ||||
| type ErrNameCharsNotAllowed struct { | ||||
| 	Name string | ||||
| } | ||||
| 
 | ||||
| // IsErrNameCharsNotAllowed checks if an error is an ErrNameCharsNotAllowed.
 | ||||
| func IsErrNameCharsNotAllowed(err error) bool { | ||||
| 	_, ok := err.(ErrNameCharsNotAllowed) | ||||
| 	return ok | ||||
| } | ||||
| 
 | ||||
| func (err ErrNameCharsNotAllowed) Error() string { | ||||
| 	return fmt.Sprintf("User name is invalid [%s]: must be valid alpha or numeric or dash(-_) or dot characters", err.Name) | ||||
| } | ||||
| 
 | ||||
| // ErrSSHDisabled represents an "SSH disabled" error.
 | ||||
| type ErrSSHDisabled struct { | ||||
| } | ||||
|  |  | |||
|  | @ -12,7 +12,6 @@ import ( | |||
| 	"fmt" | ||||
| 	"net/smtp" | ||||
| 	"net/textproto" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"code.gitea.io/gitea/modules/auth/ldap" | ||||
|  | @ -455,10 +454,6 @@ func composeFullName(firstname, surname, username string) string { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`) | ||||
| ) | ||||
| 
 | ||||
| // LoginViaLDAP queries if login/password is valid against the LDAP directory pool,
 | ||||
| // and create a local user if success when enabled.
 | ||||
| func LoginViaLDAP(user *User, login, password string, source *LoginSource) (*User, error) { | ||||
|  | @ -503,10 +498,6 @@ func LoginViaLDAP(user *User, login, password string, source *LoginSource) (*Use | |||
| 	if len(sr.Username) == 0 { | ||||
| 		sr.Username = login | ||||
| 	} | ||||
| 	// Validate username make sure it satisfies requirement.
 | ||||
| 	if alphaDashDotPattern.MatchString(sr.Username) { | ||||
| 		return nil, fmt.Errorf("Invalid pattern for attribute 'username' [%s]: must be valid alpha or numeric or dash(-_) or dot characters", sr.Username) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(sr.Mail) == 0 { | ||||
| 		sr.Mail = fmt.Sprintf("%s@localhost", sr.Username) | ||||
|  | @ -666,7 +657,8 @@ func LoginViaSMTP(user *User, login, password string, sourceID int64, cfg *SMTPC | |||
| // LoginViaPAM queries if login/password is valid against the PAM,
 | ||||
| // and create a local user if success when enabled.
 | ||||
| func LoginViaPAM(user *User, login, password string, sourceID int64, cfg *PAMConfig) (*User, error) { | ||||
| 	if err := pam.Auth(cfg.ServiceName, login, password); err != nil { | ||||
| 	pamLogin, err := pam.Auth(cfg.ServiceName, login, password) | ||||
| 	if err != nil { | ||||
| 		if strings.Contains(err.Error(), "Authentication failure") { | ||||
| 			return nil, ErrUserNotExist{0, login, 0} | ||||
| 		} | ||||
|  | @ -677,14 +669,21 @@ func LoginViaPAM(user *User, login, password string, sourceID int64, cfg *PAMCon | |||
| 		return user, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Allow PAM sources with `@` in their name, like from Active Directory
 | ||||
| 	username := pamLogin | ||||
| 	idx := strings.Index(pamLogin, "@") | ||||
| 	if idx > -1 { | ||||
| 		username = pamLogin[:idx] | ||||
| 	} | ||||
| 
 | ||||
| 	user = &User{ | ||||
| 		LowerName:   strings.ToLower(login), | ||||
| 		Name:        login, | ||||
| 		Email:       login, | ||||
| 		LowerName:   strings.ToLower(username), | ||||
| 		Name:        username, | ||||
| 		Email:       pamLogin, | ||||
| 		Passwd:      password, | ||||
| 		LoginType:   LoginPAM, | ||||
| 		LoginSource: sourceID, | ||||
| 		LoginName:   login, | ||||
| 		LoginName:   login, // This is what the user typed in
 | ||||
| 		IsActive:    true, | ||||
| 	} | ||||
| 	return user, CreateUser(user) | ||||
|  |  | |||
|  | @ -18,6 +18,7 @@ import ( | |||
| 	"image/png" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | @ -87,6 +88,9 @@ var ( | |||
| 
 | ||||
| 	// ErrUnsupportedLoginType login source is unknown error
 | ||||
| 	ErrUnsupportedLoginType = errors.New("Login source is unknown") | ||||
| 
 | ||||
| 	// Characters prohibited in a user name (anything except A-Za-z0-9_.-)
 | ||||
| 	alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`) | ||||
| ) | ||||
| 
 | ||||
| // User represents the object of individual and member of organization.
 | ||||
|  | @ -906,6 +910,11 @@ func isUsableName(names, patterns []string, name string) error { | |||
| 
 | ||||
| // IsUsableUsername returns an error when a username is reserved
 | ||||
| func IsUsableUsername(name string) error { | ||||
| 	// Validate username make sure it satisfies requirement.
 | ||||
| 	if alphaDashDotPattern.MatchString(name) { | ||||
| 		// Note: usually this error is normally caught up earlier in the UI
 | ||||
| 		return ErrNameCharsNotAllowed{Name: name} | ||||
| 	} | ||||
| 	return isUsableName(reservedUsernames, reservedUserPatterns, name) | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -13,7 +13,7 @@ import ( | |||
| ) | ||||
| 
 | ||||
| // Auth pam auth service
 | ||||
| func Auth(serviceName, userName, passwd string) error { | ||||
| func Auth(serviceName, userName, passwd string) (string, error) { | ||||
| 	t, err := pam.StartFunc(serviceName, userName, func(s pam.Style, msg string) (string, error) { | ||||
| 		switch s { | ||||
| 		case pam.PromptEchoOff: | ||||
|  | @ -25,12 +25,14 @@ func Auth(serviceName, userName, passwd string) error { | |||
| 	}) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 		return "", err | ||||
| 	} | ||||
| 
 | ||||
| 	if err = t.Authenticate(0); err != nil { | ||||
| 		return err | ||||
| 		return "", err | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| 	// PAM login names might suffer transformations in the PAM stack.
 | ||||
| 	// We should take whatever the PAM stack returns for it.
 | ||||
| 	return t.GetItem(pam.User) | ||||
| } | ||||
|  |  | |||
|  | @ -11,6 +11,6 @@ import ( | |||
| ) | ||||
| 
 | ||||
| // Auth not supported lack of pam tag
 | ||||
| func Auth(serviceName, userName, passwd string) error { | ||||
| 	return errors.New("PAM not supported") | ||||
| func Auth(serviceName, userName, passwd string) (string, error) { | ||||
| 	return "", errors.New("PAM not supported") | ||||
| } | ||||
|  |  | |||
|  | @ -35,7 +35,7 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) { | |||
| 
 | ||||
| 	// Create org.
 | ||||
| 	org := &models.User{ | ||||
| 		Name:       "All repo", | ||||
| 		Name:       "All_repo", | ||||
| 		IsActive:   true, | ||||
| 		Type:       models.UserTypeOrganization, | ||||
| 		Visibility: structs.VisibleTypePublic, | ||||
|  |  | |||
|  | @ -379,6 +379,7 @@ user_bio = Biography | |||
| 
 | ||||
| form.name_reserved = The username '%s' is reserved. | ||||
| form.name_pattern_not_allowed = The pattern '%s' is not allowed in a username. | ||||
| form.name_chars_not_allowed = User name '%s' contains invalid characters. | ||||
| 
 | ||||
| [settings] | ||||
| profile = Profile | ||||
|  |  | |||
|  | @ -124,6 +124,9 @@ func NewUserPost(ctx *context.Context, form auth.AdminCreateUserForm) { | |||
| 		case models.IsErrNamePatternNotAllowed(err): | ||||
| 			ctx.Data["Err_UserName"] = true | ||||
| 			ctx.RenderWithErr(ctx.Tr("user.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tplUserNew, &form) | ||||
| 		case models.IsErrNameCharsNotAllowed(err): | ||||
| 			ctx.Data["Err_UserName"] = true | ||||
| 			ctx.RenderWithErr(ctx.Tr("user.form.name_chars_not_allowed", err.(models.ErrNameCharsNotAllowed).Name), tplUserNew, &form) | ||||
| 		default: | ||||
| 			ctx.ServerError("CreateUser", err) | ||||
| 		} | ||||
|  |  | |||
|  | @ -67,6 +67,7 @@ func CreateOrg(ctx *context.APIContext, form api.CreateOrgOption) { | |||
| 	if err := models.CreateOrganization(org, u); err != nil { | ||||
| 		if models.IsErrUserAlreadyExist(err) || | ||||
| 			models.IsErrNameReserved(err) || | ||||
| 			models.IsErrNameCharsNotAllowed(err) || | ||||
| 			models.IsErrNamePatternNotAllowed(err) { | ||||
| 			ctx.Error(http.StatusUnprocessableEntity, "", err) | ||||
| 		} else { | ||||
|  |  | |||
|  | @ -91,6 +91,7 @@ func CreateUser(ctx *context.APIContext, form api.CreateUserOption) { | |||
| 		if models.IsErrUserAlreadyExist(err) || | ||||
| 			models.IsErrEmailAlreadyUsed(err) || | ||||
| 			models.IsErrNameReserved(err) || | ||||
| 			models.IsErrNameCharsNotAllowed(err) || | ||||
| 			models.IsErrNamePatternNotAllowed(err) { | ||||
| 			ctx.Error(http.StatusUnprocessableEntity, "", err) | ||||
| 		} else { | ||||
|  |  | |||
|  | @ -179,6 +179,7 @@ func Create(ctx *context.APIContext, form api.CreateOrgOption) { | |||
| 	if err := models.CreateOrganization(org, ctx.User); err != nil { | ||||
| 		if models.IsErrUserAlreadyExist(err) || | ||||
| 			models.IsErrNameReserved(err) || | ||||
| 			models.IsErrNameCharsNotAllowed(err) || | ||||
| 			models.IsErrNamePatternNotAllowed(err) { | ||||
| 			ctx.Error(http.StatusUnprocessableEntity, "", err) | ||||
| 		} else { | ||||
|  |  | |||
|  | @ -199,6 +199,8 @@ func handleMigrateError(ctx *context.APIContext, repoOwner *models.User, remoteA | |||
| 		ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("You have already reached your limit of %d repositories.", repoOwner.MaxCreationLimit())) | ||||
| 	case models.IsErrNameReserved(err): | ||||
| 		ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("The username '%s' is reserved.", err.(models.ErrNameReserved).Name)) | ||||
| 	case models.IsErrNameCharsNotAllowed(err): | ||||
| 		ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("The username '%s' contains invalid characters.", err.(models.ErrNameCharsNotAllowed).Name)) | ||||
| 	case models.IsErrNamePatternNotAllowed(err): | ||||
| 		ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("The pattern '%s' is not allowed in a username.", err.(models.ErrNamePatternNotAllowed).Pattern)) | ||||
| 	default: | ||||
|  |  | |||
|  | @ -928,6 +928,7 @@ func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form au | |||
| 		LoginName:   gothUser.(goth.User).UserID, | ||||
| 	} | ||||
| 
 | ||||
| 	//nolint: dupl
 | ||||
| 	if err := models.CreateUser(u); err != nil { | ||||
| 		switch { | ||||
| 		case models.IsErrUserAlreadyExist(err): | ||||
|  | @ -942,6 +943,9 @@ func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form au | |||
| 		case models.IsErrNamePatternNotAllowed(err): | ||||
| 			ctx.Data["Err_UserName"] = true | ||||
| 			ctx.RenderWithErr(ctx.Tr("user.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tplLinkAccount, &form) | ||||
| 		case models.IsErrNameCharsNotAllowed(err): | ||||
| 			ctx.Data["Err_UserName"] = true | ||||
| 			ctx.RenderWithErr(ctx.Tr("user.form.name_chars_not_allowed", err.(models.ErrNameCharsNotAllowed).Name), tplLinkAccount, &form) | ||||
| 		default: | ||||
| 			ctx.ServerError("CreateUser", err) | ||||
| 		} | ||||
|  |  | |||
|  | @ -400,6 +400,7 @@ func RegisterOpenIDPost(ctx *context.Context, cpt *captcha.Captcha, form auth.Si | |||
| 		Passwd:   password, | ||||
| 		IsActive: !setting.Service.RegisterEmailConfirm, | ||||
| 	} | ||||
| 	//nolint: dupl
 | ||||
| 	if err := models.CreateUser(u); err != nil { | ||||
| 		switch { | ||||
| 		case models.IsErrUserAlreadyExist(err): | ||||
|  | @ -414,6 +415,9 @@ func RegisterOpenIDPost(ctx *context.Context, cpt *captcha.Captcha, form auth.Si | |||
| 		case models.IsErrNamePatternNotAllowed(err): | ||||
| 			ctx.Data["Err_UserName"] = true | ||||
| 			ctx.RenderWithErr(ctx.Tr("user.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tplSignUpOID, &form) | ||||
| 		case models.IsErrNameCharsNotAllowed(err): | ||||
| 			ctx.Data["Err_UserName"] = true | ||||
| 			ctx.RenderWithErr(ctx.Tr("user.form.name_chars_not_allowed", err.(models.ErrNameCharsNotAllowed).Name), tplSignUpOID, &form) | ||||
| 		default: | ||||
| 			ctx.ServerError("CreateUser", err) | ||||
| 		} | ||||
|  |  | |||
|  | @ -58,6 +58,9 @@ func handleUsernameChange(ctx *context.Context, newName string) { | |||
| 			case models.IsErrNamePatternNotAllowed(err): | ||||
| 				ctx.Flash.Error(ctx.Tr("user.form.name_pattern_not_allowed", newName)) | ||||
| 				ctx.Redirect(setting.AppSubURL + "/user/settings") | ||||
| 			case models.IsErrNameCharsNotAllowed(err): | ||||
| 				ctx.Flash.Error(ctx.Tr("user.form.name_chars_not_allowed", newName)) | ||||
| 				ctx.Redirect(setting.AppSubURL + "/user/settings") | ||||
| 			default: | ||||
| 				ctx.ServerError("ChangeUserName", err) | ||||
| 			} | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue