From 420b5ee19535da37fb62cb61f415d539242fb548 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=C5=BE=20Jerman?= Date: Sat, 20 Nov 2021 14:50:35 +0100 Subject: [PATCH] Implement support for base password constraints --- app/boot_levels.go | 7 ++++ auth/handlers/handle_change-password_test.go | 2 +- auth/handlers/handle_signup_test.go | 2 +- pkg/options/auth.gen.go | 2 ++ pkg/options/auth.yaml | 11 ++++++ system/service/auth.go | 34 ++++++++++++++++++- system/service/auth_actions.gen.go | 7 ++-- system/service/auth_actions.yaml | 2 +- system/service/user_actions.gen.go | 7 ++-- system/service/user_actions.yaml | 2 +- system/types/app_settings.go | 32 ++++++++++++----- .../src/en/corteza-server/system/auth.yaml | 2 +- .../src/en/corteza-server/system/user.yaml | 2 +- .../src/fr/corteza-server/system/auth.yaml | 2 +- .../src/fr/corteza-server/system/user.yaml | 2 +- .../src/ro/corteza-server/system/auth.yaml | 2 +- .../src/ro/corteza-server/system/user.yaml | 2 +- .../src/sl/corteza-server/system/auth.yaml | 2 +- .../src/sl/corteza-server/system/user.yaml | 2 +- .../src/uk/corteza-server/system/auth.yaml | 2 +- .../src/uk/corteza-server/system/user.yaml | 2 +- 21 files changed, 98 insertions(+), 30 deletions(-) diff --git a/app/boot_levels.go b/app/boot_levels.go index c5f440e3c1..5a0a358246 100644 --- a/app/boot_levels.go +++ b/app/boot_levels.go @@ -491,6 +491,7 @@ 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 { @@ -498,6 +499,7 @@ func (app *CortezaApp) Activate(ctx context.Context) (err error) { } updateAuthSettings(app.AuthService, appSettings) + updatePasswdSettings(app.Opt.Auth, sysService.CurrentSettings) }) updateLocaleSettings(app.Opt.Locale) @@ -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 diff --git a/auth/handlers/handle_change-password_test.go b/auth/handlers/handle_change-password_test.go index 996b41fac5..6cd097736b 100644 --- a/auth/handlers/handle_change-password_test.go +++ b/auth/handlers/handle_change-password_test.go @@ -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{ diff --git a/auth/handlers/handle_signup_test.go b/auth/handlers/handle_signup_test.go index 82e33f49e8..8f88b23536 100644 --- a/auth/handlers/handle_signup_test.go +++ b/auth/handlers/handle_signup_test.go @@ -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) { diff --git a/pkg/options/auth.gen.go b/pkg/options/auth.gen.go index 515746709c..a30d7edb2b 100644 --- a/pkg/options/auth.gen.go +++ b/pkg/options/auth.gen.go @@ -15,6 +15,7 @@ import ( type ( AuthOpt struct { LogEnabled bool `env:"AUTH_LOG_ENABLED"` + PasswordSecurity bool `env:"AUTH_PASSWORD_SECURITY"` Secret string `env:"AUTH_JWT_SECRET"` AccessTokenLifetime time.Duration `env:"AUTH_OAUTH2_ACCESS_TOKEN_LIFETIME"` RefreshTokenLifetime time.Duration `env:"AUTH_OAUTH2_REFRESH_TOKEN_LIFETIME"` @@ -44,6 +45,7 @@ type ( // Auth initializes and returns a AuthOpt with default values func Auth() (o *AuthOpt) { o = &AuthOpt{ + PasswordSecurity: true, Secret: getSecretFromEnv("jwt secret"), AccessTokenLifetime: time.Hour * 2, RefreshTokenLifetime: time.Hour * 24 * 3, diff --git a/pkg/options/auth.yaml b/pkg/options/auth.yaml index 875845baee..f812c3fa7b 100644 --- a/pkg/options/auth.yaml +++ b/pkg/options/auth.yaml @@ -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") diff --git a/system/service/auth.go b/system/service/auth.go index 247c7cbc84..070f661767 100644 --- a/system/service/auth.go +++ b/system/service/auth.go @@ -3,6 +3,7 @@ package service import ( "context" "fmt" + "math" rand2 "math/rand" "regexp" "strconv" @@ -59,6 +60,9 @@ const ( credentialsTypeMFAEmailOTP = "mfa-email-otp" credentialsTokenLength = 32 + + passwordMinLength = 8 + passwordMaxLength = 256 ) var ( @@ -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 } diff --git a/system/service/auth_actions.gen.go b/system/service/auth_actions.gen.go index e9c5445e0a..9d523f0560 100644 --- a/system/service/auth_actions.gen.go +++ b/system/service/auth_actions.gen.go @@ -11,12 +11,13 @@ package service import ( "context" "fmt" + "strings" + "time" + "github.com/cortezaproject/corteza-server/pkg/actionlog" "github.com/cortezaproject/corteza-server/pkg/errors" "github.com/cortezaproject/corteza-server/pkg/locale" "github.com/cortezaproject/corteza-server/system/types" - "strings" - "time" ) type ( @@ -1248,7 +1249,7 @@ func AuthErrPasswordNotSecure(mm ...*authActionProps) *errors.Error { var e = errors.New( errors.KindInternal, - p.Format("provided password is not secure; use longer password with more non-alphanumeric character", nil), + p.Format("provided password is not secure; use longer password with more special characters", nil), errors.Meta("type", "passwordNotSecure"), errors.Meta("resource", "system:auth"), diff --git a/system/service/auth_actions.yaml b/system/service/auth_actions.yaml index 0796eb9637..991e75fe69 100644 --- a/system/service/auth_actions.yaml +++ b/system/service/auth_actions.yaml @@ -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" diff --git a/system/service/user_actions.gen.go b/system/service/user_actions.gen.go index 150f6aacf1..13c11ef4b9 100644 --- a/system/service/user_actions.gen.go +++ b/system/service/user_actions.gen.go @@ -11,12 +11,13 @@ package service import ( "context" "fmt" + "strings" + "time" + "github.com/cortezaproject/corteza-server/pkg/actionlog" "github.com/cortezaproject/corteza-server/pkg/errors" "github.com/cortezaproject/corteza-server/pkg/locale" "github.com/cortezaproject/corteza-server/system/types" - "strings" - "time" ) type ( @@ -1261,7 +1262,7 @@ func UserErrPasswordNotSecure(mm ...*userActionProps) *errors.Error { var e = errors.New( errors.KindInternal, - p.Format("provided password is not secure; use longer password with more non-alphanumeric character", nil), + p.Format("provided password is not secure; use longer password with more special characters", nil), errors.Meta("type", "passwordNotSecure"), errors.Meta("resource", "system:user"), diff --git a/system/service/user_actions.yaml b/system/service/user_actions.yaml index 5877a88daf..3ac45f3c09 100644 --- a/system/service/user_actions.yaml +++ b/system/service/user_actions.yaml @@ -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" diff --git a/system/types/app_settings.go b/system/types/app_settings.go index 9ca8b8dad3..e0c74d06b1 100644 --- a/system/types/app_settings.go +++ b/system/types/app_settings.go @@ -41,7 +41,7 @@ type ( Auth struct { Internal struct { // Is internal authentication (username + password) enabled - Enabled bool + Enabled bool `json:"-"` Signup struct { // Can users register @@ -49,10 +49,10 @@ type ( // 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 @@ -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 @@ -100,7 +114,7 @@ type ( // all external providers we know Providers ExternalAuthProviderSet - } + } `json:"-"` MultiFactor struct { EmailOTP struct { @@ -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 diff --git a/vendor/github.com/cortezaproject/corteza-locale/src/en/corteza-server/system/auth.yaml b/vendor/github.com/cortezaproject/corteza-locale/src/en/corteza-server/system/auth.yaml index 62a69fdf09..0cbd209bea 100644 --- a/vendor/github.com/cortezaproject/corteza-locale/src/en/corteza-server/system/auth.yaml +++ b/vendor/github.com/cortezaproject/corteza-locale/src/en/corteza-server/system/auth.yaml @@ -19,7 +19,7 @@ errors: notAllowedToRemoveTOTP: not allowed to remove TOTP passwodResetFailedOldPasswordCheckFailed: failed to change password, old password does not match passwordChangeFailedForUnknownUser: failed to change password for the unknown user - passwordNotSecure: provided password is not secure; use longer password with more non-alphanumeric character + passwordNotSecure: provided password is not secure; use longer password with more special characters passwordResetDisabledByConfig: password reset is disabled profileWithoutValidEmail: external authentication provider returned profile without valid email unconfiguredTOTP: TOTP not configured diff --git a/vendor/github.com/cortezaproject/corteza-locale/src/en/corteza-server/system/user.yaml b/vendor/github.com/cortezaproject/corteza-locale/src/en/corteza-server/system/user.yaml index 1b70812285..e750b9ebaf 100644 --- a/vendor/github.com/cortezaproject/corteza-locale/src/en/corteza-server/system/user.yaml +++ b/vendor/github.com/cortezaproject/corteza-locale/src/en/corteza-server/system/user.yaml @@ -16,5 +16,5 @@ errors: notAllowedToUpdate: not allowed to update this user notAllowedToUpdateSystem: not allowed to update system users notFound: user not found - passwordNotSecure: provided password is not secure; use longer password with more non-alphanumeric character + passwordNotSecure: provided password is not secure; use longer password with more special characters usernameNotUnique: username not unique diff --git a/vendor/github.com/cortezaproject/corteza-locale/src/fr/corteza-server/system/auth.yaml b/vendor/github.com/cortezaproject/corteza-locale/src/fr/corteza-server/system/auth.yaml index edfd41e59e..d45ddb9a61 100644 --- a/vendor/github.com/cortezaproject/corteza-locale/src/fr/corteza-server/system/auth.yaml +++ b/vendor/github.com/cortezaproject/corteza-locale/src/fr/corteza-server/system/auth.yaml @@ -20,7 +20,7 @@ errors: notAllowedToRemoveTOTP: not allowed to remove TOTP passwodResetFailedOldPasswordCheckFailed: failed to change password, old password does not match passwordChangeFailedForUnknownUser: failed to change password for the unknown user - passwordNotSecure: provided password is not secure; use longer password with more non-alphanumeric character + passwordNotSecure: provided password is not secure; use longer password with more special characters passwordResetDisabledByConfig: password reset is disabled profileWithoutValidEmail: external authentication provider returned profile without valid email unconfiguredTOTP: TOTP not configured diff --git a/vendor/github.com/cortezaproject/corteza-locale/src/fr/corteza-server/system/user.yaml b/vendor/github.com/cortezaproject/corteza-locale/src/fr/corteza-server/system/user.yaml index 39ac203565..8897420ad4 100644 --- a/vendor/github.com/cortezaproject/corteza-locale/src/fr/corteza-server/system/user.yaml +++ b/vendor/github.com/cortezaproject/corteza-locale/src/fr/corteza-server/system/user.yaml @@ -17,5 +17,5 @@ errors: notAllowedToUpdate: not allowed to update this user notAllowedToUpdateSystem: not allowed to update system users notFound: user not found - passwordNotSecure: provided password is not secure; use longer password with more non-alphanumeric character + passwordNotSecure: provided password is not secure; use longer password with more special characters usernameNotUnique: username not unique diff --git a/vendor/github.com/cortezaproject/corteza-locale/src/ro/corteza-server/system/auth.yaml b/vendor/github.com/cortezaproject/corteza-locale/src/ro/corteza-server/system/auth.yaml index edfd41e59e..d45ddb9a61 100644 --- a/vendor/github.com/cortezaproject/corteza-locale/src/ro/corteza-server/system/auth.yaml +++ b/vendor/github.com/cortezaproject/corteza-locale/src/ro/corteza-server/system/auth.yaml @@ -20,7 +20,7 @@ errors: notAllowedToRemoveTOTP: not allowed to remove TOTP passwodResetFailedOldPasswordCheckFailed: failed to change password, old password does not match passwordChangeFailedForUnknownUser: failed to change password for the unknown user - passwordNotSecure: provided password is not secure; use longer password with more non-alphanumeric character + passwordNotSecure: provided password is not secure; use longer password with more special characters passwordResetDisabledByConfig: password reset is disabled profileWithoutValidEmail: external authentication provider returned profile without valid email unconfiguredTOTP: TOTP not configured diff --git a/vendor/github.com/cortezaproject/corteza-locale/src/ro/corteza-server/system/user.yaml b/vendor/github.com/cortezaproject/corteza-locale/src/ro/corteza-server/system/user.yaml index 39ac203565..8897420ad4 100644 --- a/vendor/github.com/cortezaproject/corteza-locale/src/ro/corteza-server/system/user.yaml +++ b/vendor/github.com/cortezaproject/corteza-locale/src/ro/corteza-server/system/user.yaml @@ -17,5 +17,5 @@ errors: notAllowedToUpdate: not allowed to update this user notAllowedToUpdateSystem: not allowed to update system users notFound: user not found - passwordNotSecure: provided password is not secure; use longer password with more non-alphanumeric character + passwordNotSecure: provided password is not secure; use longer password with more special characters usernameNotUnique: username not unique diff --git a/vendor/github.com/cortezaproject/corteza-locale/src/sl/corteza-server/system/auth.yaml b/vendor/github.com/cortezaproject/corteza-locale/src/sl/corteza-server/system/auth.yaml index edfd41e59e..d45ddb9a61 100644 --- a/vendor/github.com/cortezaproject/corteza-locale/src/sl/corteza-server/system/auth.yaml +++ b/vendor/github.com/cortezaproject/corteza-locale/src/sl/corteza-server/system/auth.yaml @@ -20,7 +20,7 @@ errors: notAllowedToRemoveTOTP: not allowed to remove TOTP passwodResetFailedOldPasswordCheckFailed: failed to change password, old password does not match passwordChangeFailedForUnknownUser: failed to change password for the unknown user - passwordNotSecure: provided password is not secure; use longer password with more non-alphanumeric character + passwordNotSecure: provided password is not secure; use longer password with more special characters passwordResetDisabledByConfig: password reset is disabled profileWithoutValidEmail: external authentication provider returned profile without valid email unconfiguredTOTP: TOTP not configured diff --git a/vendor/github.com/cortezaproject/corteza-locale/src/sl/corteza-server/system/user.yaml b/vendor/github.com/cortezaproject/corteza-locale/src/sl/corteza-server/system/user.yaml index 39ac203565..8897420ad4 100644 --- a/vendor/github.com/cortezaproject/corteza-locale/src/sl/corteza-server/system/user.yaml +++ b/vendor/github.com/cortezaproject/corteza-locale/src/sl/corteza-server/system/user.yaml @@ -17,5 +17,5 @@ errors: notAllowedToUpdate: not allowed to update this user notAllowedToUpdateSystem: not allowed to update system users notFound: user not found - passwordNotSecure: provided password is not secure; use longer password with more non-alphanumeric character + passwordNotSecure: provided password is not secure; use longer password with more special characters usernameNotUnique: username not unique diff --git a/vendor/github.com/cortezaproject/corteza-locale/src/uk/corteza-server/system/auth.yaml b/vendor/github.com/cortezaproject/corteza-locale/src/uk/corteza-server/system/auth.yaml index edfd41e59e..d45ddb9a61 100644 --- a/vendor/github.com/cortezaproject/corteza-locale/src/uk/corteza-server/system/auth.yaml +++ b/vendor/github.com/cortezaproject/corteza-locale/src/uk/corteza-server/system/auth.yaml @@ -20,7 +20,7 @@ errors: notAllowedToRemoveTOTP: not allowed to remove TOTP passwodResetFailedOldPasswordCheckFailed: failed to change password, old password does not match passwordChangeFailedForUnknownUser: failed to change password for the unknown user - passwordNotSecure: provided password is not secure; use longer password with more non-alphanumeric character + passwordNotSecure: provided password is not secure; use longer password with more special characters passwordResetDisabledByConfig: password reset is disabled profileWithoutValidEmail: external authentication provider returned profile without valid email unconfiguredTOTP: TOTP not configured diff --git a/vendor/github.com/cortezaproject/corteza-locale/src/uk/corteza-server/system/user.yaml b/vendor/github.com/cortezaproject/corteza-locale/src/uk/corteza-server/system/user.yaml index 39ac203565..8897420ad4 100644 --- a/vendor/github.com/cortezaproject/corteza-locale/src/uk/corteza-server/system/user.yaml +++ b/vendor/github.com/cortezaproject/corteza-locale/src/uk/corteza-server/system/user.yaml @@ -17,5 +17,5 @@ errors: notAllowedToUpdate: not allowed to update this user notAllowedToUpdateSystem: not allowed to update system users notFound: user not found - passwordNotSecure: provided password is not secure; use longer password with more non-alphanumeric character + passwordNotSecure: provided password is not secure; use longer password with more special characters usernameNotUnique: username not unique