mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-03-31 13:52:10 -04:00
Added an option to enable a password check against a Banned-Password List (#7315)
* Added an option to enable a password check against a Banned-Password-List * Update services/frontend/README.md Co-authored-by: Martin <github@diemattels.at> Co-authored-by: Edith Parzefall <edith_parzefall@gmx.de> --------- Co-authored-by: Roman Perekhod <rperekhod@owncloud.com> Co-authored-by: Martin <github@diemattels.at> Co-authored-by: Edith Parzefall <edith_parzefall@gmx.de>
This commit is contained in:
6
changelog/unreleased/add-passwod-banned-password-list.md
Normal file
6
changelog/unreleased/add-passwod-banned-password-list.md
Normal file
@@ -0,0 +1,6 @@
|
||||
Enhancement: Add the Banned Passwords List
|
||||
|
||||
Added an option to enable a password check against a banned passwords list OCIS-3809
|
||||
|
||||
https://github.com/cs3org/reva/pull/4197
|
||||
https://github.com/owncloud/ocis/pull/7314
|
||||
2
go.mod
2
go.mod
@@ -13,7 +13,7 @@ require (
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||
github.com/coreos/go-oidc/v3 v3.6.0
|
||||
github.com/cs3org/go-cs3apis v0.0.0-20230516150832-730ac860c71d
|
||||
github.com/cs3org/reva/v2 v2.16.1-0.20230915081009-843fe781fbf8
|
||||
github.com/cs3org/reva/v2 v2.16.1-0.20230921092447-6caa589a0ae8
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
|
||||
github.com/egirna/icap-client v0.1.1
|
||||
|
||||
4
go.sum
4
go.sum
@@ -1013,8 +1013,8 @@ github.com/crewjam/httperr v0.2.0 h1:b2BfXR8U3AlIHwNeFFvZ+BV1LFvKLlzMjzaTnZMybNo
|
||||
github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4=
|
||||
github.com/crewjam/saml v0.4.13 h1:TYHggH/hwP7eArqiXSJUvtOPNzQDyQ7vwmwEqlFWhMc=
|
||||
github.com/crewjam/saml v0.4.13/go.mod h1:igEejV+fihTIlHXYP8zOec3V5A8y3lws5bQBFsTm4gA=
|
||||
github.com/cs3org/reva/v2 v2.16.1-0.20230915081009-843fe781fbf8 h1:7aj/OEZ6NbpB3nSKRJUlp2l0AT0j5tGP0nynLZS8UpU=
|
||||
github.com/cs3org/reva/v2 v2.16.1-0.20230915081009-843fe781fbf8/go.mod h1:RvhuweTFqzezjUFU0SIdTXakrEx9vJlMvQ7znPXSP1g=
|
||||
github.com/cs3org/reva/v2 v2.16.1-0.20230921092447-6caa589a0ae8 h1:IEziHvFgy6EIGkGJb3lK/TQNCzBkd4oNe5YDBMcbS1c=
|
||||
github.com/cs3org/reva/v2 v2.16.1-0.20230921092447-6caa589a0ae8/go.mod h1:RvhuweTFqzezjUFU0SIdTXakrEx9vJlMvQ7znPXSP1g=
|
||||
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
|
||||
@@ -74,13 +74,17 @@ Generally, a password can contain any UTF-8 characters, however some characters
|
||||
|
||||
Note that a password can have a maximum length of **72 bytes**. Depending on the alphabet used, a character is encoded by 1 to 4 bytes, defining the maximum length of a password indirectly. While US-ASCII will only need one byte, Latin alphabets and also Greek or Cyrillic ones need two bytes. Three bytes are needed for characters in Chinese, Japanese and Korean etc.
|
||||
|
||||
- `FRONTEND_PASSWORD_POLICIES_MIN_CHARACTERS`
|
||||
The validation against the banned passwords list can be configured via a text file with words separated by new lines. If a user tries to set a password listed in the banned passwords list, the password can not be used (is invalid) even if the other mandatory criteria are passed. The admin can define the path of the banned passwords list file. If the file doesn't exist in a location, Infinite Scale tries to load a file from the `OCIS_CONFIG_DIR/FRONTEND_PASSWORD_POLICY_BANNED_PASSWORDS_LIST`. An option will be enabled when the file has been loaded successfully.
|
||||
|
||||
- `FRONTEND_PASSWORD_POLICY_MIN_CHARACTERS`
|
||||
Define the minimum password length.
|
||||
- `FRONTEND_PASSWORD_POLICIES_MIN_LOWERCASE_CHARACTERS`
|
||||
- `FRONTEND_PASSWORD_POLICY_MIN_LOWERCASE_CHARACTERS`
|
||||
Define the minimum number of uppercase letters.
|
||||
- `FRONTEND_PASSWORD_POLICIES_MIN_UPPERCASE_CHARACTERS`
|
||||
- `FRONTEND_PASSWORD_POLICY_MIN_UPPERCASE_CHARACTERS`
|
||||
Define the minimum number of lowercase letters.
|
||||
- `FRONTEND_PASSWORD_POLICIES_MIN_DIGITS`
|
||||
- `FRONTEND_PASSWORD_POLICY_MIN_DIGITS`
|
||||
Define the minimum number of digits.
|
||||
- `FRONTEND_PASSWORD_POLICIES_MIN_SPECIAL_CHARACTERS`
|
||||
- `FRONTEND_PASSWORD_POLICY_MIN_SPECIAL_CHARACTERS`
|
||||
Define the minimum number of special characters.
|
||||
- `FRONTEND_PASSWORD_POLICY_BANNED_PASSWORDS_LIST`
|
||||
Define the path to the banned password list file.
|
||||
|
||||
@@ -42,7 +42,7 @@ func Server(cfg *config.Config) *cli.Command {
|
||||
|
||||
defer cancel()
|
||||
|
||||
rCfg, err := revaconfig.FrontendConfigFromStruct(cfg)
|
||||
rCfg, err := revaconfig.FrontendConfigFromStruct(cfg, logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -176,9 +176,10 @@ type ServiceAccount struct {
|
||||
|
||||
// PasswordPolicy configures reva password policy
|
||||
type PasswordPolicy struct {
|
||||
MinCharacters int `yaml:"min_characters,omitempty" env:"FRONTEND_PASSWORD_POLICY_MIN_CHARACTERS" desc:"Define the minimum password length. Defaults to 0 if not set."`
|
||||
MinLowerCaseCharacters int `yaml:"min_lowercase_characters" env:"FRONTEND_PASSWORD_POLICY_MIN_LOWERCASE_CHARACTERS" desc:"Define the minimum number of uppercase letters. Defaults to 0 if not set."`
|
||||
MinUpperCaseCharacters int `yaml:"min_uppercase_characters" env:"FRONTEND_PASSWORD_POLICY_MIN_UPPERCASE_CHARACTERS" desc:"Define the minimum number of lowercase letters. Defaults to 0 if not set."`
|
||||
MinDigits int `yaml:"min_digits" env:"FRONTEND_PASSWORD_POLICY_MIN_DIGITS" desc:"Define the minimum number of digits. Defaults to 0 if not set."`
|
||||
MinSpecialCharacters int `yaml:"min_special_characters" env:"FRONTEND_PASSWORD_POLICY_MIN_SPECIAL_CHARACTERS" desc:"Define the minimum number of characters from the special characters list to be present. Defaults to 0 if not set."`
|
||||
MinCharacters int `yaml:"min_characters,omitempty" env:"FRONTEND_PASSWORD_POLICY_MIN_CHARACTERS" desc:"Define the minimum password length. Defaults to 0 if not set."`
|
||||
MinLowerCaseCharacters int `yaml:"min_lowercase_characters" env:"FRONTEND_PASSWORD_POLICY_MIN_LOWERCASE_CHARACTERS" desc:"Define the minimum number of uppercase letters. Defaults to 0 if not set."`
|
||||
MinUpperCaseCharacters int `yaml:"min_uppercase_characters" env:"FRONTEND_PASSWORD_POLICY_MIN_UPPERCASE_CHARACTERS" desc:"Define the minimum number of lowercase letters. Defaults to 0 if not set."`
|
||||
MinDigits int `yaml:"min_digits" env:"FRONTEND_PASSWORD_POLICY_MIN_DIGITS" desc:"Define the minimum number of digits. Defaults to 0 if not set."`
|
||||
MinSpecialCharacters int `yaml:"min_special_characters" env:"FRONTEND_PASSWORD_POLICY_MIN_SPECIAL_CHARACTERS" desc:"Define the minimum number of characters from the special characters list to be present. Defaults to 0 if not set."`
|
||||
BannedPasswordsList string `yaml:"banned_passwords_list" env:"FRONTEND_PASSWORD_POLICY_BANNED_PASSWORDS_LIST" desc:"Path to the 'banned passwords list' file. See the documentation for more details."`
|
||||
}
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
package revaconfig
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/config/defaults"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/log"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/version"
|
||||
"github.com/owncloud/ocis/v2/services/frontend/pkg/config"
|
||||
)
|
||||
|
||||
// FrontendConfigFromStruct will adapt an oCIS config struct into a reva mapstructure to start a reva service.
|
||||
func FrontendConfigFromStruct(cfg *config.Config) (map[string]interface{}, error) {
|
||||
func FrontendConfigFromStruct(cfg *config.Config, logger log.Logger) (map[string]interface{}, error) {
|
||||
webURL, err := url.Parse(cfg.PublicURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -19,6 +25,16 @@ func FrontendConfigFromStruct(cfg *config.Config) (map[string]interface{}, error
|
||||
webURL.Path = path.Join(webURL.Path, "external")
|
||||
webOpenInAppURL := webURL.String()
|
||||
|
||||
var bannedPasswordsList map[string]struct{}
|
||||
if cfg.PasswordPolicy.BannedPasswordsList != "" {
|
||||
bannedPasswordsList, err = readMultilineFile(cfg.PasswordPolicy.BannedPasswordsList)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to load the banned passwords from a file %s: %w", cfg.PasswordPolicy.BannedPasswordsList, err)
|
||||
logger.Err(err).Send()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
archivers := []map[string]interface{}{
|
||||
{
|
||||
"enabled": true,
|
||||
@@ -281,6 +297,7 @@ func FrontendConfigFromStruct(cfg *config.Config) (map[string]interface{}, error
|
||||
"min_uppercase_characters": cfg.PasswordPolicy.MinUpperCaseCharacters,
|
||||
"min_digits": cfg.PasswordPolicy.MinDigits,
|
||||
"min_special_characters": cfg.PasswordPolicy.MinSpecialCharacters,
|
||||
"banned_passwords_list": bannedPasswordsList,
|
||||
},
|
||||
"notifications": map[string]interface{}{
|
||||
"endpoints": []string{"list", "get", "delete"},
|
||||
@@ -301,3 +318,31 @@ func FrontendConfigFromStruct(cfg *config.Config) (map[string]interface{}, error
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func readMultilineFile(path string) (map[string]struct{}, error) {
|
||||
if !fileExists(path) {
|
||||
path = filepath.Join(defaults.BaseConfigPath(), path)
|
||||
}
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
scanner := bufio.NewScanner(file)
|
||||
data := make(map[string]struct{})
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if line != "" {
|
||||
data[line] = struct{}{}
|
||||
}
|
||||
}
|
||||
return data, err
|
||||
}
|
||||
|
||||
func fileExists(path string) bool {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return !info.IsDir()
|
||||
}
|
||||
|
||||
@@ -109,7 +109,14 @@ Feature: enforce password on public link
|
||||
| password | Pas1 |
|
||||
Then the HTTP status code should be "<http-code>"
|
||||
And the OCS status code should be "400"
|
||||
And the OCS status message should be "password validation failed"
|
||||
And the OCS status message should be:
|
||||
"""
|
||||
at least 13 characters are required
|
||||
at least 3 lowercase letters are required
|
||||
at least 2 uppercase letters are required
|
||||
at least 2 numbers are required
|
||||
at least 2 special characters are required !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
|
||||
"""
|
||||
Examples:
|
||||
| ocs-api-version | http-code |
|
||||
| 1 | 200 |
|
||||
@@ -168,11 +175,11 @@ Feature: enforce password on public link
|
||||
And the OCS status code should be "400"
|
||||
And the OCS status message should be:
|
||||
"""
|
||||
missing required password at least 13 characters are required
|
||||
at least 13 characters are required
|
||||
at least 3 lowercase letters are required
|
||||
at least 2 uppercase letters are required
|
||||
at least 1 numbers are required
|
||||
at least 2 special characters are required. !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
|
||||
at least 2 special characters are required !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
|
||||
"""
|
||||
Examples:
|
||||
| ocs-api-version | http-code |
|
||||
@@ -231,7 +238,7 @@ Feature: enforce password on public link
|
||||
And the OCS status message should be "<message>"
|
||||
Examples:
|
||||
| config | config-value | password | message |
|
||||
| FRONTEND_PASSWORD_POLICY_MIN_CHARACTERS | 5 | 1234 | missing required password at least 5 characters are required |
|
||||
| FRONTEND_PASSWORD_POLICY_MIN_LOWERCASE_CHARACTERS | 3 | TesT | missing required password at least 3 lowercase letters are required |
|
||||
| FRONTEND_PASSWORD_POLICY_MIN_UPPERCASE_CHARACTERS | 3 | TesT | missing required password at least 3 uppercase letters are required |
|
||||
| FRONTEND_PASSWORD_POLICY_MIN_DIGITS | 2 | test1 | missing required password at least 2 numbers are required |
|
||||
| FRONTEND_PASSWORD_POLICY_MIN_CHARACTERS | 5 | 1234 | at least 5 characters are required |
|
||||
| FRONTEND_PASSWORD_POLICY_MIN_LOWERCASE_CHARACTERS | 3 | TesT | at least 3 lowercase letters are required |
|
||||
| FRONTEND_PASSWORD_POLICY_MIN_UPPERCASE_CHARACTERS | 3 | TesT | at least 3 uppercase letters are required |
|
||||
| FRONTEND_PASSWORD_POLICY_MIN_DIGITS | 2 | test1 | at least 2 numbers are required |
|
||||
|
||||
49
vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/put.go
generated
vendored
49
vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/put.go
generated
vendored
@@ -172,32 +172,35 @@ func (s *svc) handlePut(ctx context.Context, w http.ResponseWriter, r *http.Requ
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if tfRes.Status.Code != rpc.Code_CODE_OK {
|
||||
if tfRes.Status.Code == rpc.Code_CODE_OK {
|
||||
sRes, err := client.Stat(ctx, &provider.StatRequest{
|
||||
Ref: ref,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error sending grpc touch file request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if sRes.Status.Code != rpc.Code_CODE_OK {
|
||||
log.Error().Interface("status", sRes.Status).Msg("error touching file")
|
||||
errors.HandleErrorStatus(&log, w, sRes.Status)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set(net.HeaderETag, sRes.Info.Etag)
|
||||
w.Header().Set(net.HeaderOCETag, sRes.Info.Etag)
|
||||
w.Header().Set(net.HeaderOCFileID, storagespace.FormatResourceID(*sRes.Info.Id))
|
||||
w.Header().Set(net.HeaderLastModified, net.RFC1123Z(sRes.Info.Mtime))
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
return
|
||||
}
|
||||
|
||||
if tfRes.Status.Code != rpc.Code_CODE_ALREADY_EXISTS {
|
||||
log.Error().Interface("status", tfRes.Status).Msg("error touching file")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
errors.HandleErrorStatus(&log, w, tfRes.Status)
|
||||
return
|
||||
}
|
||||
sRes, err := client.Stat(ctx, &provider.StatRequest{
|
||||
Ref: ref,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error sending grpc touch file request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if sRes.Status.Code != rpc.Code_CODE_OK {
|
||||
log.Error().Interface("status", sRes.Status).Msg("error touching file")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set(net.HeaderETag, sRes.Info.Etag)
|
||||
w.Header().Set(net.HeaderOCETag, sRes.Info.Etag)
|
||||
w.Header().Set(net.HeaderOCFileID, storagespace.FormatResourceID(*sRes.Info.Id))
|
||||
w.Header().Set(net.HeaderLastModified, net.RFC1123Z(sRes.Info.Mtime))
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
return
|
||||
}
|
||||
|
||||
utils.AppendPlainToOpaque(opaque, net.HeaderUploadLength, strconv.FormatInt(length, 10))
|
||||
|
||||
@@ -88,12 +88,13 @@ type CapabilitiesGraph struct {
|
||||
|
||||
// CapabilitiesPasswordPolicy hold the password policy capabilities
|
||||
type CapabilitiesPasswordPolicy struct {
|
||||
MinCharacters int `json:"min_characters" xml:"min_characters" mapstructure:"min_characters"`
|
||||
MaxCharacters int `json:"max_characters" xml:"max_characters" mapstructure:"max_characters"`
|
||||
MinLowerCaseCharacters int `json:"min_lowercase_characters" xml:"min_lowercase_characters" mapstructure:"min_lowercase_characters"`
|
||||
MinUpperCaseCharacters int `json:"min_uppercase_characters" xml:"min_uppercase_characters" mapstructure:"min_uppercase_characters"`
|
||||
MinDigits int `json:"min_digits" xml:"min_digits" mapstructure:"min_digits"`
|
||||
MinSpecialCharacters int `json:"min_special_characters" xml:"min_special_characters" mapstructure:"min_special_characters"`
|
||||
MinCharacters int `json:"min_characters" xml:"min_characters" mapstructure:"min_characters"`
|
||||
MaxCharacters int `json:"max_characters" xml:"max_characters" mapstructure:"max_characters"`
|
||||
MinLowerCaseCharacters int `json:"min_lowercase_characters" xml:"min_lowercase_characters" mapstructure:"min_lowercase_characters"`
|
||||
MinUpperCaseCharacters int `json:"min_uppercase_characters" xml:"min_uppercase_characters" mapstructure:"min_uppercase_characters"`
|
||||
MinDigits int `json:"min_digits" xml:"min_digits" mapstructure:"min_digits"`
|
||||
MinSpecialCharacters int `json:"min_special_characters" xml:"min_special_characters" mapstructure:"min_special_characters"`
|
||||
BannedPasswordsList map[string]struct{} `json:"-" xml:"-" mapstructure:"banned_passwords_list"`
|
||||
}
|
||||
|
||||
// CapabilitiesGraphUsers holds the graph user capabilities
|
||||
|
||||
@@ -153,7 +153,7 @@ func (h *Handler) createPublicLinkShare(w http.ResponseWriter, r *http.Request,
|
||||
if err := h.passwordValidator.Validate(password); err != nil {
|
||||
return nil, &ocsError{
|
||||
Code: response.MetaBadRequest.StatusCode,
|
||||
Message: "password validation failed",
|
||||
Message: err.Error(),
|
||||
Error: fmt.Errorf("password validation failed: %w", err),
|
||||
}
|
||||
}
|
||||
@@ -479,7 +479,7 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar
|
||||
// skip validation if the clear password scenario
|
||||
if len(newPassword[0]) > 0 {
|
||||
if err := h.passwordValidator.Validate(newPassword[0]); err != nil {
|
||||
response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, fmt.Errorf("missing required password %w", err).Error(), err)
|
||||
response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, err.Error(), err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1592,7 +1592,7 @@ func publicPwdEnforced(c *config.Config) passwordEnforced {
|
||||
|
||||
func passwordPolicies(c *config.Config) password.Validator {
|
||||
if c.Capabilities.Capabilities == nil || c.Capabilities.Capabilities.PasswordPolicy == nil {
|
||||
return password.NewPasswordPolicy(0, 0, 0, 0, 0)
|
||||
return password.NewPasswordPolicy(0, 0, 0, 0, 0, nil)
|
||||
}
|
||||
return password.NewPasswordPolicy(
|
||||
c.Capabilities.Capabilities.PasswordPolicy.MinCharacters,
|
||||
@@ -1600,6 +1600,7 @@ func passwordPolicies(c *config.Config) password.Validator {
|
||||
c.Capabilities.Capabilities.PasswordPolicy.MinUpperCaseCharacters,
|
||||
c.Capabilities.Capabilities.PasswordPolicy.MinDigits,
|
||||
c.Capabilities.Capabilities.PasswordPolicy.MinSpecialCharacters,
|
||||
c.Capabilities.Capabilities.PasswordPolicy.BannedPasswordsList,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
22
vendor/github.com/cs3org/reva/v2/pkg/password/password_policies.go
generated
vendored
22
vendor/github.com/cs3org/reva/v2/pkg/password/password_policies.go
generated
vendored
@@ -23,18 +23,20 @@ type Policies struct {
|
||||
minUpperCaseCharacters int
|
||||
minDigits int
|
||||
minSpecialCharacters int
|
||||
bannedPasswordsList map[string]struct{}
|
||||
digitsRegexp *regexp.Regexp
|
||||
specialCharactersRegexp *regexp.Regexp
|
||||
}
|
||||
|
||||
// NewPasswordPolicy returns a new NewPasswordPolicy instance
|
||||
func NewPasswordPolicy(minCharacters, minLowerCaseCharacters, minUpperCaseCharacters, minDigits, minSpecialCharacters int) Validator {
|
||||
func NewPasswordPolicy(minCharacters, minLowerCaseCharacters, minUpperCaseCharacters, minDigits, minSpecialCharacters int, bannedPasswordsList map[string]struct{}) Validator {
|
||||
p := &Policies{
|
||||
minCharacters: minCharacters,
|
||||
minLowerCaseCharacters: minLowerCaseCharacters,
|
||||
minUpperCaseCharacters: minUpperCaseCharacters,
|
||||
minDigits: minDigits,
|
||||
minSpecialCharacters: minSpecialCharacters,
|
||||
bannedPasswordsList: bannedPasswordsList,
|
||||
}
|
||||
|
||||
p.digitsRegexp = regexp.MustCompile("[0-9]")
|
||||
@@ -48,7 +50,11 @@ func (s Policies) Validate(str string) error {
|
||||
if !utf8.ValidString(str) {
|
||||
return fmt.Errorf("the password contains invalid characters")
|
||||
}
|
||||
err := s.validateCharacters(str)
|
||||
err := s.validateBannedList(str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.validateCharacters(str)
|
||||
if err != nil {
|
||||
allErr = errors.Join(allErr, err)
|
||||
}
|
||||
@@ -74,6 +80,16 @@ func (s Policies) Validate(str string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s Policies) validateBannedList(str string) error {
|
||||
if len(s.bannedPasswordsList) == 0 {
|
||||
return nil
|
||||
}
|
||||
if _, ok := s.bannedPasswordsList[str]; ok {
|
||||
return fmt.Errorf("unfortunately, your password is commonly used. please pick a harder-to-guess password for your safety")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s Policies) validateCharacters(str string) error {
|
||||
if s.count(str) < s.minCharacters {
|
||||
return fmt.Errorf("at least %d characters are required", s.minCharacters)
|
||||
@@ -104,7 +120,7 @@ func (s Policies) validateDigits(str string) error {
|
||||
|
||||
func (s Policies) validateSpecialCharacters(str string) error {
|
||||
if s.countSpecialCharacters(str) < s.minSpecialCharacters {
|
||||
return fmt.Errorf("at least %d special characters are required. %s", s.minSpecialCharacters, _defaultSpecialCharacters)
|
||||
return fmt.Errorf("at least %d special characters are required %s", s.minSpecialCharacters, _defaultSpecialCharacters)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@@ -356,7 +356,7 @@ github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1
|
||||
github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1
|
||||
github.com/cs3org/go-cs3apis/cs3/tx/v1beta1
|
||||
github.com/cs3org/go-cs3apis/cs3/types/v1beta1
|
||||
# github.com/cs3org/reva/v2 v2.16.1-0.20230915081009-843fe781fbf8
|
||||
# github.com/cs3org/reva/v2 v2.16.1-0.20230921092447-6caa589a0ae8
|
||||
## explicit; go 1.20
|
||||
github.com/cs3org/reva/v2/cmd/revad/internal/grace
|
||||
github.com/cs3org/reva/v2/cmd/revad/runtime
|
||||
|
||||
Reference in New Issue
Block a user