feat: add validation for strong password
This commit is contained in:
parent
47d67bf3cd
commit
ec4ef97766
|
@ -35,6 +35,10 @@ func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput)
|
||||||
return res, fmt.Errorf(`passwords don't match`)
|
return res, fmt.Errorf(`passwords don't match`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !utils.IsValidPassword(params.Password) {
|
||||||
|
return res, fmt.Errorf(`password is not valid. It needs to be at least 6 characters long and contain at least one number, one uppercase letter, one lowercase letter and one special character`)
|
||||||
|
}
|
||||||
|
|
||||||
// verify if token exists in db
|
// verify if token exists in db
|
||||||
hostname := utils.GetHost(gc)
|
hostname := utils.GetHost(gc)
|
||||||
claim, err := token.ParseJWTToken(params.Token, hostname, verificationRequest.Nonce, verificationRequest.Email)
|
claim, err := token.ParseJWTToken(params.Token, hostname, verificationRequest.Nonce, verificationRequest.Email)
|
||||||
|
|
|
@ -40,6 +40,10 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
|
||||||
return res, fmt.Errorf(`password and confirm password does not match`)
|
return res, fmt.Errorf(`password and confirm password does not match`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !utils.IsValidPassword(params.Password) {
|
||||||
|
return res, fmt.Errorf(`password is not valid. It needs to be at least 6 characters long and contain at least one number, one uppercase letter, one lowercase letter and one special character`)
|
||||||
|
}
|
||||||
|
|
||||||
params.Email = strings.ToLower(params.Email)
|
params.Email = strings.ToLower(params.Email)
|
||||||
|
|
||||||
if !utils.IsValidEmail(params.Email) {
|
if !utils.IsValidEmail(params.Email) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
|
"github.com/authorizerdev/authorizer/server/envstore"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -16,11 +17,17 @@ func magicLinkLoginTests(t *testing.T, s TestSetup) {
|
||||||
t.Run(`should login with magic link`, func(t *testing.T) {
|
t.Run(`should login with magic link`, func(t *testing.T) {
|
||||||
req, ctx := createContext(s)
|
req, ctx := createContext(s)
|
||||||
email := "magic_link_login." + s.TestInfo.Email
|
email := "magic_link_login." + s.TestInfo.Email
|
||||||
|
envstore.EnvStoreObj.UpdateEnvVariable(constants.BoolStoreIdentifier, constants.EnvKeyDisableSignUp, true)
|
||||||
_, err := resolvers.MagicLinkLoginResolver(ctx, model.MagicLinkLoginInput{
|
_, err := resolvers.MagicLinkLoginResolver(ctx, model.MagicLinkLoginInput{
|
||||||
Email: email,
|
Email: email,
|
||||||
})
|
})
|
||||||
assert.Nil(t, err)
|
assert.NotNil(t, err, "signup disabled")
|
||||||
|
|
||||||
|
envstore.EnvStoreObj.UpdateEnvVariable(constants.BoolStoreIdentifier, constants.EnvKeyDisableSignUp, false)
|
||||||
|
_, err = resolvers.MagicLinkLoginResolver(ctx, model.MagicLinkLoginInput{
|
||||||
|
Email: email,
|
||||||
|
})
|
||||||
|
assert.Nil(t, err, "signup should be successful")
|
||||||
|
|
||||||
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeMagicLinkLogin)
|
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(email, constants.VerificationTypeMagicLinkLogin)
|
||||||
verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{
|
verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{
|
||||||
|
|
|
@ -43,6 +43,14 @@ func resetPasswordTest(t *testing.T, s TestSetup) {
|
||||||
ConfirmPassword: "test1",
|
ConfirmPassword: "test1",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
assert.NotNil(t, err, "invalid password")
|
||||||
|
|
||||||
|
_, err = resolvers.ResetPasswordResolver(ctx, model.ResetPasswordInput{
|
||||||
|
Token: verificationRequest.Token,
|
||||||
|
Password: "Test@1234",
|
||||||
|
ConfirmPassword: "Test@1234",
|
||||||
|
})
|
||||||
|
|
||||||
assert.Nil(t, err, "password changed successfully")
|
assert.Nil(t, err, "password changed successfully")
|
||||||
|
|
||||||
cleanData(email)
|
cleanData(email)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
|
"github.com/authorizerdev/authorizer/server/envstore"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/resolvers"
|
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -20,14 +21,30 @@ func signupTests(t *testing.T, s TestSetup) {
|
||||||
Password: s.TestInfo.Password,
|
Password: s.TestInfo.Password,
|
||||||
ConfirmPassword: s.TestInfo.Password + "s",
|
ConfirmPassword: s.TestInfo.Password + "s",
|
||||||
})
|
})
|
||||||
assert.NotNil(t, err, "invalid password errors")
|
assert.NotNil(t, err, "invalid password")
|
||||||
|
|
||||||
|
res, err = resolvers.SignupResolver(ctx, model.SignUpInput{
|
||||||
|
Email: email,
|
||||||
|
Password: "test",
|
||||||
|
ConfirmPassword: "test",
|
||||||
|
})
|
||||||
|
assert.NotNil(t, err, "invalid password")
|
||||||
|
|
||||||
|
envstore.EnvStoreObj.UpdateEnvVariable(constants.BoolStoreIdentifier, constants.EnvKeyDisableSignUp, true)
|
||||||
res, err = resolvers.SignupResolver(ctx, model.SignUpInput{
|
res, err = resolvers.SignupResolver(ctx, model.SignUpInput{
|
||||||
Email: email,
|
Email: email,
|
||||||
Password: s.TestInfo.Password,
|
Password: s.TestInfo.Password,
|
||||||
ConfirmPassword: s.TestInfo.Password,
|
ConfirmPassword: s.TestInfo.Password,
|
||||||
})
|
})
|
||||||
|
assert.NotNil(t, err, "singup disabled")
|
||||||
|
|
||||||
|
envstore.EnvStoreObj.UpdateEnvVariable(constants.BoolStoreIdentifier, constants.EnvKeyDisableSignUp, false)
|
||||||
|
res, err = resolvers.SignupResolver(ctx, model.SignUpInput{
|
||||||
|
Email: email,
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
ConfirmPassword: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.Nil(t, err, "signup should be successful")
|
||||||
user := *res.User
|
user := *res.User
|
||||||
assert.Equal(t, email, user.Email)
|
assert.Equal(t, email, user.Email)
|
||||||
assert.Nil(t, res.AccessToken, "access token should be nil")
|
assert.Nil(t, res.AccessToken, "access token should be nil")
|
||||||
|
|
|
@ -68,7 +68,7 @@ func createContext(s TestSetup) (*http.Request, context.Context) {
|
||||||
func testSetup() TestSetup {
|
func testSetup() TestSetup {
|
||||||
testData := TestData{
|
testData := TestData{
|
||||||
Email: fmt.Sprintf("%d_authorizer_tester@yopmail.com", time.Now().Unix()),
|
Email: fmt.Sprintf("%d_authorizer_tester@yopmail.com", time.Now().Unix()),
|
||||||
Password: "test",
|
Password: "Test@123",
|
||||||
}
|
}
|
||||||
|
|
||||||
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyEnvPath, "../../.env.sample")
|
envstore.EnvStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyEnvPath, "../../.env.sample")
|
||||||
|
|
|
@ -41,3 +41,11 @@ func TestIsValidIdentifier(t *testing.T) {
|
||||||
assert.True(t, utils.IsValidVerificationIdentifier(constants.VerificationTypeUpdateEmail), "it should be valid identifier")
|
assert.True(t, utils.IsValidVerificationIdentifier(constants.VerificationTypeUpdateEmail), "it should be valid identifier")
|
||||||
assert.True(t, utils.IsValidVerificationIdentifier(constants.VerificationTypeForgotPassword), "it should be valid identifier")
|
assert.True(t, utils.IsValidVerificationIdentifier(constants.VerificationTypeForgotPassword), "it should be valid identifier")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsValidPassword(t *testing.T) {
|
||||||
|
assert.False(t, utils.IsValidPassword("test"), "it should be invalid password")
|
||||||
|
assert.False(t, utils.IsValidPassword("Te@1"), "it should be invalid password")
|
||||||
|
assert.False(t, utils.IsValidPassword("n*rp7GGTd29V{xx%{pDb@7n{](SD.!+.Mp#*$EHDGk&$pAMf7e#432Sg,Gr](j3n]jV/3F8BJJT+9u9{q=8zK:8u!rpQBaXJp%A+7r!jQj)M(vC$UX,h;;WKm$U6i#7dBnC&2ryKzKd+(y&=Ud)hErT/j;v3t..CM).8nS)9qLtV7pmP;@2QuzDyGfL7KB()k:BpjAGL@bxD%r5gcBfh7$&wutk!wzMfPFY#nkjjqyZbEHku,{jc;gvbYq2)3w=KExnYz9Vbv:;*;?f##faxkULdMpmm&yEfePixzx+[{[38zGN;3TzF;6M#Xy_tMtx:yK*n$bc(bPyGz%EYkC&]ttUF@#aZ%$QZ:u!icF@+"), "it should be invalid password")
|
||||||
|
assert.False(t, utils.IsValidPassword("test@123"), "it should be invalid password")
|
||||||
|
assert.True(t, utils.IsValidPassword("Test@123"), "it should be valid password")
|
||||||
|
}
|
||||||
|
|
|
@ -86,3 +86,35 @@ func IsStringArrayEqual(a, b []string) bool {
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidatePassword to validate the password against the following policy
|
||||||
|
// min char length: 6
|
||||||
|
// max char length: 36
|
||||||
|
// at least one upper case letter
|
||||||
|
// at least one lower case letter
|
||||||
|
// at least one digit
|
||||||
|
// at least one special character
|
||||||
|
func IsValidPassword(password string) bool {
|
||||||
|
if len(password) < 6 || len(password) > 36 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
hasUpperCase := false
|
||||||
|
hasLowerCase := false
|
||||||
|
hasDigit := false
|
||||||
|
hasSpecialChar := false
|
||||||
|
|
||||||
|
for _, char := range password {
|
||||||
|
if char >= 'A' && char <= 'Z' {
|
||||||
|
hasUpperCase = true
|
||||||
|
} else if char >= 'a' && char <= 'z' {
|
||||||
|
hasLowerCase = true
|
||||||
|
} else if char >= '0' && char <= '9' {
|
||||||
|
hasDigit = true
|
||||||
|
} else {
|
||||||
|
hasSpecialChar = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasUpperCase && hasLowerCase && hasDigit && hasSpecialChar
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user