From 23acb29e560cd564ddfe114e6d5ea4fc9b392a46 Mon Sep 17 00:00:00 2001 From: Lanre Adelowo Date: Sat, 21 Jul 2018 17:07:47 +0100 Subject: [PATCH] force users to change password if account was created by an admin --- models/user.go | 30 ++++++++++-------- modules/context/auth.go | 20 +++++++++--- routers/admin/users.go | 11 ++++--- routers/user/auth.go | 67 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 21 deletions(-) diff --git a/models/user.go b/models/user.go index 32b9bfec9..21e77571c 100644 --- a/models/user.go +++ b/models/user.go @@ -14,6 +14,7 @@ import ( "errors" "fmt" "image" + // Needed for jpeg support _ "image/jpeg" "image/png" @@ -83,18 +84,23 @@ type User struct { Email string `xorm:"NOT NULL"` KeepEmailPrivate bool Passwd string `xorm:"NOT NULL"` - LoginType LoginType - LoginSource int64 `xorm:"NOT NULL DEFAULT 0"` - LoginName string - Type UserType - OwnedOrgs []*User `xorm:"-"` - Orgs []*User `xorm:"-"` - Repos []*Repository `xorm:"-"` - Location string - Website string - Rands string `xorm:"VARCHAR(10)"` - Salt string `xorm:"VARCHAR(10)"` - Language string `xorm:"VARCHAR(5)"` + + // MustChangePassword is an attribute that determines if a user + // is to change his/her password after registration. + MustChangePassword bool `xorm:"NOT NULL DEFAULT false"` + + LoginType LoginType + LoginSource int64 `xorm:"NOT NULL DEFAULT 0"` + LoginName string + Type UserType + OwnedOrgs []*User `xorm:"-"` + Orgs []*User `xorm:"-"` + Repos []*Repository `xorm:"-"` + Location string + Website string + Rands string `xorm:"VARCHAR(10)"` + Salt string `xorm:"VARCHAR(10)"` + Language string `xorm:"VARCHAR(5)"` CreatedUnix util.TimeStamp `xorm:"INDEX created"` UpdatedUnix util.TimeStamp `xorm:"INDEX updated"` diff --git a/modules/context/auth.go b/modules/context/auth.go index c38cc3948..c5df1d68d 100644 --- a/modules/context/auth.go +++ b/modules/context/auth.go @@ -31,10 +31,22 @@ func Toggle(options *ToggleOptions) macaron.Handler { } // Check prohibit login users. - if ctx.IsSigned && ctx.User.ProhibitLogin { - ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") - ctx.HTML(200, "user/auth/prohibit_login") - return + if ctx.IsSigned { + + if ctx.User.ProhibitLogin { + ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") + ctx.HTML(200, "user/auth/prohibit_login") + return + } + + if ctx.Req.URL.Path == "/user/change_password" { + return + } else if ctx.User.MustChangePassword { + ctx.Data["Title"] = ctx.Tr("auth.must_change_password") + ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password" + ctx.Redirect(setting.AppSubURL + "/user/change_password") + return + } } // Redirect to dashboard if user tries to visit any non-login page. diff --git a/routers/admin/users.go b/routers/admin/users.go index 9aa78db10..bc7850d7a 100644 --- a/routers/admin/users.go +++ b/routers/admin/users.go @@ -77,11 +77,12 @@ func NewUserPost(ctx *context.Context, form auth.AdminCreateUserForm) { } u := &models.User{ - Name: form.UserName, - Email: form.Email, - Passwd: form.Password, - IsActive: true, - LoginType: models.LoginPlain, + Name: form.UserName, + Email: form.Email, + Passwd: form.Password, + IsActive: true, + LoginType: models.LoginPlain, + MustChangePassword: false, } if len(form.LoginType) > 0 { diff --git a/routers/user/auth.go b/routers/user/auth.go index 11cc9f6b7..184b374f3 100644 --- a/routers/user/auth.go +++ b/routers/user/auth.go @@ -28,6 +28,7 @@ import ( ) const ( + tplMustChangePassword = "user/auth/change_passwd" // tplSignIn template for sign in page tplSignIn base.TplName = "user/auth/signin" // tplSignUp template path for sign up page @@ -1185,3 +1186,69 @@ func ResetPasswdPost(ctx *context.Context) { ctx.Data["IsResetFailed"] = true ctx.HTML(200, tplResetPassword) } + +// MustChangePassword renders the page to change a user's password +func MustChangePassword(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("auth.must_change_password") + ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password" + + ctx.HTML(200, tplMustChangePassword) +} + +// MustChangePasswordPost response for updating a user's password after his/her +// account was created by an admin +func MustChangePasswordPost(ctx *context.Context, cpt *captcha.Captcha, form auth.MustChangePasswordForm) { + ctx.Data["Title"] = ctx.Tr("auth.must_change_password") + + ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/sign_up" + + if ctx.HasError() { + ctx.HTML(200, tplMustChangePassword) + return + } + + u := ctx.User + + // Make sure only requests for users who are eligible to change their password via + // this method passes through + if !u.MustChangePassword { + ctx.ServerError("MustUpdatePassword", errors.New("cannot update password.. Please visit the settings page")) + return + } + + if form.Password != form.Retype { + ctx.Data["Err_Password"] = true + ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplMustChangePassword, &form) + return + } + + if len(form.Password) < setting.MinPasswordLength { + ctx.Data["Err_Password"] = true + ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplMustChangePassword, &form) + return + } + + var err error + if u.Rands, err = models.GetUserSalt(); err != nil { + ctx.ServerError("UpdateUser", err) + return + } + + if u.Salt, err = models.GetUserSalt(); err != nil { + ctx.ServerError("UpdateUser", err) + return + } + + u.HashPassword(form.Password) + u.MustChangePassword = false + + if err := models.UpdateUserCols(u, "must_change_password", "passwd", "rands", "salt"); err != nil { + ctx.ServerError("UpdateUser", err) + return + } + + ctx.Flash.Success(ctx.Tr("settings.change_password_success")) + + log.Trace("User updated password: %s", u.Name) + ctx.Redirect(setting.AppSubURL + "/") +}