Skip to content

Commit 344fc2d

Browse files
committed
enforce group-level password strength for users and shares
Signed-off-by: Nicola Murino <[email protected]>
1 parent ebd927a commit 344fc2d

File tree

3 files changed

+68
-4
lines changed

3 files changed

+68
-4
lines changed

internal/dataprovider/dataprovider.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2144,9 +2144,6 @@ func UpdateUserPassword(username, plainPwd, executor, ipAddress, role string) er
21442144
return err
21452145
}
21462146
userCopy := user.getACopy()
2147-
if err := userCopy.LoadAndApplyGroupSettings(); err != nil {
2148-
return err
2149-
}
21502147
userCopy.Password = plainPwd
21512148
if err := createUserPasswordHash(&userCopy); err != nil {
21522149
return err
@@ -3336,6 +3333,19 @@ func hashPlainPassword(plainPwd string) (string, error) {
33363333

33373334
func createUserPasswordHash(user *User) error {
33383335
if user.Password != "" && !user.IsPasswordHashed() {
3336+
for _, g := range user.Groups {
3337+
if g.Type == sdk.GroupTypePrimary {
3338+
group, err := GroupExists(g.Name)
3339+
if err != nil {
3340+
return errors.New("unable to load group password policies")
3341+
}
3342+
if minEntropy := group.UserSettings.Filters.PasswordStrength; minEntropy > 0 {
3343+
if err := passwordvalidator.Validate(user.Password, float64(minEntropy)); err != nil {
3344+
return util.NewI18nError(util.NewValidationError(err.Error()), util.I18nErrorPasswordComplexity)
3345+
}
3346+
}
3347+
}
3348+
}
33393349
if minEntropy := user.getMinPasswordEntropy(); minEntropy > 0 {
33403350
if err := passwordvalidator.Validate(user.Password, minEntropy); err != nil {
33413351
return util.NewI18nError(util.NewValidationError(err.Error()), util.I18nErrorPasswordComplexity)

internal/dataprovider/share.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ func (s *Share) HasRedactedPassword() bool {
146146

147147
func (s *Share) hashPassword() error {
148148
if s.Password != "" && !util.IsStringPrefixInSlice(s.Password, internalHashPwdPrefixes) {
149-
user, err := UserExists(s.Username, "")
149+
user, err := GetUserWithGroupSettings(s.Username, "")
150150
if err != nil {
151151
return util.NewGenericError(fmt.Sprintf("unable to validate user: %v", err))
152152
}

internal/httpd/httpd_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1842,6 +1842,19 @@ func TestGroupSettingsOverride(t *testing.T) {
18421842
assert.Contains(t, user.Filters.WebClient, sdk.WebClientInfoChangeDisabled)
18431843
assert.Contains(t, user.Filters.WebClient, sdk.WebClientMFADisabled)
18441844
}
1845+
// Attempt to create a user with a weak password and group1 as the primary group: this should fail
1846+
u = getTestUser()
1847+
u.Username = rand.Text()
1848+
u.Password = defaultPassword
1849+
u.Groups = []sdk.GroupMapping{
1850+
{
1851+
Name: group1.Name,
1852+
Type: sdk.GroupTypePrimary,
1853+
},
1854+
}
1855+
_, resp, err = httpdtest.AddUser(u, http.StatusBadRequest)
1856+
assert.NoError(t, err)
1857+
assert.Contains(t, string(resp), "insecure password")
18451858

18461859
err = os.RemoveAll(user.GetHomeDir())
18471860
assert.NoError(t, err)
@@ -15109,6 +15122,47 @@ func TestShareUsage(t *testing.T) {
1510915122
executeRequest(req)
1511015123
}
1511115124

15125+
func TestSharePasswordPolicy(t *testing.T) {
15126+
g := getTestGroup()
15127+
g.UserSettings.Filters.PasswordStrength = 70
15128+
group, _, err := httpdtest.AddGroup(g, http.StatusCreated)
15129+
assert.NoError(t, err)
15130+
15131+
u := getTestUser()
15132+
u.Groups = []sdk.GroupMapping{
15133+
{
15134+
Name: g.Name,
15135+
Type: sdk.GroupTypePrimary,
15136+
},
15137+
}
15138+
u.Password = rand.Text()
15139+
user, _, err := httpdtest.AddUser(u, http.StatusCreated)
15140+
assert.NoError(t, err)
15141+
15142+
webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, u.Password)
15143+
assert.NoError(t, err)
15144+
15145+
share := dataprovider.Share{
15146+
Name: util.GenerateUniqueID(),
15147+
Scope: dataprovider.ShareScopeRead,
15148+
Paths: []string{"/"},
15149+
Password: defaultPassword,
15150+
}
15151+
asJSON, err := json.Marshal(share)
15152+
assert.NoError(t, err)
15153+
req, err := http.NewRequest(http.MethodPost, userSharesPath, bytes.NewBuffer(asJSON))
15154+
assert.NoError(t, err)
15155+
setBearerForReq(req, webAPIToken)
15156+
rr := executeRequest(req)
15157+
checkResponseCode(t, http.StatusBadRequest, rr)
15158+
assert.Contains(t, rr.Body.String(), "insecure password")
15159+
15160+
_, err = httpdtest.RemoveUser(user, http.StatusOK)
15161+
assert.NoError(t, err)
15162+
_, err = httpdtest.RemoveGroup(group, http.StatusOK)
15163+
assert.NoError(t, err)
15164+
}
15165+
1511215166
func TestShareMaxExpiration(t *testing.T) {
1511315167
u := getTestUser()
1511415168
u.Filters.MaxSharesExpiration = 5

0 commit comments

Comments
 (0)