var test = require('tape'), errors = require('../../lib/errors'), grantTypes = require('../../lib/grantTypes'), kgo = require('kgo'), testError = 'boom!!!', mockery = require('mockery'), pathToObjectUnderTest = '../../lib/grantAccessToken'; mockery.registerAllowables([pathToObjectUnderTest, './errors', './grantTypes']); function resetMocks(){ mockery.registerMock('kgo', kgo); mockery.registerMock('./getTokenData', {}); } function getCleanTestObject(){ delete require.cache[require.resolve(pathToObjectUnderTest)]; mockery.enable({ useCleanCache: true, warnOnReplace: false }); var objectUnderTest = require(pathToObjectUnderTest); mockery.disable(); resetMocks(); return objectUnderTest; } resetMocks(); test('grantAccessToken exists', function(t){ t.plan(2); var grantAccessToken = getCleanTestObject(); t.ok(grantAccessToken, 'grantAccessToken Exists'); t.equal(typeof grantAccessToken, 'function', 'grantAccessToken is a function'); }); test('grantAccessToken requires grant_type', function(t){ t.plan(1); var context = { grant_type: undefined }, grantAccessToken = getCleanTestObject(); grantAccessToken(context, function(error){ t.deepEqual(error, errors.invalidRequest(context), 'correct error and data'); }); }); test('grantAccessToken IMPLICIT is an allowed grant_type', function(t){ t.plan(1); var context = { grant_type: grantTypes.IMPLICIT }, authServer = { clientService: { getById: function(){ t.pass('IMPLICIT grant type is allowed'); } } }, grantAccessToken = getCleanTestObject().bind(authServer); grantAccessToken(context, function(){ t.fail('should not have called back'); }); }); test('grantAccessToken AUTHORIZATIONCODE is not allowed grant_type if authorizationService not provided', function(t){ t.plan(1); var context = { grant_type: grantTypes.AUTHORIZATIONCODE }, authServer = { authorizationService: null, clientService: { getById: function(){ t.fail('AUTHORIZATIONCODE grant type is allowed without authorizationService'); } } }, grantAccessToken = getCleanTestObject().bind(authServer); grantAccessToken(context, function(error){ t.deepEqual(error, errors.unsupportedGrantType(context), 'correct error and data'); }); }); test('grantAccessToken AUTHORIZATIONCODE is allowed grant_type if authorizationService provided', function(t){ t.plan(1); var context = { grant_type: grantTypes.AUTHORIZATIONCODE }, authServer = { authorizationService: {}, clientService: { getById: function(){ t.pass('AUTHORIZATIONCODE grant type is allowed with authorizationService'); } } }, grantAccessToken = getCleanTestObject().bind(authServer); grantAccessToken(context, function(){ t.fail('should not have called back'); }); }); test('grantAccessToken CLIENTCREDENTIALS is not allowed grant_type if clientService provided', function(t){ t.plan(1); var context = { grant_type: grantTypes.CLIENTCREDENTIALS }, authServer = { clientService: null }, grantAccessToken = getCleanTestObject().bind(authServer); grantAccessToken(context, function(error){ t.deepEqual(error, errors.unsupportedGrantType(context), 'correct error and data'); }); }); test('grantAccessToken CLIENTCREDENTIALS is allowed grant_type if clientService provided', function(t){ t.plan(1); var context = { grant_type: grantTypes.CLIENTCREDENTIALS }, authServer = { clientService: { getById: function(){ t.pass('CLIENTCREDENTIALS grant type is allowed with clientService'); } } }, grantAccessToken = getCleanTestObject().bind(authServer); grantAccessToken(context, function(){ t.fail('should not have called back'); }); }); test('grantAccessToken PASSWORD is not allowed grant_type if membershipService not provided', function(t){ t.plan(1); var context = { grant_type: grantTypes.PASSWORD }, authServer = { membershipService: null, clientService: { getById: function(){ t.fail('PASSWORD grant type is allowed without membershipService'); } } }, grantAccessToken = getCleanTestObject().bind(authServer); grantAccessToken(context, function(error){ t.deepEqual(error, errors.unsupportedGrantType(context), 'correct error and data'); }); }); test('grantAccessToken PASSWORD is allowed grant_type if membershipService provided', function(t){ t.plan(1); var context = { grant_type: grantTypes.PASSWORD }, authServer = { membershipService: {}, clientService: { getById: function(){ t.pass('PASSWORD grant type is allowed with membershipService'); } } }, grantAccessToken = getCleanTestObject().bind(authServer); grantAccessToken(context, function(){ t.fail('should not have called back'); }); }); test('grantAccessToken handels get client by id error', function(t){ t.plan(1); var context = { grant_type: grantTypes.AUTHORIZATIONCODE, client_id: 123 }, authServer = { authorizationService: {}, clientService: { getById: function(clientId, callback){ callback(testError); } } }, grantAccessToken = getCleanTestObject().bind(authServer); grantAccessToken(context, function(error){ t.equal(error, testError, 'correct error'); }); }); test('grantAccessToken handels invalid client', function(t){ t.plan(1); var context = { grant_type: grantTypes.AUTHORIZATIONCODE, client_id: 123 }, authServer = { authorizationService: {}, clientService: { getById: function(clientId, callback){ callback(); } } }, grantAccessToken = getCleanTestObject().bind(authServer); grantAccessToken(context, function(error){ t.deepEqual(error, errors.invalidClient(context), 'correct error and data'); }); }); test('grantAccessToken handels missing client grantTypes', function(t){ t.plan(2); var context = { grant_type: grantTypes.AUTHORIZATIONCODE, client_id: 123 }, client = { grantTypes: null }, authServer = { authorizationService: {}, clientService: { getById: function(clientId, callback){ t.equal(clientId, context.client_id, 'got correct clientId'); callback(null, client); } } }, grantAccessToken = getCleanTestObject().bind(authServer); grantAccessToken(context, function(error){ t.deepEqual(error, errors.unsupportedGrantTypeForClient(context), 'correct error and data'); }); }); test('grantAccessToken handels invalid client grantTypes', function(t){ t.plan(2); var context = { grant_type: grantTypes.AUTHORIZATIONCODE, client_id: 123 }, client = { grantTypes: [grantTypes.PASSWORD] }, authServer = { authorizationService: {}, clientService: { getById: function(clientId, callback){ t.equal(clientId, context.client_id, 'got correct clientId'); callback(null, client); } } }, grantAccessToken = getCleanTestObject().bind(authServer); grantAccessToken(context, function(error){ t.deepEqual(error, errors.unsupportedGrantTypeForClient(context), 'correct error and data'); }); }); test('grantAccessToken checks client secret if type AUTHORIZATIONCODE', function(t){ t.plan(2); var context = { grant_type: grantTypes.AUTHORIZATIONCODE, client_id: 123, client_secret: 'foo' }, client = { grantTypes: [grantTypes.AUTHORIZATIONCODE], secret: 'bar' }, authServer = { authorizationService: {}, clientService: { getById: function(clientId, callback){ t.equal(clientId, context.client_id, 'got correct clientId'); callback(null, client); } } }, grantAccessToken = getCleanTestObject().bind(authServer); grantAccessToken(context, function(error){ t.deepEqual(error, errors.clientCredentialsInvalid(context), 'correct error and data'); }); }); test('grantAccessToken checks client secret if type CLIENTCREDENTIALS', function(t){ t.plan(2); var context = { grant_type: grantTypes.CLIENTCREDENTIALS, client_id: 123, client_secret: 'foo' }, client = { grantTypes: [grantTypes.CLIENTCREDENTIALS], secret: 'bar' }, authServer = { clientService: { getById: function(clientId, callback){ t.equal(clientId, context.client_id, 'got correct clientId'); callback(null, client); } } }, grantAccessToken = getCleanTestObject().bind(authServer); grantAccessToken(context, function(error){ t.deepEqual(error, errors.clientCredentialsInvalid(context), 'correct error and data'); }); }); test('grantAccessToken handels get token data error', function(t){ t.plan(4); var context = { grant_type: grantTypes.CLIENTCREDENTIALS, client_id: 123, client_secret: 'foo' }, client = { grantTypes: [grantTypes.CLIENTCREDENTIALS], secret: 'foo' }, authServer = { clientService: { getById: function(clientId, callback){ t.equal(clientId, context.client_id, 'got correct clientId'); callback(null, client); } } }; mockery.registerMock('./getTokenData', function(subContext, callback){ t.equal(this, authServer, 'bound correctly'); t.equal(subContext, context, 'correct context'); callback(testError); }); var grantAccessToken = getCleanTestObject().bind(authServer); grantAccessToken(context, function(error){ t.deepEqual(error, testError, 'correct error'); }); }); test('grantAccessToken handels save token data error', function(t){ t.plan(5); var context = { grant_type: grantTypes.CLIENTCREDENTIALS, client_id: 123, client_secret: 'foo' }, client = { grantTypes: [grantTypes.CLIENTCREDENTIALS], secret: 'foo' }, authServer = { clientService: { getById: function(clientId, callback){ t.equal(clientId, context.client_id, 'got correct clientId'); callback(null, client); } }, authorizationService: { saveAccessToken: function(data, callback){ t.equal(data, tokenData, 'correct tokenData'); callback(testError); } } }, tokenData = { accountId: 123, clientId: 456 }; mockery.registerMock('./getTokenData', function(subContext, callback){ t.equal(this, authServer, 'bound correctly'); t.equal(subContext, context, 'correct context'); callback(null, tokenData); }); var grantAccessToken = getCleanTestObject().bind(authServer); grantAccessToken(context, function(error){ t.deepEqual(error, testError, 'correct error'); }); }); test('grantAccessToken saves token data correctly', function(t){ t.plan(8); var context = { grant_type: grantTypes.CLIENTCREDENTIALS, client_id: 123, client_secret: 'foo' }, client = { grantTypes: [grantTypes.CLIENTCREDENTIALS], secret: 'foo' }, authServer = { clientService: { getById: function(clientId, callback){ t.equal(clientId, context.client_id, 'got correct clientId'); callback(null, client); } }, authorizationService: { saveAccessToken: function(data, callback){ t.equal(data, tokenData, 'correct tokenData'); callback(null, tokenData); } } }, tokenData = { accountId: 123, clientId: 456 }; mockery.registerMock('./getTokenData', function(subContext, callback){ t.equal(this, authServer, 'bound correctly'); t.equal(subContext, context, 'correct context'); callback(null, tokenData); }); var grantAccessToken = getCleanTestObject().bind(authServer); grantAccessToken(context, function(error, result){ t.notOk(error, 'no error'); t.equal(result, tokenData, 'correct result'); t.notOk(result.accountId, 'accountId was removed'); t.notOk(result.clientId, 'clientId was removed'); }); });