Enable setting password change requirements in user templates

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino
2025-07-17 19:34:01 +02:00
parent fe78974b47
commit c2835bc19d
3 changed files with 49 additions and 12 deletions

View File

@@ -22389,8 +22389,30 @@ func TestUserSaveFromTemplateMock(t *testing.T) {
u1, _, err := httpdtest.GetUserByUsername(user1, http.StatusOK) u1, _, err := httpdtest.GetUserByUsername(user1, http.StatusOK)
assert.NoError(t, err) assert.NoError(t, err)
assert.False(t, u1.Filters.RequirePasswordChange)
u2, _, err := httpdtest.GetUserByUsername(user2, http.StatusOK) u2, _, err := httpdtest.GetUserByUsername(user2, http.StatusOK)
assert.NoError(t, err) assert.NoError(t, err)
assert.False(t, u2.Filters.RequirePasswordChange)
_, err = httpdtest.RemoveUser(u1, http.StatusOK)
assert.NoError(t, err)
_, err = httpdtest.RemoveUser(u2, http.StatusOK)
assert.NoError(t, err)
form.Add("tpl_require_password_change", "checked")
b, contentType, _ = getMultipartFormData(form, "", "")
req, _ = http.NewRequest(http.MethodPost, webTemplateUser, &b)
setJWTCookieForReq(req, token)
req.Header.Set("Content-Type", contentType)
rr = executeRequest(req)
checkResponseCode(t, http.StatusSeeOther, rr)
u1, _, err = httpdtest.GetUserByUsername(user1, http.StatusOK)
assert.NoError(t, err)
assert.True(t, u1.Filters.RequirePasswordChange)
u2, _, err = httpdtest.GetUserByUsername(user2, http.StatusOK)
assert.NoError(t, err)
assert.True(t, u2.Filters.RequirePasswordChange)
_, err = httpdtest.RemoveUser(u1, http.StatusOK) _, err = httpdtest.RemoveUser(u1, http.StatusOK)
assert.NoError(t, err) assert.NoError(t, err)

View File

@@ -348,9 +348,10 @@ type messagePage struct {
} }
type userTemplateFields struct { type userTemplateFields struct {
Username string Username string
Password string Password string
PublicKeys []string PublicKeys []string
RequirePwdChange bool
} }
func loadAdminTemplates(templatesPath string) { func loadAdminTemplates(templatesPath string) {
@@ -1225,9 +1226,10 @@ func getUsersForTemplate(r *http.Request) []userTemplateFields {
users[username] = true users[username] = true
res = append(res, userTemplateFields{ res = append(res, userTemplateFields{
Username: username, Username: username,
Password: password, Password: password,
PublicKeys: []string{publicKey}, PublicKeys: []string{publicKey},
RequirePwdChange: r.Form.Get("tpl_require_password_change") != "",
}) })
} }
@@ -1910,6 +1912,7 @@ func getUserFromTemplate(user dataprovider.User, template userTemplateFields) da
user.Username = template.Username user.Username = template.Username
user.Password = template.Password user.Password = template.Password
user.PublicKeys = template.PublicKeys user.PublicKeys = template.PublicKeys
user.Filters.RequirePasswordChange = template.RequirePwdChange
replacements := make(map[string]string) replacements := make(map[string]string)
replacements["%username%"] = user.Username replacements["%username%"] = user.Username
if user.Password != "" && !user.IsPasswordHashed() { if user.Password != "" && !user.IsPasswordHashed() {
@@ -3461,9 +3464,10 @@ func (s *httpdServer) handleWebAddUserPost(w http.ResponseWriter, r *http.Reques
return return
} }
user = getUserFromTemplate(user, userTemplateFields{ user = getUserFromTemplate(user, userTemplateFields{
Username: user.Username, Username: user.Username,
Password: user.Password, Password: user.Password,
PublicKeys: user.PublicKeys, PublicKeys: user.PublicKeys,
RequirePwdChange: user.Filters.RequirePasswordChange,
}) })
if claims.Role != "" { if claims.Role != "" {
user.Role = claims.Role user.Role = claims.Role
@@ -3518,9 +3522,10 @@ func (s *httpdServer) handleWebUpdateUserPost(w http.ResponseWriter, r *http.Req
updateEncryptedSecrets(&updatedUser.FsConfig, &user.FsConfig) updateEncryptedSecrets(&updatedUser.FsConfig, &user.FsConfig)
updatedUser = getUserFromTemplate(updatedUser, userTemplateFields{ updatedUser = getUserFromTemplate(updatedUser, userTemplateFields{
Username: updatedUser.Username, Username: updatedUser.Username,
Password: updatedUser.Password, Password: updatedUser.Password,
PublicKeys: updatedUser.PublicKeys, PublicKeys: updatedUser.PublicKeys,
RequirePwdChange: updatedUser.Filters.RequirePasswordChange,
}) })
if claims.Role != "" { if claims.Role != "" {
updatedUser.Role = claims.Role updatedUser.Role = claims.Role

View File

@@ -91,6 +91,16 @@ explicit grant from the SFTPGo Team (support@sftpgo.com).
<span data-i18n="general.add">Add</span> <span data-i18n="general.add">Add</span>
</a> </a>
</div> </div>
<div class="form-group row align-items-center mt-10">
<label data-i18n="user.require_pwd_change" class="col-md-3 col-form-label" for="idTmplRequirePasswordChange">Require password change</label>
<div class="col-md-9">
<div class="form-check form-switch form-check-custom form-check-solid">
<input class="form-check-input" type="checkbox" id="idTmplRequirePasswordChange" name="tpl_require_password_change"/>
</div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>