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()