2018-09-01 13:58:06 -04:00
'use strict' ;
2016-11-17 22:07:51 +05:30
2018-09-24 17:07:51 -04:00
const request = require ( '../lib/request' ) ;
2016-11-17 22:07:51 +05:30
2018-09-01 13:58:06 -04:00
describe ( 'Password Policy: ' , ( ) => {
2016-11-17 22:07:51 +05:30
it ( 'should show the invalid link page if the user clicks on the password reset link after the token expires' , done => {
const user = new Parse . User ( ) ;
let sendEmailOptions ;
const emailAdapter = {
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : options => {
sendEmailOptions = options ;
} ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => { } ,
2016-11-21 21:16:38 +05:30
} ;
2016-11-17 22:07:51 +05:30
reconfigureServer ( {
appName : 'passwordPolicy' ,
emailAdapter : emailAdapter ,
passwordPolicy : {
resetTokenValidityDuration : 0.5 , // 0.5 second
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} )
. then ( ( ) => {
user . setUsername ( 'testResetTokenValidity' ) ;
user . setPassword ( 'original' ) ;
user . set ( 'email' , 'user@parse.com' ) ;
return user . signUp ( ) ;
} )
. then ( ( ) => {
Parse . User . requestPasswordReset ( 'user@parse.com' ) . catch ( err => {
jfail ( err ) ;
fail ( 'Reset password request should not fail' ) ;
done ( ) ;
} ) ;
} )
. then ( ( ) => {
// wait for a bit more than the validity duration set
setTimeout ( ( ) => {
expect ( sendEmailOptions ) . not . toBeUndefined ( ) ;
2018-09-24 17:07:51 -04:00
request ( {
url : sendEmailOptions . link ,
followRedirects : false ,
simple : false ,
resolveWithFullResponse : true ,
} )
2018-09-01 13:58:06 -04:00
. then ( response => {
2018-09-24 17:07:51 -04:00
expect ( response . status ) . toEqual ( 302 ) ;
expect ( response . text ) . toEqual (
2018-09-01 13:58:06 -04:00
'Found. Redirecting to http://localhost:8378/1/apps/invalid_link.html'
) ;
done ( ) ;
} )
. catch ( error => {
fail ( error ) ;
} ) ;
} , 1000 ) ;
} )
. catch ( err => {
2016-11-21 21:16:38 +05:30
jfail ( err ) ;
done ( ) ;
} ) ;
2016-11-17 22:07:51 +05:30
} ) ;
it ( 'should show the reset password page if the user clicks on the password reset link before the token expires' , done => {
const user = new Parse . User ( ) ;
let sendEmailOptions ;
const emailAdapter = {
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : options => {
sendEmailOptions = options ;
} ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => { } ,
2016-11-21 21:16:38 +05:30
} ;
2016-11-17 22:07:51 +05:30
reconfigureServer ( {
appName : 'passwordPolicy' ,
emailAdapter : emailAdapter ,
passwordPolicy : {
resetTokenValidityDuration : 5 , // 5 seconds
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} )
. then ( ( ) => {
user . setUsername ( 'testResetTokenValidity' ) ;
user . setPassword ( 'original' ) ;
user . set ( 'email' , 'user@parse.com' ) ;
return user . signUp ( ) ;
} )
. then ( ( ) => {
Parse . User . requestPasswordReset ( 'user@parse.com' ) . catch ( err => {
jfail ( err ) ;
fail ( 'Reset password request should not fail' ) ;
done ( ) ;
} ) ;
} )
. then ( ( ) => {
// wait for a bit but less than the validity duration
setTimeout ( ( ) => {
expect ( sendEmailOptions ) . not . toBeUndefined ( ) ;
2018-09-24 17:07:51 -04:00
request ( {
url : sendEmailOptions . link ,
simple : false ,
resolveWithFullResponse : true ,
followRedirects : false ,
} )
2018-09-01 13:58:06 -04:00
. then ( response => {
2018-09-24 17:07:51 -04:00
expect ( response . status ) . toEqual ( 302 ) ;
2018-09-01 13:58:06 -04:00
const re = /http:\/\/localhost:8378\/1\/apps\/choose_password\?token=[a-zA-Z0-9]+\&id=test\&username=testResetTokenValidity/ ;
2018-09-24 17:07:51 -04:00
expect ( response . text . match ( re ) ) . not . toBe ( null ) ;
2018-09-01 13:58:06 -04:00
done ( ) ;
} )
. catch ( error => {
fail ( error ) ;
} ) ;
} , 1000 ) ;
} )
. catch ( err => {
2016-11-21 21:16:38 +05:30
jfail ( err ) ;
done ( ) ;
} ) ;
2016-11-17 22:07:51 +05:30
} ) ;
it ( 'should fail if passwordPolicy.resetTokenValidityDuration is not a number' , done => {
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
resetTokenValidityDuration : 'not a number' ,
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} )
. then ( ( ) => {
fail (
'passwordPolicy.resetTokenValidityDuration "not a number" test failed'
) ;
done ( ) ;
} )
. catch ( err => {
expect ( err ) . toEqual (
'passwordPolicy.resetTokenValidityDuration must be a positive number'
) ;
done ( ) ;
} ) ;
2016-11-17 22:07:51 +05:30
} ) ;
it ( 'should fail if passwordPolicy.resetTokenValidityDuration is zero or a negative number' , done => {
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
resetTokenValidityDuration : 0 ,
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} )
. then ( ( ) => {
fail ( 'resetTokenValidityDuration negative number test failed' ) ;
done ( ) ;
} )
. catch ( err => {
expect ( err ) . toEqual (
'passwordPolicy.resetTokenValidityDuration must be a positive number'
) ;
done ( ) ;
} ) ;
2016-11-17 22:07:51 +05:30
} ) ;
it ( 'should fail if passwordPolicy.validatorPattern setting is invalid type' , done => {
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
validatorPattern : 1234 , // number is not a valid setting
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} )
. then ( ( ) => {
fail ( 'passwordPolicy.validatorPattern type test failed' ) ;
done ( ) ;
} )
. catch ( err => {
expect ( err ) . toEqual (
'passwordPolicy.validatorPattern must be a regex string or RegExp object.'
) ;
done ( ) ;
} ) ;
2016-11-17 22:07:51 +05:30
} ) ;
it ( 'should fail if passwordPolicy.validatorCallback setting is invalid type' , done => {
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
validatorCallback : 'abc' , // string is not a valid setting
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} )
. then ( ( ) => {
fail ( 'passwordPolicy.validatorCallback type test failed' ) ;
done ( ) ;
} )
. catch ( err => {
expect ( err ) . toEqual (
'passwordPolicy.validatorCallback must be a function.'
) ;
done ( ) ;
} ) ;
2016-11-17 22:07:51 +05:30
} ) ;
2018-09-01 13:58:06 -04:00
it ( 'signup should fail if password does not conform to the policy enforced using validatorPattern' , done => {
2016-11-17 22:07:51 +05:30
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
validatorPattern : /[0-9]+/ , // password should contain at least one digit
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-17 22:07:51 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'nodigit' ) ;
2016-11-17 22:07:51 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
fail (
'Should have failed as password does not conform to the policy.'
) ;
done ( ) ;
} )
. catch ( error => {
expect ( error . code ) . toEqual ( 142 ) ;
done ( ) ;
} ) ;
} ) ;
2016-11-17 22:07:51 +05:30
} ) ;
2018-09-01 13:58:06 -04:00
it ( 'signup should fail if password does not conform to the policy enforced using validatorPattern string' , done => {
2017-01-08 20:42:44 +05:30
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
validatorPattern : '^.{8,}' , // password should contain at least 8 char
2017-01-08 20:42:44 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2017-01-08 20:42:44 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'less' ) ;
2017-01-08 20:42:44 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
fail (
'Should have failed as password does not conform to the policy.'
) ;
done ( ) ;
} )
. catch ( error => {
expect ( error . code ) . toEqual ( 142 ) ;
done ( ) ;
} ) ;
} ) ;
2017-01-08 20:42:44 +05:30
} ) ;
2018-09-01 13:58:06 -04:00
it ( 'signup should fail if password is empty' , done => {
2017-02-24 17:51:50 +05:30
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
validatorPattern : '^.{8,}' , // password should contain at least 8 char
2017-02-24 17:51:50 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2017-02-24 17:51:50 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( '' ) ;
2017-02-24 17:51:50 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
fail (
'Should have failed as password does not conform to the policy.'
) ;
done ( ) ;
} )
. catch ( error => {
expect ( error . message ) . toEqual (
'Cannot sign up user with an empty password.'
) ;
done ( ) ;
} ) ;
} ) ;
2017-02-24 17:51:50 +05:30
} ) ;
2018-09-01 13:58:06 -04:00
it ( 'signup should succeed if password conforms to the policy enforced using validatorPattern' , done => {
2016-11-17 22:07:51 +05:30
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
validatorPattern : /[0-9]+/ , // password should contain at least one digit
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-17 22:07:51 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( '1digit' ) ;
2016-11-17 22:07:51 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
Parse . User . logOut ( )
. then ( ( ) => {
Parse . User . logIn ( 'user1' , '1digit' )
. then ( function ( ) {
done ( ) ;
} )
. catch ( err => {
jfail ( err ) ;
fail ( 'Should be able to login' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'logout should have succeeded' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
2016-11-21 21:16:38 +05:30
jfail ( error ) ;
2018-09-01 13:58:06 -04:00
fail (
'Signup should have succeeded as password conforms to the policy.'
) ;
2016-11-17 22:07:51 +05:30
done ( ) ;
} ) ;
2018-09-01 13:58:06 -04:00
} ) ;
2016-11-17 22:07:51 +05:30
} ) ;
2018-09-01 13:58:06 -04:00
it ( 'signup should succeed if password conforms to the policy enforced using validatorPattern string' , done => {
2017-01-08 20:42:44 +05:30
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
validatorPattern : '[!@#$]+' , // password should contain at least one special char
2017-01-08 20:42:44 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2017-01-08 20:42:44 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'p@sswrod' ) ;
2017-01-08 20:42:44 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
Parse . User . logOut ( )
. then ( ( ) => {
Parse . User . logIn ( 'user1' , 'p@sswrod' )
. then ( function ( ) {
done ( ) ;
} )
. catch ( err => {
jfail ( err ) ;
fail ( 'Should be able to login' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'logout should have succeeded' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
2017-01-08 20:42:44 +05:30
jfail ( error ) ;
2018-09-01 13:58:06 -04:00
fail (
'Signup should have succeeded as password conforms to the policy.'
) ;
2017-01-08 20:42:44 +05:30
done ( ) ;
} ) ;
2018-09-01 13:58:06 -04:00
} ) ;
2017-01-08 20:42:44 +05:30
} ) ;
2018-09-01 13:58:06 -04:00
it ( 'signup should fail if password does not conform to the policy enforced using validatorCallback' , done => {
2016-11-17 22:07:51 +05:30
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
validatorCallback : ( ) => false , // just fail
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-17 22:07:51 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'any' ) ;
2016-11-17 22:07:51 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
fail (
'Should have failed as password does not conform to the policy.'
) ;
done ( ) ;
} )
. catch ( error => {
expect ( error . code ) . toEqual ( 142 ) ;
done ( ) ;
} ) ;
} ) ;
2016-11-17 22:07:51 +05:30
} ) ;
2018-09-01 13:58:06 -04:00
it ( 'signup should succeed if password conforms to the policy enforced using validatorCallback' , done => {
2016-11-17 22:07:51 +05:30
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
validatorCallback : ( ) => true , // never fail
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-17 22:07:51 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'oneUpper' ) ;
2016-11-17 22:07:51 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
Parse . User . logOut ( )
. then ( ( ) => {
Parse . User . logIn ( 'user1' , 'oneUpper' )
. then ( function ( ) {
done ( ) ;
} )
. catch ( err => {
jfail ( err ) ;
fail ( 'Should be able to login' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'Logout should have succeeded' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
2016-11-21 21:16:38 +05:30
jfail ( error ) ;
2018-09-01 13:58:06 -04:00
fail ( 'Should have succeeded as password conforms to the policy.' ) ;
2016-11-17 22:07:51 +05:30
done ( ) ;
} ) ;
2018-09-01 13:58:06 -04:00
} ) ;
2016-11-17 22:07:51 +05:30
} ) ;
2018-09-01 13:58:06 -04:00
it ( 'signup should fail if password does not match validatorPattern but succeeds validatorCallback' , done => {
2016-11-17 22:07:51 +05:30
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
validatorPattern : /[A-Z]+/ , // password should contain at least one UPPER case letter
validatorCallback : ( ) => true ,
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-17 22:07:51 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'all lower' ) ;
2016-11-17 22:07:51 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
fail (
'Should have failed as password does not conform to the policy.'
) ;
done ( ) ;
} )
. catch ( error => {
expect ( error . code ) . toEqual ( 142 ) ;
done ( ) ;
} ) ;
} ) ;
2016-11-17 22:07:51 +05:30
} ) ;
2018-09-01 13:58:06 -04:00
it ( 'signup should fail if password matches validatorPattern but fails validatorCallback' , done => {
2016-11-17 22:07:51 +05:30
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
validatorPattern : /[A-Z]+/ , // password should contain at least one UPPER case letter
validatorCallback : ( ) => false ,
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-17 22:07:51 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'oneUpper' ) ;
2016-11-17 22:07:51 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
fail (
'Should have failed as password does not conform to the policy.'
) ;
done ( ) ;
} )
. catch ( error => {
expect ( error . code ) . toEqual ( 142 ) ;
done ( ) ;
} ) ;
} ) ;
2016-11-17 22:07:51 +05:30
} ) ;
2018-09-01 13:58:06 -04:00
it ( 'signup should succeed if password conforms to both validatorPattern and validatorCallback' , done => {
2016-11-17 22:07:51 +05:30
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
validatorPattern : /[A-Z]+/ , // password should contain at least one digit
validatorCallback : ( ) => true ,
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-17 22:07:51 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'oneUpper' ) ;
2016-11-17 22:07:51 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
Parse . User . logOut ( )
. then ( ( ) => {
Parse . User . logIn ( 'user1' , 'oneUpper' )
. then ( function ( ) {
done ( ) ;
} )
. catch ( err => {
jfail ( err ) ;
fail ( 'Should be able to login' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'logout should have succeeded' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
2016-11-21 21:16:38 +05:30
jfail ( error ) ;
2018-09-01 13:58:06 -04:00
fail ( 'Should have succeeded as password conforms to the policy.' ) ;
2016-11-17 22:07:51 +05:30
done ( ) ;
} ) ;
2018-09-01 13:58:06 -04:00
} ) ;
2016-11-17 22:07:51 +05:30
} ) ;
2016-11-21 21:16:38 +05:30
it ( 'should reset password if new password conforms to password policy' , done => {
const user = new Parse . User ( ) ;
const emailAdapter = {
2016-11-17 22:07:51 +05:30
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : options => {
2018-09-24 17:07:51 -04:00
request ( {
url : options . link ,
followRedirects : false ,
simple : false ,
resolveWithFullResponse : true ,
} )
2018-09-01 13:58:06 -04:00
. then ( response => {
2018-09-24 17:07:51 -04:00
expect ( response . status ) . toEqual ( 302 ) ;
2018-09-01 13:58:06 -04:00
const re = /http:\/\/localhost:8378\/1\/apps\/choose_password\?token=([a-zA-Z0-9]+)\&id=test\&username=user1/ ;
2018-09-24 17:07:51 -04:00
const match = response . text . match ( re ) ;
2018-09-01 13:58:06 -04:00
if ( ! match ) {
fail ( 'should have a token' ) ;
2016-11-17 22:07:51 +05:30
done ( ) ;
2018-09-01 13:58:06 -04:00
return ;
}
const token = match [ 1 ] ;
2018-09-24 17:07:51 -04:00
request ( {
method : 'POST' ,
url : 'http://localhost:8378/1/apps/test/request_password_reset' ,
body : ` new_password=has2init&token= ${ token } &username=user1 ` ,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded' ,
} ,
followRedirects : false ,
simple : false ,
resolveWithFullResponse : true ,
} )
2018-09-01 13:58:06 -04:00
. then ( response => {
2018-09-24 17:07:51 -04:00
expect ( response . status ) . toEqual ( 302 ) ;
expect ( response . text ) . toEqual (
2018-09-01 13:58:06 -04:00
'Found. Redirecting to http://localhost:8378/1/apps/password_reset_success.html?username=user1'
) ;
Parse . User . logIn ( 'user1' , 'has2init' )
. then ( function ( ) {
done ( ) ;
} )
. catch ( err => {
jfail ( err ) ;
fail ( 'should login with new password' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'Failed to POST request password reset' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
2016-11-17 22:07:51 +05:30
jfail ( error ) ;
2018-09-01 13:58:06 -04:00
fail ( 'Failed to get the reset link' ) ;
2016-11-17 22:07:51 +05:30
done ( ) ;
} ) ;
} ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => { } ,
2016-11-21 21:16:38 +05:30
} ;
2016-11-17 22:07:51 +05:30
reconfigureServer ( {
appName : 'passwordPolicy' ,
verifyUserEmails : false ,
emailAdapter : emailAdapter ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
validatorPattern : /[0-9]+/ , // password should contain at least one digit
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-17 22:07:51 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'has 1 digit' ) ;
2016-11-17 22:07:51 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
Parse . User . requestPasswordReset ( 'user1@parse.com' ) . catch ( err => {
jfail ( err ) ;
fail ( 'Reset password request should not fail' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'signUp should not fail' ) ;
2016-11-21 21:16:38 +05:30
done ( ) ;
2016-11-17 22:07:51 +05:30
} ) ;
} ) ;
} ) ;
it ( 'should fail to reset password if the new password does not conform to password policy' , done => {
2016-11-21 21:16:38 +05:30
const user = new Parse . User ( ) ;
const emailAdapter = {
2016-11-17 22:07:51 +05:30
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : options => {
2018-09-24 17:07:51 -04:00
request ( {
url : options . link ,
followRedirects : false ,
simple : false ,
resolveWithFullResponse : true ,
} )
2018-09-01 13:58:06 -04:00
. then ( response => {
2018-09-24 17:07:51 -04:00
expect ( response . status ) . toEqual ( 302 ) ;
2018-09-01 13:58:06 -04:00
const re = /http:\/\/localhost:8378\/1\/apps\/choose_password\?token=([a-zA-Z0-9]+)\&id=test\&username=user1/ ;
2018-09-24 17:07:51 -04:00
const match = response . text . match ( re ) ;
2018-09-01 13:58:06 -04:00
if ( ! match ) {
fail ( 'should have a token' ) ;
2016-11-17 22:07:51 +05:30
done ( ) ;
2018-09-01 13:58:06 -04:00
return ;
}
const token = match [ 1 ] ;
2018-09-24 17:07:51 -04:00
request ( {
method : 'POST' ,
url : 'http://localhost:8378/1/apps/test/request_password_reset' ,
body : ` new_password=hasnodigit&token= ${ token } &username=user1 ` ,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded' ,
} ,
followRedirects : false ,
simple : false ,
resolveWithFullResponse : true ,
} )
2018-09-01 13:58:06 -04:00
. then ( response => {
2018-09-24 17:07:51 -04:00
expect ( response . status ) . toEqual ( 302 ) ;
expect ( response . text ) . toEqual (
2019-02-28 16:17:31 -05:00
` Found. Redirecting to http://localhost:8378/1/apps/choose_password?username=user1&token= ${ token } &id=test&error=Password%20should%20contain%20at%20least%20one%20digit.&app=passwordPolicy `
2018-09-01 13:58:06 -04:00
) ;
Parse . User . logIn ( 'user1' , 'has 1 digit' )
. then ( function ( ) {
done ( ) ;
} )
. catch ( err => {
jfail ( err ) ;
fail ( 'should login with old password' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'Failed to POST request password reset' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
2016-11-17 22:07:51 +05:30
jfail ( error ) ;
2018-09-01 13:58:06 -04:00
fail ( 'Failed to get the reset link' ) ;
2016-11-17 22:07:51 +05:30
done ( ) ;
} ) ;
} ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => { } ,
2016-11-21 21:16:38 +05:30
} ;
2016-11-17 22:07:51 +05:30
reconfigureServer ( {
appName : 'passwordPolicy' ,
verifyUserEmails : false ,
emailAdapter : emailAdapter ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
validatorPattern : /[0-9]+/ , // password should contain at least one digit
2019-02-28 16:17:31 -05:00
validationError : 'Password should contain at least one digit.' ,
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-17 22:07:51 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'has 1 digit' ) ;
2016-11-17 22:07:51 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
Parse . User . requestPasswordReset ( 'user1@parse.com' ) . catch ( err => {
jfail ( err ) ;
fail ( 'Reset password request should not fail' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'signUp should not fail' ) ;
2016-11-21 21:16:38 +05:30
done ( ) ;
2016-11-17 22:07:51 +05:30
} ) ;
} ) ;
} ) ;
2018-09-01 13:58:06 -04:00
it ( 'should fail if passwordPolicy.doNotAllowUsername is not a boolean value' , done => {
2016-11-17 22:07:51 +05:30
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
doNotAllowUsername : 'no' ,
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} )
. then ( ( ) => {
fail ( 'passwordPolicy.doNotAllowUsername type test failed' ) ;
done ( ) ;
} )
. catch ( err => {
expect ( err ) . toEqual (
'passwordPolicy.doNotAllowUsername must be a boolean value.'
) ;
done ( ) ;
} ) ;
2016-11-17 22:07:51 +05:30
} ) ;
2018-09-01 13:58:06 -04:00
it ( 'signup should fail if password contains the username and is not allowed by policy' , done => {
2016-11-17 22:07:51 +05:30
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
validatorPattern : /[0-9]+/ ,
2018-09-01 13:58:06 -04:00
doNotAllowUsername : true ,
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-17 22:07:51 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( '@user11' ) ;
2016-11-17 22:07:51 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
fail ( 'Should have failed as password contains username.' ) ;
done ( ) ;
} )
. catch ( error => {
expect ( error . code ) . toEqual ( 142 ) ;
2019-02-28 16:17:31 -05:00
expect ( error . message ) . toEqual (
'Password cannot contain your username.'
) ;
2018-09-01 13:58:06 -04:00
done ( ) ;
} ) ;
} ) ;
2016-11-17 22:07:51 +05:30
} ) ;
2018-09-01 13:58:06 -04:00
it ( 'signup should succeed if password does not contain the username and is not allowed by policy' , done => {
2016-11-17 22:07:51 +05:30
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
doNotAllowUsername : true ,
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-17 22:07:51 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'r@nd0m' ) ;
2016-11-17 22:07:51 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
done ( ) ;
} )
. catch ( ( ) => {
fail ( 'Should have succeeded as password does not contain username.' ) ;
done ( ) ;
} ) ;
} ) ;
2016-11-17 22:07:51 +05:30
} ) ;
2018-09-01 13:58:06 -04:00
it ( 'signup should succeed if password contains the username and it is allowed by policy' , done => {
2016-11-17 22:07:51 +05:30
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
validatorPattern : /[0-9]+/ ,
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-17 22:07:51 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'user1' ) ;
2016-11-17 22:07:51 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
done ( ) ;
} )
. catch ( ( ) => {
fail ( 'Should have succeeded as policy allows username in password.' ) ;
done ( ) ;
} ) ;
} ) ;
2016-11-17 22:07:51 +05:30
} ) ;
it ( 'should fail to reset password if the new password contains username and not allowed by password policy' , done => {
2016-11-21 21:16:38 +05:30
const user = new Parse . User ( ) ;
const emailAdapter = {
2016-11-17 22:07:51 +05:30
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : options => {
2018-09-24 17:07:51 -04:00
request ( {
url : options . link ,
followRedirects : false ,
simple : false ,
resolveWithFullResponse : true ,
} )
2018-09-01 13:58:06 -04:00
. then ( response => {
2018-09-24 17:07:51 -04:00
expect ( response . status ) . toEqual ( 302 ) ;
2018-09-01 13:58:06 -04:00
const re = /http:\/\/localhost:8378\/1\/apps\/choose_password\?token=([a-zA-Z0-9]+)\&id=test\&username=user1/ ;
2018-09-24 17:07:51 -04:00
const match = response . text . match ( re ) ;
2018-09-01 13:58:06 -04:00
if ( ! match ) {
fail ( 'should have a token' ) ;
2016-11-17 22:07:51 +05:30
done ( ) ;
2018-09-01 13:58:06 -04:00
return ;
}
const token = match [ 1 ] ;
2018-09-24 17:07:51 -04:00
request ( {
method : 'POST' ,
url : 'http://localhost:8378/1/apps/test/request_password_reset' ,
body : ` new_password=xuser12&token= ${ token } &username=user1 ` ,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded' ,
} ,
followRedirects : false ,
simple : false ,
resolveWithFullResponse : true ,
} )
2018-09-01 13:58:06 -04:00
. then ( response => {
2018-09-24 17:07:51 -04:00
expect ( response . status ) . toEqual ( 302 ) ;
expect ( response . text ) . toEqual (
2019-02-28 16:17:31 -05:00
` Found. Redirecting to http://localhost:8378/1/apps/choose_password?username=user1&token= ${ token } &id=test&error=Password%20cannot%20contain%20your%20username.&app=passwordPolicy `
2018-09-01 13:58:06 -04:00
) ;
2016-11-17 22:07:51 +05:30
2018-09-01 13:58:06 -04:00
Parse . User . logIn ( 'user1' , 'r@nd0m' )
. then ( function ( ) {
done ( ) ;
} )
. catch ( err => {
jfail ( err ) ;
fail ( 'should login with old password' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'Failed to POST request password reset' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
2016-11-17 22:07:51 +05:30
jfail ( error ) ;
2018-09-01 13:58:06 -04:00
fail ( 'Failed to get the reset link' ) ;
2016-11-17 22:07:51 +05:30
done ( ) ;
} ) ;
} ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => { } ,
2016-11-21 21:16:38 +05:30
} ;
2016-11-17 22:07:51 +05:30
reconfigureServer ( {
appName : 'passwordPolicy' ,
verifyUserEmails : false ,
emailAdapter : emailAdapter ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
doNotAllowUsername : true ,
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-17 22:07:51 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'r@nd0m' ) ;
2016-11-17 22:07:51 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
Parse . User . requestPasswordReset ( 'user1@parse.com' ) . catch ( err => {
jfail ( err ) ;
fail ( 'Reset password request should not fail' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'signUp should not fail' ) ;
2016-11-21 21:16:38 +05:30
done ( ) ;
2016-11-17 22:07:51 +05:30
} ) ;
} ) ;
} ) ;
2019-03-14 23:06:18 +02:00
it ( 'Should return error when password violates Password Policy and reset through ajax' , async done => {
const user = new Parse . User ( ) ;
const emailAdapter = {
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : async options => {
const response = await request ( {
url : options . link ,
followRedirects : false ,
simple : false ,
resolveWithFullResponse : true ,
} ) ;
expect ( response . status ) . toEqual ( 302 ) ;
const re = /http:\/\/localhost:8378\/1\/apps\/choose_password\?token=([a-zA-Z0-9]+)\&id=test\&username=user1/ ;
const match = response . text . match ( re ) ;
if ( ! match ) {
fail ( 'should have a token' ) ;
return ;
}
const token = match [ 1 ] ;
try {
await request ( {
method : 'POST' ,
url : 'http://localhost:8378/1/apps/test/request_password_reset' ,
body : ` new_password=xuser12&token= ${ token } &username=user1 ` ,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded' ,
'X-Requested-With' : 'XMLHttpRequest' ,
} ,
followRedirects : false ,
} ) ;
} catch ( error ) {
expect ( error . status ) . not . toBe ( 302 ) ;
expect ( error . text ) . toEqual (
'{"code":-1,"error":"Password cannot contain your username."}'
) ;
}
await Parse . User . logIn ( 'user1' , 'r@nd0m' ) ;
done ( ) ;
} ,
sendMail : ( ) => { } ,
} ;
await reconfigureServer ( {
appName : 'passwordPolicy' ,
verifyUserEmails : false ,
emailAdapter : emailAdapter ,
passwordPolicy : {
doNotAllowUsername : true ,
} ,
publicServerURL : 'http://localhost:8378/1' ,
} ) ;
user . setUsername ( 'user1' ) ;
user . setPassword ( 'r@nd0m' ) ;
user . set ( 'email' , 'user1@parse.com' ) ;
await user . signUp ( ) ;
await Parse . User . requestPasswordReset ( 'user1@parse.com' ) ;
} ) ;
2016-11-17 22:07:51 +05:30
it ( 'should reset password even if the new password contains user name while the policy allows' , done => {
2016-11-21 21:16:38 +05:30
const user = new Parse . User ( ) ;
const emailAdapter = {
2016-11-17 22:07:51 +05:30
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : options => {
2018-09-24 17:07:51 -04:00
request ( {
url : options . link ,
followRedirects : false ,
simple : false ,
resolveWithFullResponse : true ,
} )
2018-09-01 13:58:06 -04:00
. then ( response => {
2018-09-24 17:07:51 -04:00
expect ( response . status ) . toEqual ( 302 ) ;
2018-09-01 13:58:06 -04:00
const re = /http:\/\/localhost:8378\/1\/apps\/choose_password\?token=([a-zA-Z0-9]+)\&id=test\&username=user1/ ;
2018-09-24 17:07:51 -04:00
const match = response . text . match ( re ) ;
2018-09-01 13:58:06 -04:00
if ( ! match ) {
fail ( 'should have a token' ) ;
2016-11-17 22:07:51 +05:30
done ( ) ;
2018-09-01 13:58:06 -04:00
return ;
}
const token = match [ 1 ] ;
2018-09-24 17:07:51 -04:00
request ( {
method : 'POST' ,
url : 'http://localhost:8378/1/apps/test/request_password_reset' ,
body : ` new_password=uuser11&token= ${ token } &username=user1 ` ,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded' ,
} ,
followRedirects : false ,
simple : false ,
resolveWithFullResponse : true ,
} )
2018-09-01 13:58:06 -04:00
. then ( response => {
2018-09-24 17:07:51 -04:00
expect ( response . status ) . toEqual ( 302 ) ;
expect ( response . text ) . toEqual (
2018-09-01 13:58:06 -04:00
'Found. Redirecting to http://localhost:8378/1/apps/password_reset_success.html?username=user1'
) ;
2016-11-17 22:07:51 +05:30
2018-09-01 13:58:06 -04:00
Parse . User . logIn ( 'user1' , 'uuser11' )
. then ( function ( ) {
done ( ) ;
} )
. catch ( err => {
jfail ( err ) ;
fail ( 'should login with new password' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'Failed to POST request password reset' ) ;
} ) ;
} )
. catch ( error => {
2016-11-17 22:07:51 +05:30
jfail ( error ) ;
2018-09-01 13:58:06 -04:00
fail ( 'Failed to get the reset link' ) ;
2016-11-17 22:07:51 +05:30
} ) ;
} ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => { } ,
2016-11-21 21:16:38 +05:30
} ;
2016-11-17 22:07:51 +05:30
reconfigureServer ( {
appName : 'passwordPolicy' ,
verifyUserEmails : false ,
emailAdapter : emailAdapter ,
passwordPolicy : {
validatorPattern : /[0-9]+/ ,
2018-09-01 13:58:06 -04:00
doNotAllowUsername : false ,
2016-11-17 22:07:51 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} )
. then ( ( ) => {
user . setUsername ( 'user1' ) ;
user . setPassword ( 'has 1 digit' ) ;
user . set ( 'email' , 'user1@parse.com' ) ;
user . signUp ( ) . then ( ( ) => {
Parse . User . requestPasswordReset ( 'user1@parse.com' ) . catch ( err => {
jfail ( err ) ;
fail ( 'Reset password request should not fail' ) ;
done ( ) ;
} ) ;
2016-11-21 21:16:38 +05:30
} ) ;
2018-09-01 13:58:06 -04:00
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'signUp should not fail' ) ;
done ( ) ;
2016-11-21 21:16:38 +05:30
} ) ;
} ) ;
it ( 'should fail if passwordPolicy.maxPasswordAge is not a number' , done => {
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
maxPasswordAge : 'not a number' ,
2016-11-21 21:16:38 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} )
. then ( ( ) => {
fail ( 'passwordPolicy.maxPasswordAge "not a number" test failed' ) ;
done ( ) ;
} )
. catch ( err => {
expect ( err ) . toEqual (
'passwordPolicy.maxPasswordAge must be a positive number'
) ;
done ( ) ;
} ) ;
2016-11-21 21:16:38 +05:30
} ) ;
it ( 'should fail if passwordPolicy.maxPasswordAge is a negative number' , done => {
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
maxPasswordAge : - 100 ,
2016-11-21 21:16:38 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} )
. then ( ( ) => {
fail ( 'passwordPolicy.maxPasswordAge negative number test failed' ) ;
done ( ) ;
} )
. catch ( err => {
expect ( err ) . toEqual (
'passwordPolicy.maxPasswordAge must be a positive number'
) ;
done ( ) ;
} ) ;
2016-11-21 21:16:38 +05:30
} ) ;
2018-09-01 13:58:06 -04:00
it ( 'should succeed if logged in before password expires' , done => {
2016-11-21 21:16:38 +05:30
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
maxPasswordAge : 1 , // 1 day
2016-11-21 21:16:38 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-21 21:16:38 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'user1' ) ;
2016-11-21 21:16:38 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
Parse . User . logIn ( 'user1' , 'user1' )
. then ( ( ) => {
done ( ) ;
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'Login should have succeeded before password expiry.' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
2016-11-21 21:16:38 +05:30
jfail ( error ) ;
2018-09-01 13:58:06 -04:00
fail ( 'Signup failed.' ) ;
2016-11-21 21:16:38 +05:30
done ( ) ;
} ) ;
2018-09-01 13:58:06 -04:00
} ) ;
2016-11-21 21:16:38 +05:30
} ) ;
2018-09-01 13:58:06 -04:00
it ( 'should fail if logged in after password expires' , done => {
2016-11-21 21:16:38 +05:30
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
maxPasswordAge : 0.5 / ( 24 * 60 * 60 ) , // 0.5 sec
2016-11-21 21:16:38 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-21 21:16:38 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'user1' ) ;
2016-11-21 21:16:38 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
// wait for a bit more than the validity duration set
setTimeout ( ( ) => {
Parse . User . logIn ( 'user1' , 'user1' )
. then ( ( ) => {
fail ( 'logIn should have failed' ) ;
done ( ) ;
} )
. catch ( error => {
expect ( error . code ) . toEqual ( Parse . Error . OBJECT _NOT _FOUND ) ;
expect ( error . message ) . toEqual (
'Your password has expired. Please reset your password.'
) ;
done ( ) ;
} ) ;
} , 1000 ) ;
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'Signup failed.' ) ;
done ( ) ;
} ) ;
2016-11-21 21:16:38 +05:30
} ) ;
} ) ;
2018-09-01 13:58:06 -04:00
it ( 'should apply password expiry policy to existing user upon first login after policy is enabled' , done => {
2016-11-21 21:16:38 +05:30
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-21 21:16:38 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'user1' ) ;
2016-11-21 21:16:38 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
Parse . User . logOut ( )
. then ( ( ) => {
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
maxPasswordAge : 0.5 / ( 24 * 60 * 60 ) , // 0.5 sec
} ,
publicServerURL : 'http://localhost:8378/1' ,
} ) . then ( ( ) => {
Parse . User . logIn ( 'user1' , 'user1' )
. then ( ( ) => {
Parse . User . logOut ( )
. then ( ( ) => {
// wait for a bit more than the validity duration set
setTimeout ( ( ) => {
Parse . User . logIn ( 'user1' , 'user1' )
. then ( ( ) => {
fail ( 'logIn should have failed' ) ;
done ( ) ;
} )
. catch ( error => {
expect ( error . code ) . toEqual (
Parse . Error . OBJECT _NOT _FOUND
) ;
expect ( error . message ) . toEqual (
'Your password has expired. Please reset your password.'
) ;
done ( ) ;
} ) ;
} , 2000 ) ;
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'logout should have succeeded' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'Login failed.' ) ;
2016-11-21 21:16:38 +05:30
done ( ) ;
} ) ;
} ) ;
2018-09-01 13:58:06 -04:00
} )
. catch ( error => {
2016-11-21 21:16:38 +05:30
jfail ( error ) ;
2018-09-01 13:58:06 -04:00
fail ( 'logout should have succeeded' ) ;
2016-11-21 21:16:38 +05:30
done ( ) ;
} ) ;
2018-09-01 13:58:06 -04:00
} )
. catch ( error => {
2016-11-21 21:16:38 +05:30
jfail ( error ) ;
2018-09-01 13:58:06 -04:00
fail ( 'Signup failed.' ) ;
2016-11-21 21:16:38 +05:30
done ( ) ;
} ) ;
} ) ;
} ) ;
it ( 'should reset password timestamp when password is reset' , done => {
const user = new Parse . User ( ) ;
const emailAdapter = {
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : options => {
2018-09-24 17:07:51 -04:00
request ( {
url : options . link ,
followRedirects : false ,
simple : false ,
resolveWithFullResponse : true ,
} )
2018-09-01 13:58:06 -04:00
. then ( response => {
2018-09-24 17:07:51 -04:00
expect ( response . status ) . toEqual ( 302 ) ;
2018-09-01 13:58:06 -04:00
const re = /http:\/\/localhost:8378\/1\/apps\/choose_password\?token=([a-zA-Z0-9]+)\&id=test\&username=user1/ ;
2018-09-24 17:07:51 -04:00
const match = response . text . match ( re ) ;
2018-09-01 13:58:06 -04:00
if ( ! match ) {
fail ( 'should have a token' ) ;
2016-11-21 21:16:38 +05:30
done ( ) ;
2018-09-01 13:58:06 -04:00
return ;
}
const token = match [ 1 ] ;
2018-09-24 17:07:51 -04:00
request ( {
method : 'POST' ,
url : 'http://localhost:8378/1/apps/test/request_password_reset' ,
body : ` new_password=uuser11&token= ${ token } &username=user1 ` ,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded' ,
} ,
followRedirects : false ,
simple : false ,
resolveWithFullResponse : true ,
} )
2018-09-01 13:58:06 -04:00
. then ( response => {
2018-09-24 17:07:51 -04:00
expect ( response . status ) . toEqual ( 302 ) ;
expect ( response . text ) . toEqual (
2018-09-01 13:58:06 -04:00
'Found. Redirecting to http://localhost:8378/1/apps/password_reset_success.html?username=user1'
) ;
Parse . User . logIn ( 'user1' , 'uuser11' )
. then ( function ( ) {
done ( ) ;
} )
. catch ( err => {
jfail ( err ) ;
fail ( 'should login with new password' ) ;
done ( ) ;
} ) ;
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'Failed to POST request password reset' ) ;
} ) ;
} )
. catch ( error => {
2016-11-21 21:16:38 +05:30
jfail ( error ) ;
2018-09-01 13:58:06 -04:00
fail ( 'Failed to get the reset link' ) ;
2016-11-21 21:16:38 +05:30
} ) ;
} ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => { } ,
2016-11-21 21:16:38 +05:30
} ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
emailAdapter : emailAdapter ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
maxPasswordAge : 0.5 / ( 24 * 60 * 60 ) , // 0.5 sec
2016-11-21 21:16:38 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-21 21:16:38 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'user1' ) ;
2016-11-21 21:16:38 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
// wait for a bit more than the validity duration set
setTimeout ( ( ) => {
Parse . User . logIn ( 'user1' , 'user1' )
. then ( ( ) => {
fail ( 'logIn should have failed' ) ;
done ( ) ;
} )
. catch ( error => {
expect ( error . code ) . toEqual ( Parse . Error . OBJECT _NOT _FOUND ) ;
expect ( error . message ) . toEqual (
'Your password has expired. Please reset your password.'
) ;
Parse . User . requestPasswordReset ( 'user1@parse.com' ) . catch (
err => {
jfail ( err ) ;
fail ( 'Reset password request should not fail' ) ;
done ( ) ;
}
) ;
} ) ;
} , 1000 ) ;
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'Signup failed.' ) ;
done ( ) ;
} ) ;
2016-11-17 22:07:51 +05:30
} ) ;
} ) ;
2016-11-29 22:31:52 +05:30
it ( 'should fail if passwordPolicy.maxPasswordHistory is not a number' , done => {
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
maxPasswordHistory : 'not a number' ,
2016-11-29 22:31:52 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} )
. then ( ( ) => {
fail ( 'passwordPolicy.maxPasswordHistory "not a number" test failed' ) ;
done ( ) ;
} )
. catch ( err => {
expect ( err ) . toEqual (
'passwordPolicy.maxPasswordHistory must be an integer ranging 0 - 20'
) ;
done ( ) ;
} ) ;
2016-11-29 22:31:52 +05:30
} ) ;
it ( 'should fail if passwordPolicy.maxPasswordHistory is a negative number' , done => {
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
maxPasswordHistory : - 10 ,
2016-11-29 22:31:52 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} )
. then ( ( ) => {
fail ( 'passwordPolicy.maxPasswordHistory negative number test failed' ) ;
done ( ) ;
} )
. catch ( err => {
expect ( err ) . toEqual (
'passwordPolicy.maxPasswordHistory must be an integer ranging 0 - 20'
) ;
done ( ) ;
} ) ;
2016-11-29 22:31:52 +05:30
} ) ;
it ( 'should fail if passwordPolicy.maxPasswordHistory is greater than 20' , done => {
reconfigureServer ( {
appName : 'passwordPolicy' ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
maxPasswordHistory : 21 ,
2016-11-29 22:31:52 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
} )
. then ( ( ) => {
fail ( 'passwordPolicy.maxPasswordHistory negative number test failed' ) ;
done ( ) ;
} )
. catch ( err => {
expect ( err ) . toEqual (
'passwordPolicy.maxPasswordHistory must be an integer ranging 0 - 20'
) ;
done ( ) ;
} ) ;
2016-11-29 22:31:52 +05:30
} ) ;
it ( 'should fail to reset if the new password is same as the last password' , done => {
const user = new Parse . User ( ) ;
const emailAdapter = {
sendVerificationEmail : ( ) => Promise . resolve ( ) ,
sendPasswordResetEmail : options => {
2018-09-24 17:07:51 -04:00
request ( {
url : options . link ,
followRedirects : false ,
} )
2018-09-01 13:58:06 -04:00
. then ( response => {
2018-09-24 17:07:51 -04:00
expect ( response . status ) . toEqual ( 302 ) ;
2018-09-01 13:58:06 -04:00
const re = /http:\/\/localhost:8378\/1\/apps\/choose_password\?token=([a-zA-Z0-9]+)\&id=test\&username=user1/ ;
2018-09-24 17:07:51 -04:00
const match = response . text . match ( re ) ;
2018-09-01 13:58:06 -04:00
if ( ! match ) {
fail ( 'should have a token' ) ;
return Promise . reject ( 'Invalid password link' ) ;
}
return Promise . resolve ( match [ 1 ] ) ; // token
} )
. then ( token => {
2018-09-24 17:07:51 -04:00
return request ( {
method : 'POST' ,
url : 'http://localhost:8378/1/apps/test/request_password_reset' ,
body : ` new_password=user1&token= ${ token } &username=user1 ` ,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded' ,
} ,
followRedirects : false ,
simple : false ,
resolveWithFullResponse : true ,
} ) . then ( response => {
return [ response , token ] ;
2016-11-29 22:31:52 +05:30
} ) ;
2018-09-01 13:58:06 -04:00
} )
. then ( data => {
const response = data [ 0 ] ;
const token = data [ 1 ] ;
2018-09-24 17:07:51 -04:00
expect ( response . status ) . toEqual ( 302 ) ;
expect ( response . text ) . toEqual (
2018-09-01 13:58:06 -04:00
` Found. Redirecting to http://localhost:8378/1/apps/choose_password?username=user1&token= ${ token } &id=test&error=New%20password%20should%20not%20be%20the%20same%20as%20last%201%20passwords.&app=passwordPolicy `
) ;
done ( ) ;
return Promise . resolve ( ) ;
} )
. catch ( error => {
2018-09-24 17:07:51 -04:00
fail ( error ) ;
2018-09-01 13:58:06 -04:00
fail ( 'Repeat password test failed' ) ;
done ( ) ;
2016-11-29 22:31:52 +05:30
} ) ;
} ,
2018-09-01 13:58:06 -04:00
sendMail : ( ) => { } ,
2016-11-29 22:31:52 +05:30
} ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
verifyUserEmails : false ,
emailAdapter : emailAdapter ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
maxPasswordHistory : 1 ,
2016-11-29 22:31:52 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-29 22:31:52 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'user1' ) ;
2016-11-29 22:31:52 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
return Parse . User . logOut ( ) ;
} )
. then ( ( ) => {
return Parse . User . requestPasswordReset ( 'user1@parse.com' ) ;
} )
. catch ( error => {
jfail ( error ) ;
fail ( 'SignUp or reset request failed' ) ;
done ( ) ;
} ) ;
2016-11-29 22:31:52 +05:30
} ) ;
} ) ;
it ( 'should fail if the new password is same as the previous one' , done => {
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
verifyUserEmails : false ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
maxPasswordHistory : 5 ,
2016-11-29 22:31:52 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-29 22:31:52 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'user1' ) ;
2016-11-29 22:31:52 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
// try to set the same password as the previous one
user . setPassword ( 'user1' ) ;
return user . save ( ) ;
} )
. then ( ( ) => {
fail (
'should have failed because the new password is same as the old'
) ;
done ( ) ;
} )
. catch ( error => {
expect ( error . message ) . toEqual (
'New password should not be the same as last 5 passwords.'
) ;
expect ( error . code ) . toEqual ( Parse . Error . VALIDATION _ERROR ) ;
done ( ) ;
} ) ;
2016-11-29 22:31:52 +05:30
} ) ;
} ) ;
it ( 'should fail if the new password is same as the 5th oldest one and policy does not allow the previous 5' , done => {
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
verifyUserEmails : false ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
maxPasswordHistory : 5 ,
2016-11-29 22:31:52 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-29 22:31:52 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'user1' ) ;
2016-11-29 22:31:52 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
// build history
user . setPassword ( 'user2' ) ;
return user . save ( ) ;
} )
. then ( ( ) => {
user . setPassword ( 'user3' ) ;
return user . save ( ) ;
} )
. then ( ( ) => {
user . setPassword ( 'user4' ) ;
return user . save ( ) ;
} )
. then ( ( ) => {
user . setPassword ( 'user5' ) ;
return user . save ( ) ;
} )
. then ( ( ) => {
// set the same password as the initial one
user . setPassword ( 'user1' ) ;
return user . save ( ) ;
} )
. then ( ( ) => {
fail (
'should have failed because the new password is same as the old'
) ;
done ( ) ;
} )
. catch ( error => {
expect ( error . message ) . toEqual (
'New password should not be the same as last 5 passwords.'
) ;
expect ( error . code ) . toEqual ( Parse . Error . VALIDATION _ERROR ) ;
done ( ) ;
} ) ;
2016-11-29 22:31:52 +05:30
} ) ;
} ) ;
it ( 'should succeed if the new password is same as the 6th oldest one and policy does not allow only previous 5' , done => {
const user = new Parse . User ( ) ;
reconfigureServer ( {
appName : 'passwordPolicy' ,
verifyUserEmails : false ,
passwordPolicy : {
2018-09-01 13:58:06 -04:00
maxPasswordHistory : 5 ,
2016-11-29 22:31:52 +05:30
} ,
2018-09-01 13:58:06 -04:00
publicServerURL : 'http://localhost:8378/1' ,
2016-11-29 22:31:52 +05:30
} ) . then ( ( ) => {
2018-09-01 13:58:06 -04:00
user . setUsername ( 'user1' ) ;
user . setPassword ( 'user1' ) ;
2016-11-29 22:31:52 +05:30
user . set ( 'email' , 'user1@parse.com' ) ;
2018-09-01 13:58:06 -04:00
user
. signUp ( )
. then ( ( ) => {
// build history
user . setPassword ( 'user2' ) ;
return user . save ( ) ;
} )
. then ( ( ) => {
user . setPassword ( 'user3' ) ;
return user . save ( ) ;
} )
. then ( ( ) => {
user . setPassword ( 'user4' ) ;
return user . save ( ) ;
} )
. then ( ( ) => {
user . setPassword ( 'user5' ) ;
return user . save ( ) ;
} )
. then ( ( ) => {
user . setPassword ( 'user6' ) ; // this pushes initial password out of history
return user . save ( ) ;
} )
. then ( ( ) => {
// set the same password as the initial one
user . setPassword ( 'user1' ) ;
return user . save ( ) ;
} )
. then ( ( ) => {
done ( ) ;
} )
. catch ( ( ) => {
fail (
'should have succeeded because the new password is not in history'
) ;
done ( ) ;
} ) ;
2016-11-29 22:31:52 +05:30
} ) ;
} ) ;
2019-04-10 22:57:09 +05:45
it ( 'should not infinitely loop if maxPasswordHistory is 1 (#4918)' , async ( ) => {
const user = new Parse . User ( ) ;
const query = new Parse . Query ( Parse . User ) ;
await reconfigureServer ( {
appName : 'passwordPolicy' ,
verifyUserEmails : false ,
passwordPolicy : {
maxPasswordHistory : 1 ,
} ,
publicServerURL : 'http://localhost:8378/1' ,
} ) ;
user . setUsername ( 'user1' ) ;
user . setPassword ( 'user1' ) ;
user . set ( 'email' , 'user1@parse.com' ) ;
await user . signUp ( ) ;
user . setPassword ( 'user2' ) ;
await user . save ( ) ;
const result1 = await query . get ( user . id , { useMasterKey : true } ) ;
expect ( result1 . get ( '_password_history' ) . length ) . toBe ( 1 ) ;
user . setPassword ( 'user3' ) ;
await user . save ( ) ;
const result2 = await query . get ( user . id , { useMasterKey : true } ) ;
expect ( result2 . get ( '_password_history' ) . length ) . toBe ( 1 ) ;
expect ( result1 . get ( '_password_history' ) ) . not . toEqual (
result2 . get ( '_password_history' )
) ;
} ) ;
2018-09-01 13:58:06 -04:00
} ) ;