Skip to content

Commit

Permalink
feat(Disable Auth V1): Allowing the disabling of Auth V1 via the config
Browse files Browse the repository at this point in the history
Adding a config object that will disable Auth V1

#34
  • Loading branch information
tocco934 committed Jul 31, 2017
1 parent ca7c906 commit 86497b7
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 26 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ The config object passed in must have the following sections and fields:
```js
var config = {
secret: 'The client secret, only needed for OAuth v1',
clientId: 'Your own client id',
clientId: 'Your own client id, only needed for OAuth v1',
domain: 'The token issuer w/o https:// or the trailing /',
realm: 'The realm of the token, used in the challenge headers, full url (w/ https:// and trailing /)',
jwksUrl: 'The url to retrieve the jwk from, only needed for OAuth v2',
audience: 'The audience for the auth token',
disableV1: 'Should auth v1 be enabled (defaults to false), not required',
excludedRoutes (OPTIONAL): [ // Routes that shouldn't be protected by Auth0
{
url: '/healthcheck', // Supports a regex as well
Expand All @@ -30,6 +31,8 @@ var config = {
};
```

This library also supports the 'express-unless' library.

You must also pass in a cache object, used for only OAuth v2, with the following two functions:
```js
- get(string key) { // Must return a promise
Expand Down
40 changes: 25 additions & 15 deletions lib/auth0verification.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const _ = require('lodash'),
jwksClient = require('jwks-rsa');

const BASE64_REGEX = /^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-_]{2}==|[A-Za-z0-9-_]{3}=)?$/;
const ERROR_NAME= 'UnauthorizedError';
const ERROR_NAME = 'UnauthorizedError';

// private function for computing the routes we do not need to apply auth0 to
const getExcludedRoutes = function (configuredExclusions) {
Expand Down Expand Up @@ -60,20 +60,23 @@ const getAuthPublicKey = function (jwksUrl, cache, kid) {
// secures the application with auth0, by implementing checks against
// incoming jwt's, with configuration of what routes to apply it to
module.exports = function (app, config, logger, cache) {
if (config && config.secret) {
// decode the client secret if it is base64 encoded
var secret;
if (config.secret.match(BASE64_REGEX)) {
secret = new Buffer(config.secret, 'base64');
} else {
secret = config.secret;
}
if (config) {

// set up jwt validation, which will take into account excluded routes
var v1JwtCheck = expressJwt({
secret: secret,
audience: config.clientId
});
if (config.secret && !config.disableV1) {
// decode the client secret if it is base64 encoded
var secret;
if (config.secret.match(BASE64_REGEX)) {
secret = new Buffer(config.secret, 'base64');
} else {
secret = config.secret;
}

// set up jwt validation, which will take into account excluded routes
var v1JwtCheck = expressJwt({
secret: secret,
audience: config.clientId
});
}

let v2JwtCheck;
if (config.audience && config.jwksUrl) {
Expand Down Expand Up @@ -120,7 +123,14 @@ module.exports = function (app, config, logger, cache) {
return v2JwtCheck(req, res, next);
}
}
return v1JwtCheck(req, res, next);
if (v1JwtCheck) {
return v1JwtCheck(req, res, next);
}
else {
var error = new Error('The supplied token is not supported by any enabled auth');
error.name = ERROR_NAME;
next(error);
}
};
jwtAuthentication.unless = unless;

Expand Down
31 changes: 21 additions & 10 deletions lib/unauthorized.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,42 @@ module.exports = function(app, config, logger) {
app.use(function(err, req, res, next) {
if (err.name === 'UnauthorizedError') {
logger.log(err);
addWwwAuthenticateHeaders(req, res, config.domain, config.clientId, config.audience, config.realm);
addLinkHeaders(res, config.domain, config.audience);
addWwwAuthenticateHeaders(req, res, config.domain, config.clientId, config.audience, config.realm, !config.disableV1);
addLinkHeaders(res, config.domain, config.audience, !config.disableV1);
return res.status(401).json();
}
next(err);
});
};

function addWwwAuthenticateHeaders(req, res, domain, clientId, resourceServer, realm) {
var v1WwwAuthenticateHeader = util.format('Bearer realm="%s", scope="client_id=%s service=%s"',
function createv1WWWAuthentiateHeader(req, domain, clientId) {
return util.format('Bearer realm="%s", scope="client_id=%s service=%s"',
domain, clientId, "https://" + req.hostname + req.baseUrl);
}

function addWwwAuthenticateHeaders(req, res, domain, clientId, resourceServer, realm, v1) {
if (resourceServer) {
var v2WwwAuthenticateHeader = util.format('Bearer realm="%s", authorization_uri="https://%s/oauth/token"', realm, domain);
return res.header('WWW-Authenticate', [v2WwwAuthenticateHeader, v1WwwAuthenticateHeader]);
if (v1) {
return res.header('WWW-Authenticate', [v2WwwAuthenticateHeader, createv1WWWAuthentiateHeader(req, domain, clientId)]);
}
return res.header('WWW-Authenticate', v2WwwAuthenticateHeader);
} else if (v1) {
res.header('WWW-Authenticate', createv1WWWAuthentiateHeader(req, domain, clientId));
}
res.header('WWW-Authenticate', v1WwwAuthenticateHeader);
}

function addLinkHeaders(res, domain, resourceServer) {
var v1authLink = '<https://%s/authorize>; rel="openid2.provider openid.server"';
function createv1LinkHeaders(domain) {
return util.format('<https://%s/authorize>; rel="openid2.provider openid.server"', domain);
}

function addLinkHeaders(res, domain, resourceServer, v1) {
if (resourceServer) {
var v2authLink = '<https://%s/oauth/token>; rel=authorization_uri';
return res.header('Link', [util.format(v1authLink, domain), util.format(v2authLink, domain)]);
if (v1) {
return res.header('Link', [util.format(v2authLink, domain), createv1LinkHeaders(domain)]);
}
} else if (v1) {
res.header('Link', createv1LinkHeaders(domain));
}
res.header('Link', util.format(v1authLink, domain));
}
27 changes: 27 additions & 0 deletions test/auth0verification.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,33 @@ describe('Verify auth0 application functions.', function () {
});
});

it('Should return an appropriate WWW-Authenticate header for API Authentication when V1 is disabled', function () {

jwtMock.setJwtFunction(function (req, res, next) {
return next(new UnauthorizedError('credentials_required', {
message: 'No authorization token was found'
}));
});
// Clone the config so as not to break other tests.
var v2config = JSON.parse(JSON.stringify(config));
v2config.audience = 'http://api.cimpress.io/';
v2config.disableV1 = true;

helper = new Helper(mw, v2config, null, defaultCache);
helper.app.get("/stub", function (req, res) {
res.status(200).json({ name: "tobi" });
});

return helper.execute("/stub").expect(401).then(function (req, res) {
expect(helper.finishedRequest.user).to.be.undefined;
expect(helper.finishedResponse._headers['www-authenticate']).to.not.include(
'Bearer realm="' + domain + '", scope="client_id=' + clientId +
' service=https://' + helper.finishedRequest.hostname + helper.finishedRequest.baseUrl + '"');
expect(helper.finishedResponse._headers['www-authenticate']).to.include(
'Bearer realm="' + realm + '", authorization_uri="https://' + domain + '/oauth/token"');
});
});

it('Should be able to exclude a route', function () {
jwtMock.setJwtFunction(function (req, res, next) {
req.user = {};
Expand Down

0 comments on commit 86497b7

Please sign in to comment.