UNPKG

ac-node-hipchat

Version:

A common module plugin for building Atlassian Connect add-ons for HipChat

196 lines (175 loc) 6.38 kB
var assert = require('assert'); var _ = require('lodash'); var jwt = require('jwt-simple'); var MemoryStore = require('ac-node').MemoryStore; var Tenants = require('ac-node').Tenants; var authenticator = require('..').authenticator; var fixtures = require('./fixtures'); var tenant = fixtures.load('tenant.json'); describe('ac hipchat authenticator', function () { var store; var tenantStore; var tenants; beforeEach(function *() { store = MemoryStore(); tenantStore = store.narrow('tenant'); tenants = Tenants(tenantStore); yield tenantStore.set(tenant.id, tenant); }); it('should create an authenticate fn from tenants and nodeEnv', function *() { assert.ok(typeof authenticator('production', tenants) === 'function'); }); it('should fail to authenticate given neither a signedRequestParam nor an authorizationHeader', function *() { var authenticate = authenticator('production', tenants); try { yield authenticate(); assert.fail(); } catch (err) { assert.equal(err.message, 'Request signature required but not found'); } }); it('should fail to authenticate given a malformed authorization header', function *() { var authenticate = authenticator('production', tenants); try { yield authenticate(null, 'malformed'); assert.fail(); } catch (err) { assert.equal(err.message, 'Authorization header was either incompatible or malformed'); } }); it('should fail to authenticate given a claim that lacks an issuer', function *() { var authenticate = authenticator('production', tenants); var claims = createClaims({ iss: null }); var token = createToken(claims); try { yield authenticate(token); assert.fail(); } catch (err) { assert.equal(err.message, 'Request signature did not contain an issuer claim'); } }); it('should fail to authenticate given a claim that lacks an issued-at timestamp', function *() { var authenticate = authenticator('production', tenants); var claims = createClaims({ iat: null }); var token = createToken(claims); try { yield authenticate(token); assert.fail(); } catch (err) { assert.equal(err.message, 'Request signature did not contain an issued-at timestamp'); } }); it('should fail to authenticate given a claim issued by an unknown tenant', function *() { var authenticate = authenticator('production', tenants); var claims = createClaims({ iss: 'unknown' }); var token = createToken(claims); try { yield authenticate(token); assert.fail(); } catch (err) { assert.equal(err.message, 'Request signature contained unknown issuer: unknown'); } }); it('should fail to authenticate given a claim with an invalid signature', function *() { var authenticate = authenticator('production', tenants); var claims = createClaims(); var token = createToken(claims) + 'fail'; try { yield authenticate(token); assert.fail(); } catch (err) { assert.ok(err.message.indexOf('Request signature verification failed: ') === 0); } }); it('should fail to authenticate given a claim with an expired expiry', function *() { var authenticate = authenticator('production', tenants); var claims = createClaims({ iat: 0, exp: 1 }); var token = createToken(claims); try { yield authenticate(token); assert.fail(); } catch (err) { assert.equal(err.message, 'Request signature expired'); } }); it('should ignore expiry expiration when not running in production mode', function *() { var authenticate = authenticator('development', tenants); var claims = createClaims({ iat: 0, exp: 1 }); var token = createToken(claims); yield authenticate(token); }); it('should fail to authenticate given a claim with an issued-at timestamp greater than authTokenTtl minutes ago', function *() { var authenticate = authenticator('production', tenants, { authTokenTtl: 1 // minutes }); var claims = createClaims({ iat: Math.floor(Date.now() / 1000) - 62 // seconds }); var token = createToken(claims); try { yield authenticate(token); assert.fail(); } catch (err) { assert.equal(err.message, 'Request signature expired'); } }); it('should ignore authTokenTtl expiration when not running in production mode', function *() { var authenticate = authenticator('development', tenants, { authTokenTtl: 1 // minutes }); var claims = createClaims({ iat: Math.floor(Date.now() / 1000) - 62 // seconds }); var token = createToken(claims); yield authenticate(token); }); it('should successfully authenticate given a valid signed request param', function *() { var authenticate = authenticator('production', tenants); var claims = createClaims(); var token = createToken(claims); var authentication = yield authenticate(token); assert.ok(authentication); assert.equal(authentication.issuer, tenant); assert.ok(authentication.issued > claims.iat); assert.equal(authentication.userId, claims.prn); assert.equal(authentication.expiry, authentication.issued + (15 * 60)); assert.deepEqual(authentication.context, claims.context); jwt.decode(authentication.token, tenant.secret); }); it('should successfully authenticate given a valid authorization header', function *() { var authenticate = authenticator('production', tenants); var claims = createClaims(); var token = createToken(claims); var authentication = yield authenticate(null, 'JWT token=' + token); assert.ok(authentication); assert.equal(authentication.issuer, tenant); assert.ok(authentication.issued > claims.iat); assert.equal(authentication.userId, claims.prn); assert.equal(authentication.expiry, authentication.issued + (15 * 60)); assert.deepEqual(authentication.context, claims.context); jwt.decode(authentication.token, tenant.secret); }); }); function createClaims(overrides) { return _.extend({ iss: tenant.id, iat: Math.floor(Date.now() / 1000) - 10, prn: 1, context: {tz: 'GMT'} }, overrides); } function createToken(claims) { return jwt.encode(claims, tenant.secret); }