Skip to content

Commit f331f66

Browse files
bhaskaryasaArthur Cinader
authored and
Arthur Cinader
committed
Add support for regex string for password policy validatorPattern setting (#3331)
1 parent df029b8 commit f331f66

File tree

3 files changed

+72
-10
lines changed

3 files changed

+72
-10
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ var server = ParseServer({
281281
passwordPolicy: {
282282
// Two optional settings to enforce strong passwords. Either one or both can be specified.
283283
// If both are specified, both checks must pass to accept the password
284-
// 1. a RegExp representing the pattern to enforce
284+
// 1. a RegExp object or a regex string representing the pattern to enforce
285285
validatorPattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,})/, // enforce password with at least 8 char with at least 1 lower case, 1 upper case and 1 digit
286286
// 2. a callback function to be invoked to validate the password
287287
validatorCallback: (password) => { return validatePassword(password) },

spec/PasswordPolicy.spec.js

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -147,14 +147,14 @@ describe("Password Policy: ", () => {
147147
reconfigureServer({
148148
appName: 'passwordPolicy',
149149
passwordPolicy: {
150-
validatorPattern: "abc" // string is not a valid setting
150+
validatorPattern: 1234 // number is not a valid setting
151151
},
152152
publicServerURL: "http://localhost:8378/1"
153153
}).then(() => {
154154
fail('passwordPolicy.validatorPattern type test failed');
155155
done();
156156
}).catch(err => {
157-
expect(err).toEqual('passwordPolicy.validatorPattern must be a RegExp.');
157+
expect(err).toEqual('passwordPolicy.validatorPattern must be a regex string or RegExp object.');
158158
done();
159159
});
160160
});
@@ -197,6 +197,28 @@ describe("Password Policy: ", () => {
197197
})
198198
});
199199

200+
it('signup should fail if password does not conform to the policy enforced using validatorPattern string', (done) => {
201+
const user = new Parse.User();
202+
reconfigureServer({
203+
appName: 'passwordPolicy',
204+
passwordPolicy: {
205+
validatorPattern: "^.{8,}" // password should contain at least 8 char
206+
},
207+
publicServerURL: "http://localhost:8378/1"
208+
}).then(() => {
209+
user.setUsername("user1");
210+
user.setPassword("less");
211+
user.set('email', '[email protected]');
212+
user.signUp().then(() => {
213+
fail('Should have failed as password does not conform to the policy.');
214+
done();
215+
}).catch((error) => {
216+
expect(error.code).toEqual(142);
217+
done();
218+
});
219+
})
220+
});
221+
200222
it('signup should succeed if password conforms to the policy enforced using validatorPattern', (done) => {
201223
const user = new Parse.User();
202224
reconfigureServer({
@@ -231,6 +253,40 @@ describe("Password Policy: ", () => {
231253
})
232254
});
233255

256+
it('signup should succeed if password conforms to the policy enforced using validatorPattern string', (done) => {
257+
const user = new Parse.User();
258+
reconfigureServer({
259+
appName: 'passwordPolicy',
260+
passwordPolicy: {
261+
validatorPattern: "[!@#$]+" // password should contain at least one special char
262+
},
263+
publicServerURL: "http://localhost:8378/1"
264+
}).then(() => {
265+
user.setUsername("user1");
266+
user.setPassword("p@sswrod");
267+
user.set('email', '[email protected]');
268+
user.signUp().then(() => {
269+
Parse.User.logOut().then(() => {
270+
Parse.User.logIn("user1", "p@sswrod").then(function () {
271+
done();
272+
}).catch((err) => {
273+
jfail(err);
274+
fail("Should be able to login");
275+
done();
276+
});
277+
}).catch((error) => {
278+
jfail(error);
279+
fail('logout should have succeeded');
280+
done();
281+
});
282+
}).catch((error) => {
283+
jfail(error);
284+
fail('Signup should have succeeded as password conforms to the policy.');
285+
done();
286+
});
287+
})
288+
});
289+
234290
it('signup should fail if password does not conform to the policy enforced using validatorCallback', (done) => {
235291
const user = new Parse.User();
236292
reconfigureServer({
@@ -409,12 +465,12 @@ describe("Password Policy: ", () => {
409465
fail("should login with new password");
410466
done();
411467
});
412-
}).catch((error)=> {
468+
}).catch((error) => {
413469
jfail(error);
414470
fail("Failed to POST request password reset");
415471
done();
416472
});
417-
}).catch((error)=> {
473+
}).catch((error) => {
418474
jfail(error);
419475
fail("Failed to get the reset link");
420476
done();
@@ -839,7 +895,7 @@ describe("Password Policy: ", () => {
839895
reconfigureServer({
840896
appName: 'passwordPolicy',
841897
passwordPolicy: {
842-
maxPasswordAge: 0.5/(24*60*60) // 0.5 sec
898+
maxPasswordAge: 0.5 / (24 * 60 * 60) // 0.5 sec
843899
},
844900
publicServerURL: "http://localhost:8378/1"
845901
}).then(() => {
@@ -880,7 +936,7 @@ describe("Password Policy: ", () => {
880936
reconfigureServer({
881937
appName: 'passwordPolicy',
882938
passwordPolicy: {
883-
maxPasswordAge: 0.5/(24*60*60) // 0.5 sec
939+
maxPasswordAge: 0.5 / (24 * 60 * 60) // 0.5 sec
884940
},
885941
publicServerURL: "http://localhost:8378/1"
886942
}).then(() => {
@@ -979,7 +1035,7 @@ describe("Password Policy: ", () => {
9791035
appName: 'passwordPolicy',
9801036
emailAdapter: emailAdapter,
9811037
passwordPolicy: {
982-
maxPasswordAge: 0.5/(24*60*60) // 0.5 sec
1038+
maxPasswordAge: 0.5 / (24 * 60 * 60) // 0.5 sec
9831039
},
9841040
publicServerURL: "http://localhost:8378/1"
9851041
}).then(() => {

src/Config.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,16 @@ export class Config {
127127
throw 'passwordPolicy.resetTokenValidityDuration must be a positive number';
128128
}
129129

130-
if(passwordPolicy.validatorPattern && !(passwordPolicy.validatorPattern instanceof RegExp)) {
131-
throw 'passwordPolicy.validatorPattern must be a RegExp.';
130+
if(passwordPolicy.validatorPattern){
131+
if(typeof(passwordPolicy.validatorPattern) === 'string') {
132+
passwordPolicy.validatorPattern = new RegExp(passwordPolicy.validatorPattern);
133+
}
134+
else if(!(passwordPolicy.validatorPattern instanceof RegExp)){
135+
throw 'passwordPolicy.validatorPattern must be a regex string or RegExp object.';
136+
}
132137
}
133138

139+
134140
if(passwordPolicy.validatorCallback && typeof passwordPolicy.validatorCallback !== 'function') {
135141
throw 'passwordPolicy.validatorCallback must be a function.';
136142
}

0 commit comments

Comments
 (0)