UNPKG

6.38 kBJavaScriptView Raw
1var assert = require('assert');
2var _ = require('lodash');
3var jwt = require('jwt-simple');
4var MemoryStore = require('ac-node').MemoryStore;
5var Tenants = require('ac-node').Tenants;
6var authenticator = require('..').authenticator;
7var fixtures = require('./fixtures');
8
9var tenant = fixtures.load('tenant.json');
10
11describe('ac hipchat authenticator', function () {
12
13 var store;
14 var tenantStore;
15 var tenants;
16
17 beforeEach(function *() {
18 store = MemoryStore();
19 tenantStore = store.narrow('tenant');
20 tenants = Tenants(tenantStore);
21 yield tenantStore.set(tenant.id, tenant);
22 });
23
24 it('should create an authenticate fn from tenants and nodeEnv', function *() {
25 assert.ok(typeof authenticator('production', tenants) === 'function');
26 });
27
28 it('should fail to authenticate given neither a signedRequestParam nor an authorizationHeader', function *() {
29 var authenticate = authenticator('production', tenants);
30 try {
31 yield authenticate();
32 assert.fail();
33 } catch (err) {
34 assert.equal(err.message, 'Request signature required but not found');
35 }
36 });
37
38 it('should fail to authenticate given a malformed authorization header', function *() {
39 var authenticate = authenticator('production', tenants);
40 try {
41 yield authenticate(null, 'malformed');
42 assert.fail();
43 } catch (err) {
44 assert.equal(err.message, 'Authorization header was either incompatible or malformed');
45 }
46 });
47
48 it('should fail to authenticate given a claim that lacks an issuer', function *() {
49 var authenticate = authenticator('production', tenants);
50 var claims = createClaims({
51 iss: null
52 });
53 var token = createToken(claims);
54 try {
55 yield authenticate(token);
56 assert.fail();
57 } catch (err) {
58 assert.equal(err.message, 'Request signature did not contain an issuer claim');
59 }
60 });
61
62 it('should fail to authenticate given a claim that lacks an issued-at timestamp', function *() {
63 var authenticate = authenticator('production', tenants);
64 var claims = createClaims({
65 iat: null
66 });
67 var token = createToken(claims);
68 try {
69 yield authenticate(token);
70 assert.fail();
71 } catch (err) {
72 assert.equal(err.message, 'Request signature did not contain an issued-at timestamp');
73 }
74 });
75
76 it('should fail to authenticate given a claim issued by an unknown tenant', function *() {
77 var authenticate = authenticator('production', tenants);
78 var claims = createClaims({
79 iss: 'unknown'
80 });
81 var token = createToken(claims);
82 try {
83 yield authenticate(token);
84 assert.fail();
85 } catch (err) {
86 assert.equal(err.message, 'Request signature contained unknown issuer: unknown');
87 }
88 });
89
90 it('should fail to authenticate given a claim with an invalid signature', function *() {
91 var authenticate = authenticator('production', tenants);
92 var claims = createClaims();
93 var token = createToken(claims) + 'fail';
94 try {
95 yield authenticate(token);
96 assert.fail();
97 } catch (err) {
98 assert.ok(err.message.indexOf('Request signature verification failed: ') === 0);
99 }
100 });
101
102 it('should fail to authenticate given a claim with an expired expiry', function *() {
103 var authenticate = authenticator('production', tenants);
104 var claims = createClaims({
105 iat: 0,
106 exp: 1
107 });
108 var token = createToken(claims);
109 try {
110 yield authenticate(token);
111 assert.fail();
112 } catch (err) {
113 assert.equal(err.message, 'Request signature expired');
114 }
115 });
116
117 it('should ignore expiry expiration when not running in production mode', function *() {
118 var authenticate = authenticator('development', tenants);
119 var claims = createClaims({
120 iat: 0,
121 exp: 1
122 });
123 var token = createToken(claims);
124 yield authenticate(token);
125 });
126
127 it('should fail to authenticate given a claim with an issued-at timestamp greater than authTokenTtl minutes ago', function *() {
128 var authenticate = authenticator('production', tenants, {
129 authTokenTtl: 1 // minutes
130 });
131 var claims = createClaims({
132 iat: Math.floor(Date.now() / 1000) - 62 // seconds
133 });
134 var token = createToken(claims);
135 try {
136 yield authenticate(token);
137 assert.fail();
138 } catch (err) {
139 assert.equal(err.message, 'Request signature expired');
140 }
141 });
142
143 it('should ignore authTokenTtl expiration when not running in production mode', function *() {
144 var authenticate = authenticator('development', tenants, {
145 authTokenTtl: 1 // minutes
146 });
147 var claims = createClaims({
148 iat: Math.floor(Date.now() / 1000) - 62 // seconds
149 });
150 var token = createToken(claims);
151 yield authenticate(token);
152 });
153
154 it('should successfully authenticate given a valid signed request param', function *() {
155 var authenticate = authenticator('production', tenants);
156 var claims = createClaims();
157 var token = createToken(claims);
158 var authentication = yield authenticate(token);
159 assert.ok(authentication);
160 assert.equal(authentication.issuer, tenant);
161 assert.ok(authentication.issued > claims.iat);
162 assert.equal(authentication.userId, claims.prn);
163 assert.equal(authentication.expiry, authentication.issued + (15 * 60));
164 assert.deepEqual(authentication.context, claims.context);
165 jwt.decode(authentication.token, tenant.secret);
166 });
167
168 it('should successfully authenticate given a valid authorization header', function *() {
169 var authenticate = authenticator('production', tenants);
170 var claims = createClaims();
171 var token = createToken(claims);
172 var authentication = yield authenticate(null, 'JWT token=' + token);
173 assert.ok(authentication);
174 assert.equal(authentication.issuer, tenant);
175 assert.ok(authentication.issued > claims.iat);
176 assert.equal(authentication.userId, claims.prn);
177 assert.equal(authentication.expiry, authentication.issued + (15 * 60));
178 assert.deepEqual(authentication.context, claims.context);
179 jwt.decode(authentication.token, tenant.secret);
180 });
181
182});
183
184function createClaims(overrides) {
185 return _.extend({
186 iss: tenant.id,
187 iat: Math.floor(Date.now() / 1000) - 10,
188 prn: 1,
189 context: {tz: 'GMT'}
190 }, overrides);
191}
192
193function createToken(claims) {
194 return jwt.encode(claims, tenant.secret);
195}