From 51946da4ad5858bea31e5f645a4fb9ebad9e81bf Mon Sep 17 00:00:00 2001 From: Matthew Kleiman Date: Mon, 19 May 2014 15:20:19 -0400 Subject: [PATCH 1/5] fixed typo var error object was being created in a few places but the function was returning err instead of error. --- lib/user.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/user.js b/lib/user.js index 4de610f..647cd5a 100644 --- a/lib/user.js +++ b/lib/user.js @@ -44,7 +44,7 @@ module.exports.create = function (firstname, lastname, displayname, email, usern else { var error = new Error("Invalid Response from Atlassian Crowd"); error.type = "INVALID_RESPONSE"; - return callback(err); + return callback(error); } } }); @@ -60,7 +60,7 @@ module.exports.remove = function (username, callback) { _doRequest(options, function(err, res) { if(err) { return callback(err); - } + } else { if(res === 204) { return callback(null); @@ -68,7 +68,7 @@ module.exports.remove = function (username, callback) { else { var error = new Error("Invalid Response from Atlassian Crowd"); error.type = "INVALID_RESPONSE"; - return callback(err); + return callback(error); } } }); @@ -91,7 +91,7 @@ module.exports.changepassword = function (username, password, callback) { module.exports.active = function (username, callback) { this.find(username, function (err, res) { if(err) { - return callback(err); + return callback(err); } else { if(res.active.toString() === "true") { From 054ed8d6f0da04eb11af7e715eae22fe542cfd21 Mon Sep 17 00:00:00 2001 From: Matthew Kleiman Date: Thu, 22 May 2014 17:17:02 -0400 Subject: [PATCH 2/5] provide statusCode from original Crowd response to Error object when an error occurred This statusCode is useful to determine the nature of the response from Crowd. Crowd's REST api provides precise mappings from the HTTP status code to a meaning at https://developer.atlassian.com/display/CROWDDEV/Crowd+REST+Resources --- lib/index.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/index.js b/lib/index.js index c438686..913bf85 100644 --- a/lib/index.js +++ b/lib/index.js @@ -32,7 +32,7 @@ function AtlassianCrowd(options) { settings.authstring = settings.application.name + ":" + settings.application.password; - if(!settings.port) { + if(!settings.port) { settings.port = (uri.port) ? uri.port : (uri.protocol === "https:") ? 443 : 80; } } @@ -93,7 +93,7 @@ _doRequest = function (options, callback) { error = new Error("Missing POST Data"); error.type = "BAD_REQUEST"; return callback(error); - } + } } else { if(options.method === "DELETE") { @@ -109,7 +109,7 @@ _doRequest = function (options, callback) { response.on('data', function(chunk) { data += chunk.toString(); }); - + if(response.statusCode === 204) { return callback(null, response.statusCode); } @@ -117,12 +117,14 @@ _doRequest = function (options, callback) { if(response.statusCode === 401) { error = new Error("Application Authorization Error"); error.type = "APPLICATION_ACCESS_DENIED"; + error.statusCode = response.statusCode; return callback(error); } if(response.statusCode === 403) { error = new Error("Application Permission Denied"); error.type = "APPLICATION_PERMISSION_DENIED"; + error.statusCode = response.statusCode; return callback(error); } @@ -130,6 +132,7 @@ _doRequest = function (options, callback) { if (response.headers['content-type'] !== "application/json") { error = new Error("Invalid Response from Atlassian Crowd"); error.type = "INVALID_RESPONSE"; + error.statusCode = response.statusCode; return callback(error); } else { @@ -142,6 +145,7 @@ _doRequest = function (options, callback) { } error = new Error(data.message); error.type = data.reason; + error.statusCode = response.statusCode; return callback(error); } else { From 4a1fe9c67f3538d513b785dacb827b0de75cbeb8 Mon Sep 17 00:00:00 2001 From: Matthew Kleiman Date: Tue, 2 Dec 2014 17:12:52 -0500 Subject: [PATCH 3/5] propogate Crowd response and headers to clients --- lib/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/index.js b/lib/index.js index 913bf85..66d0251 100644 --- a/lib/index.js +++ b/lib/index.js @@ -133,6 +133,8 @@ _doRequest = function (options, callback) { error = new Error("Invalid Response from Atlassian Crowd"); error.type = "INVALID_RESPONSE"; error.statusCode = response.statusCode; + error.res = response; + error.headers = response.headers; return callback(error); } else { From 394cc8b5bb0a3ec9bc83ee0d88aba0d34b6c799e Mon Sep 17 00:00:00 2001 From: Matthew Kleiman Date: Tue, 2 Dec 2014 17:13:30 -0500 Subject: [PATCH 4/5] added findWithAttributes and attribute endpoints --- lib/user.js | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/lib/user.js b/lib/user.js index 647cd5a..9fd1bb8 100644 --- a/lib/user.js +++ b/lib/user.js @@ -14,6 +14,102 @@ module.exports.find = function (username, callback) { }); }; +module.exports.findWithAttributes = function (username, callback) { + var options = { + method: "GET", + path: "/user?username=" + username + "&expand=attributes" + }; + + _doRequest(options, function(err, res) { + if(err) { + callback(err); + } + else { + callback(null, res); + } + }); +}; + +module.exports.getAttributes = function (username, callback) { + var options = { + method: "GET", + path: "/user/attribute?username=" + username + }; + + _doRequest(options, function(err, res) { + if(err) { + callback(err); + } + else { + callback(null, res); + } + }); +}; + +module.exports.postAttributes = function (username, attributes, callback) { + // attributes param should be an array of json objects with following format: + // { + // "name" : "attributeName", + // "values" : [ "arrayOfArbitraryValues" ] + // } + var payload = { + "attributes": attributes + }; + + var options = { + "method": "POST", + "data": JSON.stringify(payload), + "path": "/user/attribute?username=" + username + }; + + _doRequest(options, function(err, res) { + if (err) { + return callback(err); + } else { + var error; + if (res === 204) { + return callback(null); + } if (res === 404) { + error = new Error("User could not be found in Crowd"); + error.type = "NOT_FOUND"; + return callback(error); + } else { + error = new Error("Invalid Response from Atlassian Crowd"); + error.type = "INVALID_RESPONSE"; + return callback(error); + } + } + }); +}; + +module.exports.deleteAttribute = function (username, attributeName, callback) { + + console.log(username, attributeName); + var options = { + method: "DELETE", + path: "/user/attribute?username=" + username + "&attributename=" + attributeName + }; + + _doRequest(options, function(err, res) { + if (err) { + return callback(err); + } else { + var error; + if (res === 204) { + return callback(null); + } if (res === 404) { + error = new Error("User or Attribute could not be found in Crowd"); + error.type = "NOT_FOUND"; + return callback(error); + } else { + error = new Error("Invalid Response from Atlassian Crowd"); + error.type = "INVALID_RESPONSE"; + return callback(error); + } + } + }); +}; + module.exports.create = function (firstname, lastname, displayname, email, username, password, callback) { var payload = { "name": username, From 14182fc8339e43d2ace41f4a2ff33317883498da Mon Sep 17 00:00:00 2001 From: Matthew Kleiman Date: Tue, 2 Dec 2014 17:22:29 -0500 Subject: [PATCH 5/5] documented new endpoints --- README.md | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bd3d96f..a739b53 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ crowd.search('group', 'name="*test*"', function (err, res) { Here you can find utilities for Managing, Creating, Removing, Users as well as Changing Passwords, and Basic Authentication (NON SSO). #### Finding a User by Username #### -user.find(userrname, callback) +user.find(username, callback) * username String * callback Function (err, res) @@ -103,6 +103,22 @@ crowd.user.find('user', function(err, res) { } }); ``` +#### Finding a User by Username (and return user's attributes) #### +user.findWithAttributes(username, callback) + +* username String +* callback Function (err, res) + +```javascript +crowd.user.findWithAttributes('user', function(err, res) { + if(err) { + throw err; + } + else { + console.log(res); + } +}); +``` #### Checking if User is Active #### user.active(username, callback) @@ -177,6 +193,63 @@ crowd.user.groups('testuser', function (err, res) { }); ``` +#### List a User's Attributes #### +user.getAttributes(username, callback) + +* username String +* callback Function (err, res) + +```javascript +crowd.user.getAttributes('user', function(err, res) { + if(err) { + throw err; + } + else { + console.log(res); + } +}); +``` + +#### Modify/Add User Attributes #### +user.postAttributes(username, attributes, callback) + +* username String +* attributes array of objects in the format: +* { +* "name" : "attributeName", +* "values" : [ "arrayOfArbitraryValues" ] +* } +* callback Function (err, res) + +```javascript +crowd.user.postAttributes('user', arrayOfAttributes, function(err, res) { + if(err) { + throw err; + } + else { + console.log(res); + } +}); +``` + +#### Delete a User's Attribute #### +user.deleteAttributes(username, attributeName, callback) + +* username String +* attributeName String +* callback Function (err, res) + +```javascript +crowd.user.deleteAttributes('user', 'attribute-name', function(err, res) { + if(err) { + throw err; + } + else { + console.log(res); + } +}); +``` + #### User Authentication (NON SSO) #### user.authenticate(username, password, callback)