Implemented authenticateUser() and currentUser state for client
diff --git a/helpers/index.js b/helpers/index.js
index ac7d678..6ab2b35 100644
--- a/helpers/index.js
+++ b/helpers/index.js
@@ -4,6 +4,7 @@
userAgent = require('./userAgent'),
query = require('./query'),
config = require('./config'),
+ time = require('./time'),
_ = require('lodash')
module.exports = _.assign(module.exports, {
@@ -11,5 +12,6 @@
build: build,
userAgent: userAgent,
query: query,
- config: config
+ config: config,
+ time: time
}, mutability)
\ No newline at end of file
diff --git a/helpers/time.js b/helpers/time.js
new file mode 100644
index 0000000..06e8d84
--- /dev/null
+++ b/helpers/time.js
@@ -0,0 +1,7 @@
+'use strict'
+
+module.exports = {
+ expiry: function(expires_in) {
+ return Date.now() + ((expires_in ? expires_in - 5 : 0) * 1000)
+ }
+}
\ No newline at end of file
diff --git a/lib/appAuth.js b/lib/appAuth.js
index 335c90e..00574c1 100644
--- a/lib/appAuth.js
+++ b/lib/appAuth.js
@@ -11,6 +11,7 @@
if (typeof args[0] === 'object') {
args = args[0]
}
+
self.clientId = args.clientId || args[0]
self.clientSecret = args.clientSecret || args[1]
self.tokenTtl = args.tokenTtl || args[2]
diff --git a/lib/client.js b/lib/client.js
index 3c37010..611bda3 100644
--- a/lib/client.js
+++ b/lib/client.js
@@ -3,8 +3,9 @@
var UsergridRequest = require('./request'),
request = require('request'),
helpers = require('../helpers'),
- config = helpers.config,
UsergridAppAuth = require('./appAuth'),
+ UsergridUserAuth = require('./userAuth'),
+ UsergridUser = require('./user'),
_ = require('lodash')
var AuthFallback = {
@@ -30,7 +31,7 @@
self.appId = arguments[1]
}
- _.defaults(self, options, config, defaultOptions)
+ _.defaults(self, options, helpers.config, defaultOptions)
if (!self.orgId || !self.appId) {
throw new Error('"orgId" and "appId" parameters are required when instantiating UsergridClient')
@@ -43,7 +44,7 @@
set: function(options) {
if (options instanceof UsergridAppAuth) {
__appAuth = options
- } else {
+ } else if (options !== undefined) {
__appAuth = new UsergridAppAuth(options)
}
}
@@ -74,14 +75,14 @@
var self = this
callback = helpers.cb(callback || options)
- options.clientId = options.clientId || self.appAuth.clientId
- options.clientSecret = options.clientSecret || self.appAuth.clientSecret
+ options = (options instanceof UsergridAppAuth) ? options : self.appAuth || new UsergridAppAuth(options)
- if (!(self.appAuth instanceof UsergridAppAuth)) {
+ if (!(options instanceof UsergridAppAuth)) {
throw new Error('App auth context was not defined when attempting to call .authenticateApp()')
} else if (!options.clientId || !options.clientSecret) {
throw new Error('authenticateApp() failed because clientId or clientSecret are missing')
}
+
options.type = 'token'
options.client = self
request({
@@ -95,9 +96,49 @@
method: 'POST',
json: true
}, function(error, response, body) {
- self.appAuth.token = body.access_token
- self.appAuth.expiry = Date.now() + ((body.expires_in ? body.expires_in - 5 : 0) * 1000)
- self.appAuth.tokenTtl = body.expires_in
+ if (self.appAuth && response.statusCode === 200) {
+ self.appAuth.token = body.access_token
+ self.appAuth.expiry = helpers.time.expiry(body.expires_in)
+ self.appAuth.tokenTtl = body.expires_in
+ }
+ callback(error, response, body.access_token)
+ })
+}
+
+UsergridClient.prototype.authenticateUser = function(options, callback) {
+ var self = this
+ callback = helpers.cb(callback || options)
+
+ if (!options.username && !options.email && !options.password) {
+ throw new Error('authenticateUser() failed because username/email and password are missing')
+ } else if (!options.password) {
+ throw new Error('authenticateUser() failed because password is missing')
+ }
+
+ options.type = 'token'
+ options.client = self
+ request({
+ uri: helpers.build.url(options),
+ headers: helpers.userAgent,
+ body: options.username ? {
+ grant_type: 'password',
+ username: options.username,
+ password: options.password
+ } : {
+ grant_type: 'password',
+ email: options.email,
+ password: options.password
+ },
+ method: 'POST',
+ json: true
+ }, function(error, response, body) {
+ if (response.statusCode === 200) {
+ self.currentUser = new UsergridUser(body.user)
+ self.currentUser.auth = new UsergridUserAuth(body.user)
+ self.currentUser.auth.token = body.access_token
+ self.currentUser.auth.expiry = helpers.time.expiry(body.expires_in)
+ self.currentUser.auth.tokenTtl = body.expires_in
+ }
callback(error, response, body.access_token)
})
}
diff --git a/lib/userAuth.js b/lib/userAuth.js
new file mode 100644
index 0000000..ca5200f
--- /dev/null
+++ b/lib/userAuth.js
@@ -0,0 +1,23 @@
+'use strict'
+
+var UsergridAuth = require('./auth'),
+ util = require('util'),
+ _ = require('lodash')
+
+var UsergridUserAuth = function(options) {
+ var self = this
+
+ self.email = options.email
+ self.username = options.username
+ if (options.password) {
+ self.password = options.password
+ }
+ self.tokenTtl = options.tokenTtl
+ UsergridAuth.call(self)
+ _.assign(self, UsergridAuth)
+ return self
+}
+
+util.inherits(UsergridUserAuth, UsergridAuth)
+
+module.exports = UsergridUserAuth
\ No newline at end of file
diff --git a/tests/config.test.json b/tests/config.test.json
index 746c937..acdbfdf 100644
--- a/tests/config.test.json
+++ b/tests/config.test.json
@@ -5,7 +5,12 @@
"clientId": "YXA6GXSAACS2EeOYd20aP4G6Lw",
"clientSecret": "YXA66BeEvgNpJBwc4PAbvZZGTVS_SSw",
"orgId": "brandon.apigee",
- "testCollection": "tests"
+ "test": {
+ "collection": "tests",
+ "email": "authtest@test.com",
+ "password": "P@ssw0rd",
+ "username": "authtest"
+ }
},
"2.1": {
"appId": "sdksandbox",
@@ -13,6 +18,11 @@
"clientId": "YXA6WMhAuFJTEeWoggrRE9kXrQ",
"clientSecret": "YXA6zZbat7PKgOlN73rpByc36LWaUhw",
"orgId": "api-connectors",
- "testCollection": "nodejs"
+ "test": {
+ "collection": "nodejs",
+ "email": "authtest@test.com",
+ "password": "P@ssw0rd",
+ "username": "authtest"
+ }
}
}
\ No newline at end of file
diff --git a/tests/lib/client.test.js b/tests/lib/client.test.js
index a093b46..09995fe 100644
--- a/tests/lib/client.test.js
+++ b/tests/lib/client.test.js
@@ -51,7 +51,7 @@
var response, client, query
before(function(done) {
client = new UsergridClient(config)
- client.GET(config.testCollection, function(err, usergridResponse) {
+ client.GET(config.test.collection, function(err, usergridResponse) {
response = usergridResponse
done()
})
@@ -59,7 +59,7 @@
it('should not fail when a callback function is not passed', function() {
// note: this test will NOT fail gracefully inside the Mocha event chain
- client.GET(config.testCollection)
+ client.GET(config.test.collection)
})
it('should return a 200 ok', function() {
@@ -88,7 +88,7 @@
this.timeout(_timeout)
client = new UsergridClient(config)
- query = new UsergridQuery(config.testCollection).eq('color', 'black')
+ query = new UsergridQuery(config.test.collection).eq('color', 'black')
client.GET(query, function(err, usergridResponse) {
usergridResponse.entities.forEach(function(entity) {
@@ -107,7 +107,7 @@
var response, client
before(function(done) {
client = new UsergridClient()
- client.POST(config.testCollection, {
+ client.POST(config.test.collection, {
author: 'Sir Arthur Conan Doyle'
}, function(err, usergridResponse) {
response = usergridResponse
@@ -118,7 +118,7 @@
it('should not fail when a callback function is not passed', function() {
// note: this test will NOT fail gracefully inside the Mocha event chain
- client.POST(config.testCollection, {})
+ client.POST(config.test.collection, {})
})
it('should return a 200 ok', function() {
@@ -143,7 +143,7 @@
this.timeout(_timeout)
var entity = new UsergridEntity({
- type: config.testCollection,
+ type: config.test.collection,
restaurant: "Dino's Deep Dish",
cuisine: "pizza"
})
@@ -159,7 +159,7 @@
this.slow(_slow)
this.timeout(_timeout)
- client.POST(config.testCollection, {
+ client.POST(config.test.collection, {
restaurant: "Dino's Deep Dish",
cuisine: "pizza"
}, function(err, usergridResponse) {
@@ -174,7 +174,7 @@
this.timeout(_timeout)
client.POST({
- type: config.testCollection,
+ type: config.test.collection,
restaurant: "Dino's Deep Dish",
cuisine: "pizza"
}, function(err, usergridResponse) {
@@ -190,11 +190,11 @@
var entities = [
new UsergridEntity({
- type: config.testCollection,
+ type: config.test.collection,
restaurant: "Dino's Deep Dish",
cuisine: "pizza"
}), new UsergridEntity({
- type: config.testCollection,
+ type: config.test.collection,
restaurant: "Chipotle",
cuisine: "mexican"
})
@@ -214,7 +214,7 @@
this.timeout(_timeout)
var options = {
- type: config.testCollection,
+ type: config.test.collection,
body: {
restaurant: "Chipotle",
cuisine: "mexican"
@@ -238,7 +238,7 @@
var response, client
before(function(done) {
client = new UsergridClient()
- client.PUT(config.testCollection, _uuid, {
+ client.PUT(config.test.collection, _uuid, {
narrator: 'Peter Doyle'
}, function(err, usergridResponse) {
response = usergridResponse
@@ -248,7 +248,7 @@
it('should not fail when a callback function is not passed', function() {
// note: this test will NOT fail gracefully inside the Mocha event chain
- client.PUT(config.testCollection, _uuid, {})
+ client.PUT(config.test.collection, _uuid, {})
})
it('should return a 200 ok', function() {
@@ -273,7 +273,7 @@
this.timeout(_timeout)
var newEntity = new UsergridEntity({
- type: config.testCollection,
+ type: config.test.collection,
author: 'Frank Mills'
})
@@ -310,7 +310,7 @@
this.slow(_slow)
this.timeout(_timeout)
- client.PUT(config.testCollection, {
+ client.PUT(config.test.collection, {
uuid: response.entity.uuid,
updateByPassingTypeAndBody: true
}, function(err, usergridResponse) {
@@ -324,8 +324,8 @@
this.slow(_slow)
this.timeout(_timeout)
- client.PUT(config.testCollection, {
- type: config.testCollection,
+ client.PUT(config.test.collection, {
+ type: config.test.collection,
uuid: response.entity.uuid,
updateByPassingBodyIncludingType: true
}, function(err, usergridResponse) {
@@ -336,10 +336,10 @@
it('should support updating a set of entities by passing an UsergridQuery object', function(done) {
- this.slow(_slow)
- this.timeout(_timeout)
+ this.slow(_slow + 1000)
+ this.timeout(_timeout + 2000)
- var query = new UsergridQuery(config.testCollection).eq('cuisine', 'pizza').limit(2)
+ var query = new UsergridQuery(config.test.collection).eq('cuisine', 'pizza').limit(2)
var body = {
testUuid: _.uuid()
}
@@ -359,7 +359,7 @@
var options = {
uuidOrName: response.entity.uuid,
- type: config.testCollection,
+ type: config.test.collection,
body: {
relatedUuid: _.uuid()
}
@@ -380,8 +380,8 @@
var response, client
before(function(done) {
client = new UsergridClient()
- client.DELETE(config.testCollection, _uuid, function() {
- client.GET(config.testCollection, _uuid, function(err, usergridResponse) {
+ client.DELETE(config.test.collection, _uuid, function() {
+ client.GET(config.test.collection, _uuid, function(err, usergridResponse) {
response = usergridResponse
done()
})
@@ -390,7 +390,7 @@
it('should not fail when a callback function is not passed', function() {
// note: this test will NOT fail gracefully inside the Mocha event chain
- client.DELETE(config.testCollection, _uuid)
+ client.DELETE(config.test.collection, _uuid)
})
it('should return a 200 ok', function() {
@@ -415,13 +415,13 @@
this.timeout(_timeout + 1000)
var entity = new UsergridEntity({
- type: config.testCollection,
+ type: config.test.collection,
command: "CTRL+ALT+DEL"
})
client.POST(entity, function(err, usergridResponse) {
client.DELETE(usergridResponse.entity, function() {
- client.GET(config.testCollection, usergridResponse.entity.uuid, function(err, delResponse) {
+ client.GET(config.test.collection, usergridResponse.entity.uuid, function(err, delResponse) {
delResponse.error.name.should.equal((config.target === '1.0') ? 'service_resource_not_found' : 'entity_not_found')
done()
})
@@ -438,9 +438,9 @@
command: "CTRL+ALT+DEL"
}
- client.POST(config.testCollection, body, function(err, usergridResponse) {
- client.DELETE(config.testCollection, usergridResponse.entity.uuid, function() {
- client.GET(config.testCollection, usergridResponse.entity.uuid, function(err, delResponse) {
+ client.POST(config.test.collection, body, function(err, usergridResponse) {
+ client.DELETE(config.test.collection, usergridResponse.entity.uuid, function() {
+ client.GET(config.test.collection, usergridResponse.entity.uuid, function(err, delResponse) {
delResponse.error.name.should.equal((config.target === '1.0') ? 'service_resource_not_found' : 'entity_not_found')
done()
})
@@ -454,11 +454,11 @@
this.timeout(_timeout + 1000)
var entity = new UsergridEntity({
- type: config.testCollection,
+ type: config.test.collection,
command: "CMD+TAB"
})
- var query = new UsergridQuery(config.testCollection).eq('command', 'CMD+TAB')
+ var query = new UsergridQuery(config.test.collection).eq('command', 'CMD+TAB')
client.POST([entity, entity, entity, entity], function() {
client.DELETE(query, function() {
@@ -476,7 +476,7 @@
this.timeout(_timeout + 1000)
var options = {
- type: config.testCollection,
+ type: config.test.collection,
body: {
restaurant: "IHOP",
cuisine: "breakfast"
@@ -484,8 +484,10 @@
}
client.POST(options, function(err, usergridResponse) {
- client.DELETE(_.assign(options, {uuid: usergridResponse.entity.uuid}), function() {
- client.GET(config.testCollection, usergridResponse.entity.uuid, function(err, delResponse) {
+ client.DELETE(_.assign(options, {
+ uuid: usergridResponse.entity.uuid
+ }), function() {
+ client.GET(config.test.collection, usergridResponse.entity.uuid, function(err, delResponse) {
delResponse.error.name.should.equal((config.target === '1.0') ? 'service_resource_not_found' : 'entity_not_found')
done()
})
@@ -499,9 +501,8 @@
this.slow(_slow)
this.timeout(_timeout)
- var response, token, client
+ var response, token, client = new UsergridClient()
before(function(done) {
- client = new UsergridClient()
client.setAppAuth(config.clientId, config.clientSecret, config.tokenTtl)
client.authenticateApp(function(err, r, t) {
response = r
@@ -518,6 +519,27 @@
}).throw()
})
+ it('should not set client.appAuth when authenticating with a bad UsergridAppAuth instance (using an object)', function(done) {
+ var failClient = new UsergridClient()
+ failClient.authenticateApp(new UsergridAppAuth({
+ clientId: 'BADCLIENTID',
+ clientSecret: 'BADCLIENTSECRET'
+ }), function(e, r, token) {
+ should(token).be.undefined()
+ should(failClient.appAuth).be.undefined()
+ done()
+ })
+ })
+
+ it('should not set client.appAuth when authenticating with a bad UsergridAppAuth instance (using arguments)', function(done) {
+ var failClient = new UsergridClient()
+ failClient.authenticateApp(new UsergridAppAuth('BADCLIENTID', 'BADCLIENTSECRET'), function(e, r, token) {
+ should(token).be.undefined()
+ should(failClient.appAuth).be.undefined()
+ done()
+ })
+ })
+
it('should return a 200 ok', function() {
response.statusCode.should.equal(200)
})
@@ -540,6 +562,65 @@
})
})
+describe('authenticateUser()', function() {
+
+ this.slow(_slow)
+ this.timeout(_timeout)
+
+ var response, token, client = new UsergridClient()
+ before(function(done) {
+ client.authenticateUser({
+ username: config.test.username,
+ password: config.test.password
+ }, function(err, r, t) {
+ response = r
+ token = t
+ done()
+ })
+ })
+
+ it('should fail when called without a email (or username) and password', function() {
+ should(function() {
+ var client = new UsergridClient()
+ client.authenticateUser({})
+ }).throw()
+ })
+
+ it('should return a 200 ok', function() {
+ response.statusCode.should.equal(200)
+ })
+
+ it('should have a valid token', function() {
+ token.should.be.a.String()
+ token.length.should.be.greaterThan(10)
+ })
+
+ it('client.currentUser.auth.token should be set to the token returned from Usergrid', function() {
+ client.currentUser.auth.should.have.property('token').equal(token)
+ })
+
+ it('client.currentUser.auth.isTokenValid should be true', function() {
+ client.currentUser.auth.should.have.property('isTokenValid').which.is.true()
+ })
+
+ it('client.currentUser.auth.expiry should be set to a future date', function() {
+ client.currentUser.auth.should.have.property('expiry').greaterThan(Date.now())
+ })
+
+ it('client.currentUser should have a username', function() {
+ client.currentUser.should.have.property('username')
+ })
+
+ it('client.currentUser should have an email', function() {
+ client.currentUser.should.have.property('email')
+ })
+
+ it('client.currentUser and client.currentUser.auth should not store password', function() {
+ client.currentUser.should.not.have.property('password')
+ client.currentUser.auth.should.not.have.property('password')
+ })
+})
+
describe('appAuth, setAppAuth()', function() {
it('should initialize by passing a list of arguments', function() {
var client = new UsergridClient()
diff --git a/tests/lib/response.test.js b/tests/lib/response.test.js
index e897f84..a79e08c 100644
--- a/tests/lib/response.test.js
+++ b/tests/lib/response.test.js
@@ -19,7 +19,7 @@
this.slow(_slow)
this.timeout(_timeout)
- client.GET(config.testCollection, function(err, usergridResponse) {
+ client.GET(config.test.collection, function(err, usergridResponse) {
_response = usergridResponse
done()
})
@@ -53,7 +53,7 @@
this.slow(_slow)
this.timeout(_timeout)
- client.GET(config.testCollection, 'BADNAMEORUUID', function(err, usergridResponse) {
+ client.GET(config.test.collection, 'BADNAMEORUUID', function(err, usergridResponse) {
usergridResponse.error.should.be.an.instanceof(UsergridResponseError)
done()
})
@@ -137,7 +137,7 @@
this.timeout(_timeout)
it('should be true when more entities exist', function(done) {
- client.GET(config.testCollection, function(err, usergridResponse) {
+ client.GET(config.test.collection, function(err, usergridResponse) {
usergridResponse.hasNextPage.should.be.true()
done()
})
diff --git a/tests/lib/responseError.test.js b/tests/lib/responseError.test.js
index a100917..27a7967 100644
--- a/tests/lib/responseError.test.js
+++ b/tests/lib/responseError.test.js
@@ -18,7 +18,7 @@
this.slow(_slow)
this.timeout(_timeout)
- client.GET(config.testCollection, 'BADNAMEORUUID', function(err, usergridResponse) {
+ client.GET(config.test.collection, 'BADNAMEORUUID', function(err, usergridResponse) {
_response = usergridResponse
done()
})
@@ -38,7 +38,7 @@
it('response.error should be undefined on a successful response', function(done) {
this.slow(_slow)
this.timeout(_timeout)
- client.GET(config.testCollection, function(err, usergridResponse) {
+ client.GET(config.test.collection, function(err, usergridResponse) {
usergridResponse.statusCode.should.equal(200)
should(usergridResponse.error).be.undefined()
done()