/**
* Require auth for an API endpoint.
- * Check for valid local identifier in session, or Authentication header.
+ * Check for valid local identifier in Authorization header; optionally
+ * fall back to session cookie if no header provided.
* Prompts for Basic auth if not valid.
* @param {http.ClientRequest} req
* @param {http.ServerResponse} res
* @param {Boolean} sessionAlsoValid
*/
async apiRequiredLocal(req, res, ctx, sessionAlsoValid = true) {
- const validSession = sessionAlsoValid && this.sessionCheck(req, res, ctx, undefined, false, false);
+ const _scope = _fileScope('apiRequiredLocal');
+ this.logger.debug(_scope, 'called', { ctx, sessionAlsoValid });
+
+ // If a Authorization header was provided, never consider session as a fallback.
const authorizationHeader = req.getHeader(Enum.Header.Authorization);
- const validAuthorization = authorizationHeader && this.isValidAuthorization(authorizationHeader, ctx);
- if (validSession || validAuthorization) {
- return true;
+ if (authorizationHeader) {
+ if (await this.isValidAuthorization(authorizationHeader, ctx)) {
+ this.logger.debug(_scope, 'valid authorization', { ctx, sessionAlsoValid });
+ return true;
+ }
+ } else {
+ if (sessionAlsoValid
+ && await this.sessionCheck(req, res, ctx, undefined, false, false)) {
+ this.logger.debug(_scope, 'valid session', { ctx, sessionAlsoValid });
+ return true;
+ }
}
+
+ this.logger.debug(_scope, 'invalid authorization', { ctx, sessionAlsoValid });
this.requestBasic(res);
}
}); // sessionCheck
describe('apiRequiredLocal', function () {
- let req, res, ctx;
+ let req, res;
beforeEach(function () {
ctx = {};
req = {
sinon.stub(authenticator, 'sessionCheck').resolves(false);
sinon.stub(authenticator, 'isValidAuthorization').resolves(true);
const result = await authenticator.apiRequiredLocal(req, res, ctx);
- assert(authenticator.sessionCheck.called);
+ assert.strictEqual(result, true);
assert(authenticator.isValidAuthorization.called);
+ assert(!authenticator.sessionCheck.called);
+ });
+ it('covers invalid basic auth', async function () {
+ req.getHeader.returns('Basic Zm9vOmJhcg==');
+ sinon.stub(authenticator, 'sessionCheck').resolves(false);
+ sinon.stub(authenticator, 'isValidAuthorization').resolves(false);
+ try {
+ await authenticator.apiRequiredLocal(req, res, ctx);
+ assert.fail(noExpectedException);
+ } catch (e) {
+ assert.strictEqual(e.statusCode, 401);
+ assert(!authenticator.sessionCheck.called);
+ assert(authenticator.isValidAuthorization.called);
+ }
+ });
+ it('covers missing basic auth, valid session', async function () {
+ req.getHeader.returns();
+ sinon.stub(authenticator, 'sessionCheck').resolves(true);
+ sinon.stub(authenticator, 'isValidAuthorization').resolves(false);
+ const result = await authenticator.apiRequiredLocal(req, res, ctx);
assert.strictEqual(result, true);
+ assert(!authenticator.isValidAuthorization.called);
+ assert(authenticator.sessionCheck.called);
});
- it('requests basic auth when missing, ignores session', async function () {
+ it('covers missing basic auth, ignores session', async function () {
req.getHeader.returns();
sinon.stub(authenticator, 'isValidAuthorization').resolves(true);
try {
await authenticator.apiRequiredLocal(req, res, ctx, false);
assert.fail(noExpectedException);
} catch (e) {
- console.log(e);
assert.strictEqual(e.statusCode, 401);
assert(!authenticator.sessionCheck.called);
assert(!authenticator.isValidAuthorization.called);