Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Bug 531495 - Node server does not forbid certain characters from user…
… names
  • Loading branch information
mrennie committed Feb 22, 2018
1 parent 04a33bd commit fb8ef36
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 45 deletions.
23 changes: 23 additions & 0 deletions modules/orionode/lib/api.js
Expand Up @@ -249,6 +249,29 @@ function isValidProjectName(fileName) {
});
return !result;
}
const ILOD_UNICODE_REGEX = /[^\u{0000}-\u{001F}\u{2000}-\u{206F}]/u;
/**
* Checks if the given character if a letter or a digit.
* Any letter of digit from ASCII is true, and any character that is not part of the follow tables is true:
* - General Punctuation
* - Control Character
* @param {string} char The character to check
* @returns {bool} True if the char is a letter or digit, as defined above
* @since 18.0
*/
exports.isLetterOrDigit = function isLetterOrDigit(char) {
const code = char.charCodeAt(0);
if(code < 48 || (code > 57 && code < 65) || (code > 90 && code < 97) || (code > 122 && code < 128)) {
return false;
}
if(code <= 255) { // extended ascii
return true;
}
if(ILOD_UNICODE_REGEX.test(char)) { //unicode
return true;
}
return false;
}

/**
* @name logAccess
Expand Down
24 changes: 21 additions & 3 deletions modules/orionode/lib/user.js
Expand Up @@ -522,15 +522,33 @@ module.exports.router = function router(options) {

app.post('/users', options.CSRF, options.authenticate, function(req, res) {
// If there are admin accounts, only admin accounts can create users
if (options.configParams.get("orion.auth.user.creation")) {
const admins = options.configParams.get("orion.auth.user.creation");
if (typeof admins === 'string' && admins.length > 0) {
if(!isAdmin(options, req.user && req.user.username)) {
return api.writeResponse(403, res);
}
}
const uname = req.body.UserName;
if(typeof uname === 'string') {
if(!!options.configParams.get('orion.auth.disable.account.rules')) {
if(uname.length < 3) {
return api.writeResponse(400, res, null, {Message: "User name must be 3 characters or longer"});
}
if(uname.length > 20) {
return api.writeResponse(400, res, null, {Message: "User name must be 20 characters or shorter"});
}
}
for (let i = 0, len = uname.length; i < len; i++) {
const c = uname.charAt(i);
if(!api.isLetterOrDigit(c)) {
return api.writeResponse(400, res, null, {Message: "Invalid character in user name: "+c});
}
}
} else {
return api.writeResponse(400, res);
return api.writeResponse(400, res, null, {Message: "Invalid user name for new user"});
}
const userData = {
username: req.body.UserName,
username: uname,
email: req.body.Email,
fullname: req.body.FullName,
oauth: req.body.identifier,
Expand Down
111 changes: 69 additions & 42 deletions modules/orionode/test/endpoints/test-users.js
Expand Up @@ -41,7 +41,6 @@ function createUser(request, data) {
* These test are all skipped until we have proper authentication support
*/
describe("Users endpoint", function() {
it("testCreateDeleteRights");
describe("Single user mode", function() {
beforeEach(function(done) { // testData.setUp.bind(null, parentDir)
testData.setUp(WORKSPACE, function() {
Expand All @@ -50,8 +49,8 @@ describe("Users endpoint", function() {
});
afterEach("Remove .test_workspace", function(done) {
testData.tearDown(testHelper.WORKSPACE, function(){
testData.tearDown(path.join(METADATA, '.orion'), function(){
testData.tearDown(METADATA, done)
testData.tearDown(path.join(testHelper.METADATA, '.orion'), function(){
testData.tearDown(testHelper.METADATA, done)
})
});
});
Expand Down Expand Up @@ -290,8 +289,11 @@ describe("Users endpoint", function() {
"orion.single.user": false
});
});
after("Reset to default server state", function() {
after("Reset to default server state", function(done) {
request = testData.setupOrionServer({});
testData.tearDown(testHelper.WORKSPACE, function() {
done();
});
});
it("testGetUsers", function(done) {
request()
Expand Down Expand Up @@ -364,14 +366,14 @@ describe("Users endpoint", function() {
.post(CONTEXT_PATH + '/users')
.set('Orion-Version', 1)
.send({Password: "pw", FullName: "user1", Email: "user1@email.ca", UserName: "user1"})
.expect(400, done);
.expect(201, done);
});
it("testPostUsers - trailing slash", function(done) {
request()
.post(CONTEXT_PATH + '/users/')
.set('Orion-Version', 1)
.send({Password: "pw", FullName: "user1", Email: "user1@email.ca", UserName: "user1"})
.expect(400, done);
.expect(404, done);
});
it("testDeleteUser - anonymous", function(done) {
request()
Expand Down Expand Up @@ -414,7 +416,7 @@ describe("Users endpoint", function() {
request()
.post(CONTEXT_PATH + '/users')
.send(json)
.expect(400, done);
.expect(201, done);
});
it("testCreateUserWithNoUserName", function(done) {
var json = {Email: 'testCreateDuplicateUser@bar.org', FullName: "testCreateDuplicateUser Bar", Password: "1234"};
Expand All @@ -428,83 +430,108 @@ describe("Users endpoint", function() {
request()
.post(CONTEXT_PATH + '/users')
.send(json)
.expect(400, done);
.expect(201, done);
});
it("testCreateUserDuplicateEmail", function(done) {
var json = {UserName: "testCreateUserDuplicateEmail", Email: 'testCreateUserDuplicateEmail@bar.org', FullName: "testCreateUserDuplicateEmail Bar", Password: "1234"};
request()
.post(CONTEXT_PATH + '/users')
.send(json)
.expect(400, done);
.expect(201, done);
});
it("testCreateUserEmailDifferentCase", function(done) {
var json = {UserName: "testCreateUserEmailDifferentCase", Email: 'testCreateUserEmailDifferentCase@bar.org', FullName: "testCreateUserEmailDifferentCase Bar", Password: "1234"};
request()
.post(CONTEXT_PATH + '/users')
.send(json)
.expect(400, done);
});
it("testCreateUserInvalidName", function(done) {
var json = {UserName: "foo", Email: 'foo@bar.org', FullName: "Foo Bar", Password: "1234"};
var badChars = " !@#$%^&*()-=_+[]{}\";':\\/><.,`~";
for(var i = 0, len = badChars.length; i < len; i++) {
json.UserName = "bad" + badChars.charAt(i) + "name";
request()
.post(CONTEXT_PATH + '/users')
.send(json)
.expect(400)
.end(function(err, res) {
testHelper.throwIfError(err);
});
if(i === len-1) {
done();
}
}
.expect(201, done);
});
it("testCreateDeleteUsers", function(done) {
var json = {UserName: "testCreateDeleteUsers", Email: 'testCreateDeleteUsers@bar.org', FullName: "testCreateDeleteUsers Bar", Password: "1234"};
request()
.post(CONTEXT_PATH + '/users')
.send(json)
.expect(400, done);
});
/**
* TODO we currently don't have a unique ID implementation in the node server
*/
it("testDeleteUserByUniqueIdProperty", function(done) {
var json = {UserName: "testDeleteUserByUniqueIdProperty", Email: 'testDeleteUserByUniqueIdProperty@bar.org', FullName: "testDeleteUserByUniqueIdProperty Bar", Password: "1234"};
request()
.post(CONTEXT_PATH + '/users')
.send(json)
.expect(400, done);
.expect(201)
.end(function(err, res) {
testHelper.throwIfError(err);
request()
.delete(CONTEXT_PATH + '/users/testCreateDeleteUsers')
.expect(403, done) //TODO what to do in single user mode?
});
});
it("testUpdateUsers", function(done) {
var json = {UserName: "testUpdateUsers", Email: 'testUpdateUsers@bar.org', FullName: "testUpdateUsers Bar", Password: "1234"};
request()
.post(CONTEXT_PATH + '/users')
.send(json)
.expect(400, done);
.expect(201)
.end(function(err, res) {
testHelper.throwIfError(err);
done();
});
});
it("testResetUser", function(done) {
var json = {roles: "admin", UserName: "testResetUser", Email: 'testResetUser@bar.org', FullName: "testResetUser Bar", Password: "1234"};
request()
.post(CONTEXT_PATH + '/users')
.send(json)
.expect(400, done);
.expect(201)
.end(function(err, res) {
testHelper.throwIfError(err);
done();
});
});
it("testCreateUser", function(done) {
var json = {UserName: "testCreateUser", Email: 'testCreateUser@bar.org', FullName: "testCreateUser Bar", Password: "1234"};
request()
.post(CONTEXT_PATH + '/users')
.send(json)
.expect(400, done);
.expect(201)
.end(function(err, res) {
testHelper.throwIfError(err);
done();
});
});
it("testChangeUserName", function(done) {
var json = {UserName: "testChangeUserName", Email: 'testChangeUserName@bar.org', FullName: "testChangeUserName Bar", Password: "1234"};
request()
.post(CONTEXT_PATH + '/users')
.send(json)
.expect(400, done);
.expect(201)
.end(function(err, res) {
testHelper.throwIfError(err);
done();
});
});
describe("Create users with invalid user names", function() {
Array.from(" !@#$%^&*()-=_+[]{}\";':\\/><.,`~|\u001C\u204B").forEach(function(c) {
const uname = "bad" + c + "name";
it("testCreateUserBadName: "+uname, function(done) {
request()
.post(CONTEXT_PATH + '/users')
.send({
UserName: uname,
Email: 'emailz',
FullName: "Bad"+c,
Password: "1234"})
.expect(400, done);
});
});
});
describe("Create users with allowed UNICODE user names", function() {
Array.from("\u225B\u1F707\u11ACB").forEach(function(c) {
const uname = "good" + c + "name";
it("testCreateUserBadName: "+uname, function(done) {
request()
.post(CONTEXT_PATH + '/users')
.send({
UserName: uname,
Email: 'emailz',
FullName: "Good"+c,
Password: "1234"})
.expect(201, done);
});
});
});
});
});

0 comments on commit fb8ef36

Please sign in to comment.