Skip to content

Commit

Permalink
feat: add max length password policy
Browse files Browse the repository at this point in the history
  • Loading branch information
mmeller-wikia committed Feb 26, 2024
1 parent a1bf427 commit 6a52949
Show file tree
Hide file tree
Showing 7 changed files with 33 additions and 1 deletion.
7 changes: 7 additions & 0 deletions .schemastore/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1524,6 +1524,13 @@
"default": 8,
"minimum": 6
},
"max_password_length": {
"title": "Maximum Password Length",
"description": "Defines the maximum length of the password.",
"type": "integer",
"default": 1024,
"minimum": 20
},
"identifier_similarity_check_enabled": {
"title": "Enable password-identifier similarity check",
"description": "If set to false the password validation does not check for similarity between the password and the user identifier.",
Expand Down
3 changes: 3 additions & 0 deletions driver/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ const (
ViperKeyPasswordHaveIBeenPwnedEnabled = "selfservice.methods.password.config.haveibeenpwned_enabled"
ViperKeyPasswordMaxBreaches = "selfservice.methods.password.config.max_breaches"
ViperKeyPasswordMinLength = "selfservice.methods.password.config.min_password_length"
ViperKeyPasswordMaxLength = "selfservice.methods.password.config.max_password_length"
ViperKeyPasswordIdentifierSimilarityCheckEnabled = "selfservice.methods.password.config.identifier_similarity_check_enabled"
ViperKeyIgnoreNetworkErrors = "selfservice.methods.password.config.ignore_network_errors"
ViperKeyTOTPIssuer = "selfservice.methods.totp.config.issuer"
Expand Down Expand Up @@ -249,6 +250,7 @@ type (
MaxBreaches uint `json:"max_breaches"`
IgnoreNetworkErrors bool `json:"ignore_network_errors"`
MinPasswordLength uint `json:"min_password_length"`
MaxPasswordLength uint `json:"max_password_length"`
IdentifierSimilarityCheckEnabled bool `json:"identifier_similarity_check_enabled"`
}
Schemas []Schema
Expand Down Expand Up @@ -1425,6 +1427,7 @@ func (p *Config) PasswordPolicyConfig(ctx context.Context) *PasswordPolicy {
MaxBreaches: uint(p.GetProvider(ctx).Int(ViperKeyPasswordMaxBreaches)),
IgnoreNetworkErrors: p.GetProvider(ctx).BoolF(ViperKeyIgnoreNetworkErrors, true),
MinPasswordLength: uint(p.GetProvider(ctx).IntF(ViperKeyPasswordMinLength, 8)),
MaxPasswordLength: uint(p.GetProvider(ctx).IntF(ViperKeyPasswordMaxLength, 20)),
IdentifierSimilarityCheckEnabled: p.GetProvider(ctx).BoolF(ViperKeyPasswordIdentifierSimilarityCheckEnabled, true),
}
}
Expand Down
2 changes: 1 addition & 1 deletion driver/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func TestViperProvider(t *testing.T) {
config string
enabled bool
}{
{id: "password", enabled: true, config: `{"haveibeenpwned_host":"api.pwnedpasswords.com","haveibeenpwned_enabled":true,"ignore_network_errors":true,"max_breaches":0,"min_password_length":8,"identifier_similarity_check_enabled":true}`},
{id: "password", enabled: true, config: `{"haveibeenpwned_host":"api.pwnedpasswords.com","haveibeenpwned_enabled":true,"ignore_network_errors":true,"max_breaches":0,"min_password_length":8,"max_password_length":1024,"identifier_similarity_check_enabled":true}`},
{id: "oidc", enabled: true, config: `{"providers":[{"client_id":"a","client_secret":"b","id":"github","provider":"github","mapper_url":"http://test.kratos.ory.sh/default-identity.schema.json"}]}`},
{id: "totp", enabled: true, config: `{"issuer":"issuer.ory.sh"}`},
} {
Expand Down
7 changes: 7 additions & 0 deletions embedx/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1524,6 +1524,13 @@
"default": 8,
"minimum": 6
},
"max_password_length": {
"title": "Maximum Password Length",
"description": "Defines the maximum length of the password.",
"type": "integer",
"default": 1024,
"minimum": 20
},
"identifier_similarity_check_enabled": {
"title": "Enable password-identifier similarity check",
"description": "If set to false the password validation does not check for similarity between the password and the user identifier.",
Expand Down
6 changes: 6 additions & 0 deletions selfservice/strategy/password/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ func (s *Strategy) Login(w http.ResponseWriter, r *http.Request, f *login.Flow,
return nil, s.handleLoginError(w, r, f, &p, err)
}

// Reduce possibility of DDoS attacks with long password
if len([]byte(p.Password)) > int(s.d.Config().PasswordPolicyConfig(r.Context()).MaxPasswordLength) {
time.Sleep(x.RandomDelay(s.d.Config().HasherArgon2(r.Context()).ExpectedDuration, s.d.Config().HasherArgon2(r.Context()).ExpectedDeviation))
return nil, s.handleLoginError(w, r, f, &p, errors.WithStack(schema.NewInvalidCredentialsError()))
}

i, c, err := s.d.PrivilegedIdentityPool().FindByCredentialsIdentifier(r.Context(), s.ID(), stringsx.Coalesce(p.Identifier, p.LegacyIdentifier))
if err != nil {
time.Sleep(x.RandomDelay(s.d.Config().HasherArgon2(r.Context()).ExpectedDuration, s.d.Config().HasherArgon2(r.Context()).ExpectedDeviation))
Expand Down
4 changes: 4 additions & 0 deletions selfservice/strategy/password/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ func (s *DefaultPasswordValidator) validate(ctx context.Context, identifier, pas
return text.NewErrorValidationPasswordMinLength(int(passwordPolicyConfig.MinPasswordLength), len(password))
}

if len(password) > int(passwordPolicyConfig.MaxPasswordLength) {
return errors.Errorf("password length cannot exceed %d characters", passwordPolicyConfig.MaxPasswordLength)
}

if passwordPolicyConfig.IdentifierSimilarityCheckEnabled && len(identifier) > 0 {
compIdentifier, compPassword := strings.ToLower(identifier), strings.ToLower(password)
dist := levenshtein.Distance(compIdentifier, compPassword)
Expand Down
5 changes: 5 additions & 0 deletions test/e2e/cypress/support/config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ export type IgnoreLookupNetworkErrors = boolean
* Defines the minimum length of the password.
*/
export type MinimumPasswordLength = number
/**
* Defines the maximum length of the password.
*/
export type MaximumPasswordLength = number
/**
* If set to false the password validation does not check for similarity between the password and the user identifier.
*/
Expand Down Expand Up @@ -875,6 +879,7 @@ export interface PasswordConfiguration {
max_breaches?: AllowPasswordBreaches
ignore_network_errors?: IgnoreLookupNetworkErrors
min_password_length?: MinimumPasswordLength
max_password_length?: MaximumPasswordLength
identifier_similarity_check_enabled?: EnablePasswordIdentifierSimilarityCheck
}
export interface TOTPConfiguration {
Expand Down

0 comments on commit 6a52949

Please sign in to comment.