Respect DefaultUserIsRestricted system default when creating new user (#19310)

* Apply DefaultUserIsRestricted in CreateUser

* Enforce system defaults in CreateUser

Allow for overwrites with CreateUserOverwriteOptions

* Fix compilation errors

* Add "restricted" option to create user command

* Add "restricted" option to create user admin api

* Respect default setting.Service.RegisterEmailConfirm and setting.Service.RegisterManualConfirm where needed

* Revert "Respect default setting.Service.RegisterEmailConfirm and setting.Service.RegisterManualConfirm where needed"

This reverts commit ee95d3e8dc9e9fff4fa66a5111e4d3930280e033.
This commit is contained in:
Jimmy Praet 2022-04-29 21:38:11 +02:00 committed by GitHub
parent 219c87e7d8
commit 5aebc4f000
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 169 additions and 84 deletions

View File

@ -25,6 +25,7 @@ import (
repo_module "code.gitea.io/gitea/modules/repository" repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/util"
auth_service "code.gitea.io/gitea/services/auth" auth_service "code.gitea.io/gitea/services/auth"
"code.gitea.io/gitea/services/auth/source/oauth2" "code.gitea.io/gitea/services/auth/source/oauth2"
"code.gitea.io/gitea/services/auth/source/smtp" "code.gitea.io/gitea/services/auth/source/smtp"
@ -114,6 +115,10 @@ var (
Name: "access-token", Name: "access-token",
Usage: "Generate access token for the user", Usage: "Generate access token for the user",
}, },
cli.BoolFlag{
Name: "restricted",
Usage: "Make a restricted user account",
},
}, },
} }
@ -559,17 +564,26 @@ func runCreateUser(c *cli.Context) error {
changePassword = c.Bool("must-change-password") changePassword = c.Bool("must-change-password")
} }
restricted := util.OptionalBoolNone
if c.IsSet("restricted") {
restricted = util.OptionalBoolOf(c.Bool("restricted"))
}
u := &user_model.User{ u := &user_model.User{
Name: username, Name: username,
Email: c.String("email"), Email: c.String("email"),
Passwd: password, Passwd: password,
IsActive: true,
IsAdmin: c.Bool("admin"), IsAdmin: c.Bool("admin"),
MustChangePassword: changePassword, MustChangePassword: changePassword,
Theme: setting.UI.DefaultTheme,
} }
if err := user_model.CreateUser(u); err != nil { overwriteDefault := &user_model.CreateUserOverwriteOptions{
IsActive: util.OptionalBoolTrue,
IsRestricted: restricted,
}
if err := user_model.CreateUser(u, overwriteDefault); err != nil {
return fmt.Errorf("CreateUser: %v", err) return fmt.Errorf("CreateUser: %v", err)
} }

View File

@ -621,7 +621,14 @@ func IsUsableUsername(name string) error {
// CreateUserOverwriteOptions are an optional options who overwrite system defaults on user creation // CreateUserOverwriteOptions are an optional options who overwrite system defaults on user creation
type CreateUserOverwriteOptions struct { type CreateUserOverwriteOptions struct {
Visibility structs.VisibleType KeepEmailPrivate util.OptionalBool
Visibility *structs.VisibleType
AllowCreateOrganization util.OptionalBool
EmailNotificationsPreference *string
MaxRepoCreation *int
Theme *string
IsRestricted util.OptionalBool
IsActive util.OptionalBool
} }
// CreateUser creates record of a new user. // CreateUser creates record of a new user.
@ -637,10 +644,36 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e
u.EmailNotificationsPreference = setting.Admin.DefaultEmailNotification u.EmailNotificationsPreference = setting.Admin.DefaultEmailNotification
u.MaxRepoCreation = -1 u.MaxRepoCreation = -1
u.Theme = setting.UI.DefaultTheme u.Theme = setting.UI.DefaultTheme
u.IsRestricted = setting.Service.DefaultUserIsRestricted
u.IsActive = !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm)
// overwrite defaults if set // overwrite defaults if set
if len(overwriteDefault) != 0 && overwriteDefault[0] != nil { if len(overwriteDefault) != 0 && overwriteDefault[0] != nil {
u.Visibility = overwriteDefault[0].Visibility overwrite := overwriteDefault[0]
if !overwrite.KeepEmailPrivate.IsNone() {
u.KeepEmailPrivate = overwrite.KeepEmailPrivate.IsTrue()
}
if overwrite.Visibility != nil {
u.Visibility = *overwrite.Visibility
}
if !overwrite.AllowCreateOrganization.IsNone() {
u.AllowCreateOrganization = overwrite.AllowCreateOrganization.IsTrue()
}
if overwrite.EmailNotificationsPreference != nil {
u.EmailNotificationsPreference = *overwrite.EmailNotificationsPreference
}
if overwrite.MaxRepoCreation != nil {
u.MaxRepoCreation = *overwrite.MaxRepoCreation
}
if overwrite.Theme != nil {
u.Theme = *overwrite.Theme
}
if !overwrite.IsRestricted.IsNone() {
u.IsRestricted = overwrite.IsRestricted.IsTrue()
}
if !overwrite.IsActive.IsNone() {
u.IsActive = overwrite.IsActive.IsTrue()
}
} }
// validate data // validate data

