Skip to content

Commit

Permalink
Add Signature header support. (#83)
Browse files Browse the repository at this point in the history
* add signature header parser support

* add authorization and signature header name to utils

* remove unused require module

* add signature header support for set header

* fix signatureHeaderName not defined bug
  • Loading branch information
lizheming authored and kusor committed Oct 30, 2019
1 parent 523e7c5 commit 276bd13
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 73 deletions.
136 changes: 69 additions & 67 deletions lib/parser.js
Expand Up @@ -26,7 +26,6 @@ var ParamsState = {
Comma: 3
};


///--- Specific Errors


Expand Down Expand Up @@ -118,91 +117,94 @@ module.exports = {
assert.arrayOfString(options.headers, 'options.headers');
assert.optionalFinite(options.clockSkew, 'options.clockSkew');

var authzHeaderName = options.authorizationHeaderName || 'authorization';
var headers = request.headers;
var authzHeaderName = options.authorizationHeaderName;
var authz = headers[authzHeaderName] || headers[utils.HEADER.AUTH] || headers[utils.HEADER.SIG];

if (!authz) {
var errHeader = authzHeaderName ? authzHeaderName : utils.HEADER.AUTH + ' or ' + utils.HEADER.SIG;

if (!request.headers[authzHeaderName]) {
throw new MissingHeaderError('no ' + authzHeaderName + ' header ' +
'present in the request');
throw new MissingHeaderError('no ' + errHeader + ' header ' +
'present in the request');
}

options.clockSkew = options.clockSkew || 300;


var i = 0;
var state = State.New;
var state = authz === headers[utils.HEADER.SIG] ? State.Params : State.New;
var substate = ParamsState.Name;
var tmpName = '';
var tmpValue = '';

var parsed = {
scheme: '',
scheme: authz === headers[utils.HEADER.SIG] ? 'Signature' : '',
params: {},
signingString: ''
};

var authz = request.headers[authzHeaderName];
for (i = 0; i < authz.length; i++) {
var c = authz.charAt(i);

switch (Number(state)) {

case State.New:
if (c !== ' ') parsed.scheme += c;
else state = State.Params;
break;

case State.Params:
switch (Number(substate)) {

case ParamsState.Name:
var code = c.charCodeAt(0);
// restricted name of A-Z / a-z
if ((code >= 0x41 && code <= 0x5a) || // A-Z
(code >= 0x61 && code <= 0x7a)) { // a-z
tmpName += c;
} else if (c === '=') {
if (tmpName.length === 0)
throw new InvalidHeaderError('bad param format');
substate = ParamsState.Quote;
} else {
throw new InvalidHeaderError('bad param format');
}
break;

case ParamsState.Quote:
if (c === '"') {
tmpValue = '';
substate = ParamsState.Value;
} else {
throw new InvalidHeaderError('bad param format');
}
break;

case ParamsState.Value:
if (c === '"') {
parsed.params[tmpName] = tmpValue;
substate = ParamsState.Comma;
} else {
tmpValue += c;
}
case State.New:
if (c !== ' ') parsed.scheme += c;
else state = State.Params;
break;

case ParamsState.Comma:
if (c === ',') {
tmpName = '';
substate = ParamsState.Name;
} else {
throw new InvalidHeaderError('bad param format');
case State.Params:
switch (Number(substate)) {

case ParamsState.Name:
var code = c.charCodeAt(0);
// restricted name of A-Z / a-z
if ((code >= 0x41 && code <= 0x5a) || // A-Z
(code >= 0x61 && code <= 0x7a)) { // a-z
tmpName += c;
} else if (c === '=') {
if (tmpName.length === 0)
throw new InvalidHeaderError('bad param format');
substate = ParamsState.Quote;
} else {
throw new InvalidHeaderError('bad param format');
}
break;

case ParamsState.Quote:
if (c === '"') {
tmpValue = '';
substate = ParamsState.Value;
} else {
throw new InvalidHeaderError('bad param format');
}
break;

case ParamsState.Value:
if (c === '"') {
parsed.params[tmpName] = tmpValue;
substate = ParamsState.Comma;
} else {
tmpValue += c;
}
break;

case ParamsState.Comma:
if (c === ',') {
tmpName = '';
substate = ParamsState.Name;
} else {
throw new InvalidHeaderError('bad param format');
}
break;

default:
throw new Error('Invalid substate');
}
break;

default:
throw new Error('Invalid substate');
}
break;

default:
throw new Error('Invalid substate');
}

}
Expand Down Expand Up @@ -278,19 +280,19 @@ module.exports = {
// Check against the constraints
var date;
if (request.headers.date || request.headers['x-date']) {
if (request.headers['x-date']) {
date = new Date(request.headers['x-date']);
} else {
date = new Date(request.headers.date);
}
if (request.headers['x-date']) {
date = new Date(request.headers['x-date']);
} else {
date = new Date(request.headers.date);
}
var now = new Date();
var skew = Math.abs(now.getTime() - date.getTime());

if (skew > options.clockSkew * 1000) {
throw new ExpiredRequestError('clock skew of ' +
(skew / 1000) +
's was greater than ' +
options.clockSkew + 's');
(skew / 1000) +
's was greater than ' +
options.clockSkew + 's');
}
}

Expand All @@ -304,7 +306,7 @@ module.exports = {
if (options.algorithms) {
if (options.algorithms.indexOf(parsed.params.algorithm) === -1)
throw new InvalidParamsError(parsed.params.algorithm +
' is not a supported algorithm');
' is not a supported algorithm');
}

parsed.algorithm = parsed.params.algorithm.toUpperCase();
Expand Down
14 changes: 8 additions & 6 deletions lib/signer.js
Expand Up @@ -2,7 +2,6 @@

var assert = require('assert-plus');
var crypto = require('crypto');
var http = require('http');
var util = require('util');
var sshpk = require('sshpk');
var jsprim = require('jsprim');
Expand All @@ -21,6 +20,8 @@ var validateAlgorithm = utils.validateAlgorithm;
var AUTHZ_FMT =
'Signature keyId="%s",algorithm="%s",headers="%s",signature="%s"';

var SIGNATURE_FMT = 'keyId="%s",algorithm="%s",headers="%s",signature="%s"';

///--- Specific Errors

function MissingHeaderError(message) {
Expand Down Expand Up @@ -389,11 +390,12 @@ module.exports = {

var authzHeaderName = options.authorizationHeaderName || 'Authorization';

request.setHeader(authzHeaderName, sprintf(AUTHZ_FMT,
options.keyId,
options.algorithm,
options.headers.join(' '),
signature));
var FMT = authzHeaderName.toLowerCase() === utils.HEADER.SIG ? SIGNATURE_FMT : AUTHZ_FMT;
request.setHeader(authzHeaderName, sprintf(FMT,
options.keyId,
options.algorithm,
options.headers.join(' '),
signature));

return true;
}
Expand Down
6 changes: 6 additions & 0 deletions lib/utils.js
Expand Up @@ -16,6 +16,11 @@ var PK_ALGOS = {
'ecdsa': true
};

var HEADER = {
AUTH: 'authorization',
SIG: 'signature'
};

function HttpSignatureError(message, caller) {
if (Error.captureStackTrace)
Error.captureStackTrace(this, caller || HttpSignatureError);
Expand Down Expand Up @@ -54,6 +59,7 @@ function validateAlgorithm(algorithm) {
///--- API

module.exports = {
HEADER,

HASH_ALGOS: HASH_ALGOS,
PK_ALGOS: PK_ALGOS,
Expand Down

0 comments on commit 276bd13

Please sign in to comment.