1 | 'use strict';
|
2 |
|
3 | var expect = require('chai').expect;
|
4 | var winston = require('winston');
|
5 | var cache = require('../lib/cache');
|
6 | var errors = require('@leisurelink/http-equiv-errors');
|
7 | var httpMocks = require('node-mocks-http');
|
8 |
|
9 | var SignatureParser = require('../lib/signature-parser');
|
10 |
|
11 | describe('SignatureParser', function(){
|
12 | var parser, mockAuthentic, mockHttpSignature;
|
13 | var mockRequest, parsedRequest, keyResponse;
|
14 |
|
15 | beforeEach(function(){
|
16 | cache.disable();
|
17 | mockHttpSignature = {
|
18 | parseRequest: function() { return parsedRequest; },
|
19 | verifySignature: function() { return true; }
|
20 | };
|
21 | mockAuthentic = {
|
22 | getEndpointKey: function(lang, endpointId, keyId, cb) { cb(null, keyResponse.response, keyResponse.body); }
|
23 | };
|
24 |
|
25 | parsedRequest = { params: { keyId: 'some-endpoint/some-key', headers: ['host', 'date', 'request-line'] } };
|
26 | keyResponse = { response: { statusCode: 200 }, body: { result: { key: '---PUBLIC KEY---' } } };
|
27 | mockRequest = httpMocks.createRequest({
|
28 | method: 'GET',
|
29 | url: '/some/endpoint'
|
30 | });
|
31 | mockRequest.headers.authorization = 'authorization';
|
32 | mockRequest.headers.host = 'some host';
|
33 | mockRequest.headers.date = '2015-11-01';
|
34 |
|
35 | });
|
36 |
|
37 | describe('#parse', function(){
|
38 | describe('given strict parsing', function(){
|
39 | beforeEach(function(){
|
40 | parser = SignatureParser(mockHttpSignature, mockAuthentic, winston, false);
|
41 | });
|
42 | it('should return parsed signature', function(){
|
43 | return parser.parse(mockRequest).then(function(val){
|
44 | expect(val).to.eql(parsedRequest);
|
45 | });
|
46 | });
|
47 | it('should return null when parsed signature is null', function(){
|
48 | parsedRequest = null;
|
49 | return parser.parse(mockRequest).then(function(val){
|
50 | expect(val).to.be.null;
|
51 | });
|
52 | });
|
53 | it('should return parsed signature when parsed signature is missing params', function(){
|
54 | parsedRequest.params = undefined;
|
55 | return parser.parse(mockRequest).then(function(val){
|
56 | expect(val).to.eql(parsedRequest);
|
57 | });
|
58 | });
|
59 | it('should return parsed signature when parsed signature is missing keyId', function(){
|
60 | parsedRequest.params.keyId = undefined;
|
61 | return parser.parse(mockRequest).then(function(val){
|
62 | expect(val).to.eql(parsedRequest);
|
63 | });
|
64 | });
|
65 | it('should return null when parsing request throws error', function(){
|
66 | mockHttpSignature.parseRequest = function(){ throw new Error('fake error'); };
|
67 | return parser.parse(mockRequest).then(function(val){
|
68 | expect(val).to.be.null;
|
69 | });
|
70 | });
|
71 | it('should return error when authentic returns error', function(){
|
72 | mockAuthentic.getEndpointKey = function(_, __, ___, cb) { cb(new Error('fake error')); };
|
73 | return parser.parse(mockRequest).then(function(){
|
74 | throw new Error('Expected failure, got success');
|
75 | }).catch(function(err){
|
76 | expect(err).to.be.ok;
|
77 | });
|
78 | });
|
79 | it('should return UnauthorizedError when key is not found', function(){
|
80 | keyResponse.body.result.key = undefined;
|
81 | return parser.parse(mockRequest).then(function(){
|
82 | throw new Error('Expected failure, got success');
|
83 | }).catch(errors.UnauthorizedError, function(err){
|
84 | expect(err).to.be.ok;
|
85 | expect(err.message).to.eql('authentic:signing-key-not-found');
|
86 | });
|
87 | });
|
88 | it('should return null when request is missing required headers', function(){
|
89 | parsedRequest.params.headers = ['date'];
|
90 | return parser.parse(mockRequest).then(function(val){
|
91 | expect(val).to.be.null;
|
92 | });
|
93 | });
|
94 | it('should return UnauthorizedError when signature is not verified', function(){
|
95 | mockHttpSignature.verifySignature = function() { return false; };
|
96 | return parser.parse(mockRequest).then(function(){
|
97 | throw new Error('Expected failure, got success');
|
98 | }).catch(errors.UnauthorizedError, function(err){
|
99 | expect(err).to.be.ok;
|
100 | expect(err.message).to.eql('authentic:signature-inauthentic');
|
101 | });
|
102 | });
|
103 | });
|
104 |
|
105 | describe('given lax parsing', function(){
|
106 | beforeEach(function(){
|
107 | parser = SignatureParser(mockHttpSignature, mockAuthentic, winston, true);
|
108 | });
|
109 | describe('with request that still contains signature', function(){
|
110 | it('should return parsed signature', function(){
|
111 | return parser.parse(mockRequest).then(function(val){
|
112 | expect(val).to.eql(parsedRequest);
|
113 | });
|
114 | });
|
115 | it('should return parsed signature when signature is not verified', function(){
|
116 | mockHttpSignature.verifySignature = function() { return false; };
|
117 | return parser.parse(mockRequest).then(function(val){
|
118 | expect(val).to.eql(parsedRequest);
|
119 | });
|
120 | });
|
121 | });
|
122 | describe('with request that has signature fields in the header', function(){
|
123 | var keyId = 'some-endpoint/some-key';
|
124 | var jwt = 'somejwt';
|
125 |
|
126 | beforeEach(function(){
|
127 | mockRequest.headers = {
|
128 | 'x-lax-key-id': keyId,
|
129 | 'x-lax-headers': 'host date request-line',
|
130 | 'x-lax-jwt': jwt
|
131 | };
|
132 | mockHttpSignature.parseRequest = function() { return null; };
|
133 | });
|
134 | it('should return parsed request', function(){
|
135 | return parser.parse(mockRequest).then(function(val){
|
136 | expect(val).to.eql({
|
137 | scheme: 'LaxSignature',
|
138 | params: {
|
139 | keyId: keyId,
|
140 | algorithm: 'fake',
|
141 | headers: ['host', 'date', 'request-line'],
|
142 | jwt: jwt,
|
143 | signature: 'fake'
|
144 | },
|
145 | signingString: 'fake'
|
146 | });
|
147 | });
|
148 | });
|
149 | it('should return parsed request when http signature throws error', function(){
|
150 | mockHttpSignature.parseRequest = function() { throw new Error('fake error'); };
|
151 | return parser.parse(mockRequest).then(function(val){
|
152 | expect(val).to.eql({
|
153 | scheme: 'LaxSignature',
|
154 | params: {
|
155 | keyId: keyId,
|
156 | algorithm: 'fake',
|
157 | headers: ['host', 'date', 'request-line'],
|
158 | jwt: jwt,
|
159 | signature: 'fake'
|
160 | },
|
161 | signingString: 'fake'
|
162 | });
|
163 | });
|
164 | });
|
165 | });
|
166 | });
|
167 | });
|
168 | });
|