View File

@ -19,6 +19,7 @@ type CreateUserOption struct {
Password string `json:"password" binding:"Required;MaxSize(255)"` Password string `json:"password" binding:"Required;MaxSize(255)"`
MustChangePassword *bool `json:"must_change_password"` MustChangePassword *bool `json:"must_change_password"`
SendNotify bool `json:"send_notify"` SendNotify bool `json:"send_notify"`
Restricted *bool `json:"restricted"`
Visibility string `json:"visibility" binding:"In(,public,limited,private)"` Visibility string `json:"visibility" binding:"In(,public,limited,private)"`
} }

View File

@ -22,6 +22,7 @@ import (
"code.gitea.io/gitea/modules/password" "code.gitea.io/gitea/modules/password"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/user" "code.gitea.io/gitea/routers/api/v1/user"
"code.gitea.io/gitea/routers/api/v1/utils" "code.gitea.io/gitea/routers/api/v1/utils"
@ -82,7 +83,6 @@ func CreateUser(ctx *context.APIContext) {
Email: form.Email, Email: form.Email,
Passwd: form.Password, Passwd: form.Password,
MustChangePassword: true, MustChangePassword: true,
IsActive: true,
LoginType: auth.Plain, LoginType: auth.Plain,
} }
if form.MustChangePassword != nil { if form.MustChangePassword != nil {
@ -108,11 +108,17 @@ func CreateUser(ctx *context.APIContext) {
return return
} }
var overwriteDefault *user_model.CreateUserOverwriteOptions overwriteDefault := &user_model.CreateUserOverwriteOptions{
if form.Visibility != "" { IsActive: util.OptionalBoolTrue,
overwriteDefault = &user_model.CreateUserOverwriteOptions{
Visibility: api.VisibilityModes[form.Visibility],
} }
if form.Restricted != nil {
overwriteDefault.IsRestricted = util.OptionalBoolOf(*form.Restricted)
}
if form.Visibility != "" {
visibility := api.VisibilityModes[form.Visibility]
overwriteDefault.Visibility = &visibility
} }
if err := user_model.CreateUser(u, overwriteDefault); err != nil { if err := user_model.CreateUser(u, overwriteDefault); err != nil {

View File

@ -503,9 +503,13 @@ func SubmitInstall(ctx *context.Context) {
Email: form.AdminEmail, Email: form.AdminEmail,
Passwd: form.AdminPasswd, Passwd: form.AdminPasswd,
IsAdmin: true, IsAdmin: true,
IsActive: true,
} }
if err = user_model.CreateUser(u); err != nil { overwriteDefault := &user_model.CreateUserOverwriteOptions{
IsRestricted: util.OptionalBoolFalse,
IsActive: util.OptionalBoolTrue,
}
if err = user_model.CreateUser(u, overwriteDefault); err != nil {
if !user_model.IsErrUserAlreadyExist(err) { if !user_model.IsErrUserAlreadyExist(err) {
setting.InstallLock = false setting.InstallLock = false
ctx.Data["Err_AdminName"] = true ctx.Data["Err_AdminName"] = true

View File

@ -125,10 +125,14 @@ func NewUserPost(ctx *context.Context) {
Name: form.UserName, Name: form.UserName,
Email: form.Email, Email: form.Email,
Passwd: form.Password, Passwd: form.Password,
IsActive: true,
LoginType: auth.Plain, LoginType: auth.Plain,
} }
overwriteDefault := &user_model.CreateUserOverwriteOptions{
IsActive: util.OptionalBoolTrue,
Visibility: &form.Visibility,
}
if len(form.LoginType) > 0 { if len(form.LoginType) > 0 {
fields := strings.Split(form.LoginType, "-") fields := strings.Split(form.LoginType, "-")
if len(fields) == 2 { if len(fields) == 2 {
@ -163,7 +167,7 @@ func NewUserPost(ctx *context.Context) {
u.MustChangePassword = form.MustChangePassword u.MustChangePassword = form.MustChangePassword
} }
if err := user_model.CreateUser(u, &user_model.CreateUserOverwriteOptions{Visibility: form.Visibility}); err != nil { if err := user_model.CreateUser(u, overwriteDefault); err != nil {
switch { switch {
case user_model.IsErrUserAlreadyExist(err): case user_model.IsErrUserAlreadyExist(err):
ctx.Data["Err_UserName"] = true ctx.Data["Err_UserName"] = true

View File

@ -510,11 +510,9 @@ func SignUpPost(ctx *context.Context) {
Name: form.UserName, Name: form.UserName,
Email: form.Email, Email: form.Email,
Passwd: form.Password, Passwd: form.Password,
IsActive: !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm),
IsRestricted: setting.Service.DefaultUserIsRestricted,
} }
if !createAndHandleCreatedUser(ctx, tplSignUp, form, u, nil, false) { if !createAndHandleCreatedUser(ctx, tplSignUp, form, u, nil, nil, false) {
// error already handled // error already handled
return return
} }
@ -525,8 +523,8 @@ func SignUpPost(ctx *context.Context) {
// createAndHandleCreatedUser calls createUserInContext and // createAndHandleCreatedUser calls createUserInContext and
// then handleUserCreated. // then handleUserCreated.
func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form interface{}, u *user_model.User, gothUser *goth.User, allowLink bool) bool { func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form interface{}, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) bool {
if !createUserInContext(ctx, tpl, form, u, gothUser, allowLink) { if !createUserInContext(ctx, tpl, form, u, overwrites, gothUser, allowLink) {
return false return false
} }
return handleUserCreated(ctx, u, gothUser) return handleUserCreated(ctx, u, gothUser)
@ -534,8 +532,8 @@ func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form int
// createUserInContext creates a user and handles errors within a given context. // createUserInContext creates a user and handles errors within a given context.
// Optionally a template can be specified. // Optionally a template can be specified.
func createUserInContext(ctx *context.Context, tpl base.TplName, form interface{}, u *user_model.User, gothUser *goth.User, allowLink bool) (ok bool) { func createUserInContext(ctx *context.Context, tpl base.TplName, form interface{}, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) (ok bool) {
if err := user_model.CreateUser(u); err != nil { if err := user_model.CreateUser(u, overwrites); err != nil {
if allowLink && (user_model.IsErrUserAlreadyExist(err) || user_model.IsErrEmailAlreadyUsed(err)) { if allowLink && (user_model.IsErrUserAlreadyExist(err) || user_model.IsErrEmailAlreadyUsed(err)) {
if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingAuto { if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingAuto {
var user *user_model.User var user *user_model.User

View File

@ -283,13 +283,12 @@ func LinkAccountPostRegister(ctx *context.Context) {
Name: form.UserName, Name: form.UserName,
Email: form.Email, Email: form.Email,
Passwd: form.Password, Passwd: form.Password,
IsActive: !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm),
LoginType: auth.OAuth2, LoginType: auth.OAuth2,
LoginSource: authSource.ID, LoginSource: authSource.ID,
LoginName: gothUser.UserID, LoginName: gothUser.UserID,
} }
if !createAndHandleCreatedUser(ctx, tplLinkAccount, form, u, &gothUser, false) { if !createAndHandleCreatedUser(ctx, tplLinkAccount, form, u, nil, &gothUser, false) {
// error already handled // error already handled
return return
} }

View File

@ -24,6 +24,7 @@ import (
"code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/session"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/modules/web/middleware" "code.gitea.io/gitea/modules/web/middleware"
auth_service "code.gitea.io/gitea/services/auth" auth_service "code.gitea.io/gitea/services/auth"
@ -870,16 +871,18 @@ func SignInOAuthCallback(ctx *context.Context) {
Name: getUserName(&gothUser), Name: getUserName(&gothUser),
FullName: gothUser.Name, FullName: gothUser.Name,
Email: gothUser.Email, Email: gothUser.Email,
IsActive: !setting.OAuth2Client.RegisterEmailConfirm,
LoginType: auth.OAuth2, LoginType: auth.OAuth2,
LoginSource: authSource.ID, LoginSource: authSource.ID,
LoginName: gothUser.UserID, LoginName: gothUser.UserID,
IsRestricted: setting.Service.DefaultUserIsRestricted, }
overwriteDefault := &user_model.CreateUserOverwriteOptions{
IsActive: util.OptionalBoolOf(!setting.OAuth2Client.RegisterEmailConfirm),
} }
setUserGroupClaims(authSource, u, &gothUser) setUserGroupClaims(authSource, u, &gothUser)
if !createAndHandleCreatedUser(ctx, base.TplName(""), nil, u, &gothUser, setting.OAuth2Client.AccountLinking != setting.OAuth2AccountLinkingDisabled) { if !createAndHandleCreatedUser(ctx, base.TplName(""), nil, u, overwriteDefault, &gothUser, setting.OAuth2Client.AccountLinking != setting.OAuth2AccountLinkingDisabled) {
// error already handled // error already handled
return return
} }

View File

@ -426,9 +426,8 @@ func RegisterOpenIDPost(ctx *context.Context) {
Name: form.UserName, Name: form.UserName,
Email: form.Email, Email: form.Email,
Passwd: password, Passwd: password,
IsActive: !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm),
} }
if !createUserInContext(ctx, tplSignUpOID, form, u, nil, false) { if !createUserInContext(ctx, tplSignUpOID, form, u, nil, nil, false) {
// error already handled // error already handled
return return
} }

View File

@ -12,6 +12,7 @@ import (
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web/middleware" "code.gitea.io/gitea/modules/web/middleware"
"code.gitea.io/gitea/services/mailer" "code.gitea.io/gitea/services/mailer"
@ -107,9 +108,13 @@ func (r *ReverseProxy) newUser(req *http.Request) *user_model.User {
user := &user_model.User{ user := &user_model.User{
Name: username, Name: username,
Email: email, Email: email,
IsActive: true,
} }
if err := user_model.CreateUser(user); err != nil {
overwriteDefault := user_model.CreateUserOverwriteOptions{
IsActive: util.OptionalBoolTrue,
}
if err := user_model.CreateUser(user, &overwriteDefault); err != nil {
// FIXME: should I create a system notice? // FIXME: should I create a system notice?
log.Error("CreateUser: %v", err) log.Error("CreateUser: %v", err)
return nil return nil

View File

@ -13,6 +13,7 @@ import (
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/mailer" "code.gitea.io/gitea/services/mailer"
user_service "code.gitea.io/gitea/services/user" user_service "code.gitea.io/gitea/services/user"
) )
@ -92,12 +93,14 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str
LoginType: source.authSource.Type, LoginType: source.authSource.Type,
LoginSource: source.authSource.ID, LoginSource: source.authSource.ID,
LoginName: userName, LoginName: userName,
IsActive: true,
IsAdmin: sr.IsAdmin, IsAdmin: sr.IsAdmin,
IsRestricted: sr.IsRestricted, }
overwriteDefault := &user_model.CreateUserOverwriteOptions{
IsRestricted: util.OptionalBoolOf(sr.IsRestricted),
IsActive: util.OptionalBoolTrue,
} }
err := user_model.CreateUser(user) err := user_model.CreateUser(user, overwriteDefault)
if err != nil { if err != nil {
return user, err return user, err
} }

View File

@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
user_service "code.gitea.io/gitea/services/user" user_service "code.gitea.io/gitea/services/user"
) )
@ -110,11 +111,13 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error {
LoginName: su.Username, LoginName: su.Username,
Email: su.Mail, Email: su.Mail,
IsAdmin: su.IsAdmin, IsAdmin: su.IsAdmin,
IsRestricted: su.IsRestricted, }
IsActive: true, overwriteDefault := &user_model.CreateUserOverwriteOptions{
IsRestricted: util.OptionalBoolOf(su.IsRestricted),
IsActive: util.OptionalBoolTrue,
} }
err = user_model.CreateUser(usr) err = user_model.CreateUser(usr, overwriteDefault)
if err != nil { if err != nil {
log.Error("SyncExternalUsers[%s]: Error creating user %s: %v", source.authSource.Name, su.Username, err) log.Error("SyncExternalUsers[%s]: Error creating user %s: %v", source.authSource.Name, su.Username, err)

View File

@ -12,6 +12,7 @@ import (
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/auth/pam" "code.gitea.io/gitea/modules/auth/pam"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/mailer" "code.gitea.io/gitea/services/mailer"
"github.com/google/uuid" "github.com/google/uuid"
@ -58,10 +59,12 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str
LoginType: auth.PAM, LoginType: auth.PAM,
LoginSource: source.authSource.ID, LoginSource: source.authSource.ID,
LoginName: userName, // This is what the user typed in LoginName: userName, // This is what the user typed in
IsActive: true, }
overwriteDefault := &user_model.CreateUserOverwriteOptions{
IsActive: util.OptionalBoolTrue,
} }
if err := user_model.CreateUser(user); err != nil { if err := user_model.CreateUser(user, overwriteDefault); err != nil {
return user, err return user, err
} }

View File

@ -74,10 +74,12 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str
LoginType: auth_model.SMTP, LoginType: auth_model.SMTP,
LoginSource: source.authSource.ID, LoginSource: source.authSource.ID,
LoginName: userName, LoginName: userName,
IsActive: true, }
overwriteDefault := &user_model.CreateUserOverwriteOptions{
IsActive: util.OptionalBoolTrue,
} }
if err := user_model.CreateUser(user); err != nil { if err := user_model.CreateUser(user, overwriteDefault); err != nil {
return user, err return user, err
} }

View File

@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web/middleware" "code.gitea.io/gitea/modules/web/middleware"
"code.gitea.io/gitea/services/auth/source/sspi" "code.gitea.io/gitea/services/auth/source/sspi"
"code.gitea.io/gitea/services/mailer" "code.gitea.io/gitea/services/mailer"
@ -189,15 +190,18 @@ func (s *SSPI) newUser(username string, cfg *sspi.Source) (*user_model.User, err
user := &user_model.User{ user := &user_model.User{
Name: username, Name: username,
Email: email, Email: email,
KeepEmailPrivate: true,
Passwd: gouuid.New().String(), Passwd: gouuid.New().String(),
IsActive: cfg.AutoActivateUsers,
Language: cfg.DefaultLanguage, Language: cfg.DefaultLanguage,
UseCustomAvatar: true, UseCustomAvatar: true,
Avatar: avatars.DefaultAvatarLink(), Avatar: avatars.DefaultAvatarLink(),
EmailNotificationsPreference: user_model.EmailNotificationsDisabled,
} }
if err := user_model.CreateUser(user); err != nil { emailNotificationPreference := user_model.EmailNotificationsDisabled
overwriteDefault := &user_model.CreateUserOverwriteOptions{
IsActive: util.OptionalBoolOf(cfg.AutoActivateUsers),
KeepEmailPrivate: util.OptionalBoolTrue,
EmailNotificationsPreference: &emailNotificationPreference,
}
if err := user_model.CreateUser(user, overwriteDefault); err != nil {
return nil, err return nil, err
} }

View File

@ -14471,6 +14471,10 @@
"type": "string", "type": "string",
"x-go-name": "Password" "x-go-name": "Password"
}, },
"restricted": {
"type": "boolean",
"x-go-name": "Restricted"
},
"send_notify": { "send_notify": {
"type": "boolean", "type": "boolean",
"x-go-name": "SendNotify" "x-go-name": "SendNotify"