feat: add validation for strong password

This commit is contained in:
Lakhan Samani 2022-03-17 15:35:07 +05:30
parent 47d67bf3cd
commit ec4ef97766
8 changed files with 84 additions and 4 deletions

View File

@ -35,6 +35,10 @@ func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput)
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
hostname := utils.GetHost(gc)
claim, err := token.ParseJWTToken(params.Token, hostname, verificationRequest.Nonce, verificationRequest.Email)

View File

@ -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`)
}
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)
if !utils.IsValidEmail(params.Email) {

View File

@ -6,6 +6,7 @@ import (
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers"
"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) {
req, ctx := createContext(s)
email := "magic_link_login." + s.TestInfo.Email
envstore.EnvStoreObj.UpdateEnvVariable(constants.BoolStoreIdentifier, constants.EnvKeyDisableSignUp, true)
_, err := resolvers.MagicLinkLoginResolver(ctx, model.MagicLinkLoginInput{
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)
verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{

View File

@ -43,6 +43,14 @@ func resetPasswordTest(t *testing.T, s TestSetup) {
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")
cleanData(email)

View File

@ -5,6 +5,7 @@ import (
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/graph/model"
"github.com/authorizerdev/authorizer/server/resolvers"
"github.com/stretchr/testify/assert"
@ -20,14 +21,30 @@ func signupTests(t *testing.T, s TestSetup) {
Password: s.TestInfo.Password,
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{
Email: email,
Password: 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
assert.Equal(t, email, user.Email)
assert.Nil(t, res.AccessToken, "access token should be nil")

View File

@ -68,7 +68,7 @@ func createContext(s TestSetup) (*http.Request, context.Context) {
func testSetup() TestSetup {
testData := TestData{
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")

View File

@ -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.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")
}

View File

@ -86,3 +86,35 @@ func IsStringArrayEqual(a, b []string) bool {
}
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
}