Skip to content

Commit

Permalink
Implement support for base password constraints
Browse files Browse the repository at this point in the history
  • Loading branch information
tjerman committed Nov 22, 2021
1 parent edbbf2f commit 420b5ee
Show file tree
Hide file tree
Showing 21 changed files with 98 additions and 30 deletions.
7 changes: 7 additions & 0 deletions app/boot_levels.go
Expand Up @@ -491,13 +491,15 @@ func (app *CortezaApp) Activate(ctx context.Context) (err error) {

updateFederationSettings(app.Opt.Federation, sysService.CurrentSettings)
updateAuthSettings(app.AuthService, sysService.CurrentSettings)
updatePasswdSettings(app.Opt.Auth, sysService.CurrentSettings)
sysService.DefaultSettings.Register("auth.", func(ctx context.Context, current interface{}, set types.SettingValueSet) {
appSettings, is := current.(*types.AppSettings)
if !is {
return
}

updateAuthSettings(app.AuthService, appSettings)
updatePasswdSettings(app.Opt.Auth, sysService.CurrentSettings)
})

updateLocaleSettings(app.Opt.Locale)
Expand Down Expand Up @@ -601,6 +603,11 @@ func updateFederationSettings(opt options.FederationOpt, current *types.AppSetti
current.Federation.Enabled = opt.Enabled
}

// Checks if password security is enabled in the options
func updatePasswdSettings(opt options.AuthOpt, current *types.AppSettings) {
current.Auth.Internal.PasswordConstraints.PasswordSecurity = opt.PasswordSecurity
}

// Sanitizes application (current) settings with languages from options
//
// It updates resource-translations.languages slice
Expand Down
2 changes: 1 addition & 1 deletion auth/handlers/handle_change-password_test.go
Expand Up @@ -73,7 +73,7 @@ func Test_changePasswordProc(t *testing.T) {
},
{
name: "provided password is not secure",
payload: map[string]string{"error": "provided password is not secure; use longer password with more non-alphanumeric character"},
payload: map[string]string{"error": "provided password is not secure; use longer password with more special characters"},
link: GetLinks().ChangePassword,
fn: func(_ *settings.Settings) {
authService = &authServiceMocked{
Expand Down
2 changes: 1 addition & 1 deletion auth/handlers/handle_signup_test.go
Expand Up @@ -147,7 +147,7 @@ func Test_signupProc(t *testing.T) {
err: "",
alerts: []request.Alert(nil),
link: GetLinks().Signup,
payload: map[string]string{"email": "", "error": "provided password is not secure; use longer password with more non-alphanumeric character", "handle": "", "name": ""},
payload: map[string]string{"email": "", "error": "provided password is not secure; use longer password with more special characters", "handle": "", "name": ""},
fn: func(_ *settings.Settings) {
authService = &authServiceMocked{
internalSignUp: func(c context.Context, user *types.User, s string) (u *types.User, err error) {
Expand Down
2 changes: 2 additions & 0 deletions pkg/options/auth.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions pkg/options/auth.yaml
Expand Up @@ -10,6 +10,17 @@ props:
description: |-
Enable extra logging for authentication flows
- name: passwordSecurity
type: bool
default: true
description: |-
Password security allows you to disable constraints to which passwords must conform to.
[CAUTION]
====
Password security should not be disabled on production environments as it is insecure.
====
- name: secret
env: AUTH_JWT_SECRET
default: getSecretFromEnv("jwt secret")
Expand Down
34 changes: 33 additions & 1 deletion system/service/auth.go
Expand Up @@ -3,6 +3,7 @@ package service
import (
"context"
"fmt"
"math"
rand2 "math/rand"
"regexp"
"strconv"
Expand Down Expand Up @@ -59,6 +60,9 @@ const (
credentialsTypeMFAEmailOTP = "mfa-email-otp"

credentialsTokenLength = 32

passwordMinLength = 8
passwordMaxLength = 256
)

var (
Expand Down Expand Up @@ -622,10 +626,38 @@ func (svc auth) hashPassword(password string) (hash []byte, err error) {
}

func (svc auth) CheckPasswordStrength(password string) bool {
if len(password) <= 4 {
pwdL := len(password)

// Ignore defined password constraints
if !svc.settings.Auth.Internal.PasswordConstraints.PasswordSecurity {
return true
}

// Check the password length
minL := math.Max(float64(passwordMinLength), float64(svc.settings.Auth.Internal.PasswordConstraints.MinLength))
if pwdL < int(minL) || pwdL > passwordMaxLength {
return false
}

// Check special constraints
// - numeric characters
count := svc.settings.Auth.Internal.PasswordConstraints.MinNumCount
if count > 0 {
rr := regexp.MustCompile("[0-9]")
if uint(len(rr.FindAllStringIndex(password, -1))) < count {
return false
}
}

// - special characters
count = svc.settings.Auth.Internal.PasswordConstraints.MinSpecialCount
if count > 0 {
rr := regexp.MustCompile("[^0-9a-zA-Z]")
if uint(len(rr.FindAllStringIndex(password, -1))) < count {
return false
}
}

return true
}

Expand Down
7 changes: 4 additions & 3 deletions system/service/auth_actions.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion system/service/auth_actions.yaml
Expand Up @@ -143,7 +143,7 @@ errors:
message: "password create is disabled"

- error: passwordNotSecure
message: "provided password is not secure; use longer password with more non-alphanumeric character"
message: "provided password is not secure; use longer password with more special characters"

- error: externalDisabledByConfig
message: "external authentication (using external authentication provider) is disabled"
Expand Down
7 changes: 4 additions & 3 deletions system/service/user_actions.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion system/service/user_actions.yaml
Expand Up @@ -145,7 +145,7 @@ errors:
severity: warning

- error: passwordNotSecure
message: "provided password is not secure; use longer password with more non-alphanumeric character"
message: "provided password is not secure; use longer password with more special characters"

- error: maxUserLimitReached
message: "you have reached your user limit, contact your Corteza administrator"
Expand Down
32 changes: 23 additions & 9 deletions system/types/app_settings.go
Expand Up @@ -41,18 +41,18 @@ type (
Auth struct {
Internal struct {
// Is internal authentication (username + password) enabled
Enabled bool
Enabled bool `json:"-"`

Signup struct {
// Can users register
Enabled bool

// Users must confirm their emails when signing-up
EmailConfirmationRequired bool `kv:"email-confirmation-required"`
}
} `json:"-"`

// Can users reset their passwords
PasswordReset struct{ Enabled bool } `kv:"password-reset"`
PasswordReset struct{ Enabled bool } `json:"-" kv:"password-reset"`

// PasswordCreate setting for create password for user via generated link with token
// If user has no password then link redirects to create password page
Expand All @@ -61,14 +61,28 @@ type (
PasswordCreate struct {
Enabled bool
Expires uint
} `kv:"password-create"`
} `json:"-" kv:"password-create"`

// Splits credentials check into 2 parts
// If user has password credentials it offers him to enter the password
// Otherwise we offer the user to choose among the enabled external providers
// If only one ext. provider is enabled, user is automatically redirected there
SplitCredentialsCheck bool `kv:"split-credentials-check"`
}
SplitCredentialsCheck bool `json:"-" kv:"split-credentials-check"`

PasswordConstraints struct {
// Should the environment not enforce the constraints
PasswordSecurity bool `kv:"-" json:"passwordSecurity"`

// The min password length
MinLength uint `kv:"min-length"`

// The min number of numeric characters
MinNumCount uint `kv:"min-num-count"`

// The min number of special characters
MinSpecialCount uint `kv:"min-special-count"`
} `kv:"password-constraints" json:"passwordConstraints"`
} `json:"internal"`

External struct {
// Is external authentication
Expand Down Expand Up @@ -100,7 +114,7 @@ type (

// all external providers we know
Providers ExternalAuthProviderSet
}
} `json:"-"`

MultiFactor struct {
EmailOTP struct {
Expand Down Expand Up @@ -129,13 +143,13 @@ type (
// TOTP issuer, defaults to "Corteza"
Issuer string
} `kv:"totp"`
} `kv:"multi-factor"`
} `json:"-" kv:"multi-factor"`

Mail struct {
FromAddress string `kv:"from-address"`
FromName string `kv:"from-name"`
} `json:"-"`
} `json:"-"`
} `json:"auth"`

Compose struct {
// UI related settings
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 420b5ee

Please sign in to comment.