Adds password history support to passwordPolicy (#3102)

* password history support in passwordPolicy

* Refactor RestWrite.transformUser

* fix eslint issues
This commit is contained in:
Bhaskar Reddy Yasa
2016-11-29 22:31:52 +05:30
committed by Diwakar Cherukumilli
parent 08bac9f790
commit bd1689190f
7 changed files with 415 additions and 96 deletions

View File

@@ -1010,4 +1010,242 @@ describe("Password Policy: ", () => {
});
});
it('should fail if passwordPolicy.maxPasswordHistory is not a number', done => {
reconfigureServer({
appName: 'passwordPolicy',
passwordPolicy: {
maxPasswordHistory: "not a number"
},
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();
});
});
it('should fail if passwordPolicy.maxPasswordHistory is a negative number', done => {
reconfigureServer({
appName: 'passwordPolicy',
passwordPolicy: {
maxPasswordHistory: -10
},
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();
});
});
it('should fail if passwordPolicy.maxPasswordHistory is greater than 20', done => {
reconfigureServer({
appName: 'passwordPolicy',
passwordPolicy: {
maxPasswordHistory: 21
},
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();
});
});
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 => {
requestp.get({
uri: options.link,
followRedirect: false,
simple: false,
resolveWithFullResponse: true
}).then(response => {
expect(response.statusCode).toEqual(302);
const re = /http:\/\/localhost:8378\/1\/apps\/choose_password\?token=([a-zA-Z0-9]+)\&id=test\&username=user1/;
const match = response.body.match(re);
if (!match) {
fail("should have a token");
return Promise.reject("Invalid password link");
}
return Promise.resolve(match[1]); // token
}).then(token => {
return new Promise((resolve, reject) => {
requestp.post({
uri: "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'
},
followRedirect: false,
simple: false,
resolveWithFullResponse: true
}).then(response => {
resolve([response, token]);
}).catch(error => {
reject(error);
});
});
}).then(data => {
const response = data[0];
const token = data[1];
expect(response.statusCode).toEqual(302);
expect(response.body).toEqual(`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 => {
jfail(error);
fail("Repeat password test failed");
done();
});
},
sendMail: () => {
}
};
reconfigureServer({
appName: 'passwordPolicy',
verifyUserEmails: false,
emailAdapter: emailAdapter,
passwordPolicy: {
maxPasswordHistory: 1
},
publicServerURL: "http://localhost:8378/1"
}).then(() => {
user.setUsername("user1");
user.setPassword("user1");
user.set('email', 'user1@parse.com');
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();
});
});
});
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: {
maxPasswordHistory: 5
},
publicServerURL: "http://localhost:8378/1"
}).then(() => {
user.setUsername("user1");
user.setPassword("user1");
user.set('email', 'user1@parse.com');
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();
});
});
});
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: {
maxPasswordHistory: 5
},
publicServerURL: "http://localhost:8378/1"
}).then(() => {
user.setUsername("user1");
user.setPassword("user1");
user.set('email', 'user1@parse.com');
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();
});
});
});
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: {
maxPasswordHistory: 5
},
publicServerURL: "http://localhost:8378/1"
}).then(() => {
user.setUsername("user1");
user.setPassword("user1");
user.set('email', 'user1@parse.com');
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();
});
});
});
})