refactor of authentication and html-templates into separate modules
[websub-hub] / test / src / authenticator.js
diff --git a/test/src/authenticator.js b/test/src/authenticator.js
deleted file mode 100644 (file)
index 47313d8..0000000
+++ /dev/null
@@ -1,344 +0,0 @@
-/* eslint-env mocha */
-'use strict';
-
-const assert = require('assert');
-const sinon = require('sinon'); // eslint-disable-line node/no-unpublished-require
-const Authenticator = require('../../src/authenticator');
-const stubLogger = require('../stub-logger');
-const stubDb = require('../stub-db');
-const Errors = require('../../src/errors');
-const Enum = require('../../src/enum');
-const Config = require('../../config');
-
-const noExpectedException = 'did not receive expected exception';
-
-describe('Authenticator', function () {
-  let authenticator, credential, ctx, identifier, password, options;
-  function _authMechanismRequired(a, m) {
-    if (!a.authn[m]) { // eslint-disable-line security/detect-object-injection
-      this.skip();
-    }
-  };
-
-  beforeEach(function () {
-    options = Config('test');
-    authenticator = new Authenticator(stubLogger, stubDb, options);
-    identifier = 'username';
-    credential = '$argon2id$v=19$m=4096,t=3,p=1$1a6zRlX4BI4$sZGcQ72BTpDOlxUI/j3DmE1PMcu+Cs5liZ/D6kk79Ew';
-    ctx = {};
-    password = 'badPassword';
-    stubDb._reset();
-  });
-  afterEach(function () {
-    sinon.restore();
-  });
-
-  it('covers no auth mechanisms', function () {
-    options.authenticator.authnEnabled = [];
-    try {
-      authenticator = new Authenticator(stubLogger, stubDb, options);
-      assert.fail(noExpectedException);
-    } catch (e) {
-      assert.strictEqual(e.message, 'no authentication mechanisms available');
-    }
-  });
-
-  describe('isValidBasic', function () {
-    it('succeeds', async function () {
-      _authMechanismRequired(authenticator, 'argon2');
-      authenticator.db.authenticationGet.resolves({
-        identifier,
-        credential,
-      });
-      const authString = `${identifier}:${password}`;
-      const result = await authenticator.isValidBasic(authString, ctx);
-      assert.strictEqual(result, true);
-      assert.strictEqual(ctx.authenticationId, identifier);
-    });
-    it('fails', async function () {
-      _authMechanismRequired(authenticator, 'argon2');
-      authenticator.db.authenticationGet.resolves({
-        identifier,
-        credential,
-      });
-      const authString = `${identifier}:wrongPassword}`;
-      const result = await authenticator.isValidBasic(authString, ctx);
-      assert.strictEqual(result, false);
-      assert.strictEqual(ctx.authenticationId, undefined);
-    });
-    it('covers no entry', async function() {
-      authenticator.db.authenticationGet.resolves();
-      const authString = `${identifier}:wrongPassword}`;
-      const result = await authenticator.isValidBasic(authString, ctx);
-      assert.strictEqual(result, false);
-      assert.strictEqual(ctx.authenticationId, undefined);
-    });
-    it('covers unknown password hash', async function () {
-      authenticator.db.authenticationGet.resolves({
-        identifier,
-        credential: '$other$kind_of_credential',
-      });
-      const authString = `${identifier}:wrongPassword}`;
-      const result = await authenticator.isValidBasic(authString, ctx);
-      assert.strictEqual(result, false);
-      assert.strictEqual(ctx.authenticationId, undefined);
-    });
-  }); // isValidBasic
-
-  describe('isValidIdentifierCredential', function () {
-    it('succeeds', async function () {
-      _authMechanismRequired(authenticator, 'argon2');
-      authenticator.db.authenticationGet.resolves({
-        identifier,
-        credential,
-      });
-      const result = await authenticator.isValidIdentifierCredential(identifier, password, ctx);
-      assert.strictEqual(result, true);
-      assert.strictEqual(ctx.authenticationId, identifier);
-    });
-    it('fails', async function () {
-      _authMechanismRequired(authenticator, 'argon2');
-      authenticator.db.authenticationGet.resolves({
-        identifier,
-        credential,
-      });
-      const result = await authenticator.isValidIdentifierCredential(identifier, 'wrongPassword', ctx);
-      assert.strictEqual(result, false);
-      assert.strictEqual(ctx.authenticationId, undefined);
-    });
-    it('covers no entry', async function() {
-      authenticator.db.authenticationGet.resolves();
-      const result = await authenticator.isValidIdentifierCredential(identifier, 'wrongPassword', ctx);
-      assert.strictEqual(result, false);
-      assert.strictEqual(ctx.authenticationId, undefined);
-    });
-    it('covers unknown password hash', async function () {
-      authenticator.db.authenticationGet.resolves({
-        identifier,
-        credential: '$other$kind_of_credential',
-      });
-      const result = await authenticator.isValidIdentifierCredential(identifier, 'wrongPassword', ctx);
-      assert.strictEqual(result, false);
-      assert.strictEqual(ctx.authenticationId, undefined);
-    });
-    it('covers PAM', async function () {
-      _authMechanismRequired(authenticator, 'pam');
-      sinon.stub(authenticator, '_isValidPAMIdentifier').resolves(true);
-      authenticator.db.authenticationGet.resolves({
-        identifier,
-        credential: '$PAM$',
-      });
-      const result = await authenticator.isValidIdentifierCredential(identifier, password, ctx);
-      assert.strictEqual(result, true);
-      assert.strictEqual(ctx.authenticationId, identifier);
-    });
-    it('covers debug', async function () {
-      authenticator.authnEnabled = ['DEBUG_ANY'];
-      const result = await authenticator.isValidIdentifierCredential(identifier, password, ctx);
-      assert.strictEqual(result, true);
-      assert.strictEqual(ctx.authenticationId, identifier);
-    });
-  }); // isValidIdentifierCredential
-
-  describe('_isValidPAMIdentifier', function () {
-    beforeEach(function () {
-      _authMechanismRequired(authenticator, 'pam');
-      sinon.stub(authenticator.authn.pam, 'pamAuthenticatePromise');
-    });
-    it('covers success', async function () {
-      authenticator.authn.pam.pamAuthenticatePromise.resolves(true);
-      const result = await authenticator._isValidPAMIdentifier(identifier, credential);
-      assert.strictEqual(result, true);
-    });
-    it('covers failure', async function () {
-      _authMechanismRequired(authenticator, 'pam');
-      authenticator.authn.pam.pamAuthenticatePromise.rejects(new authenticator.authn.pam.PamError());
-      const result = await authenticator._isValidPAMIdentifier(identifier, credential);
-      assert.strictEqual(result, false);
-    });
-    it('covers error', async function () {
-      _authMechanismRequired(authenticator, 'pam');
-      const expected = new Error('blah');
-      authenticator.authn.pam.pamAuthenticatePromise.rejects(expected);
-      try {
-        await authenticator._isValidPAMIdentifier(identifier, credential);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert.deepStrictEqual(e, expected);
-      }
-    });
-    it('covers forbidden', async function () {
-      identifier = 'root';
-      const result = await authenticator._isValidPAMIdentifier(identifier, credential);
-      assert.strictEqual(result, false);
-    });
-  }); // _isValidPAMIdentifier
-
-  describe('isValidAuthorization', function () {
-    it('handles basic', async function () {
-      const expected = true;
-      const authorizationHeader = 'basic Zm9vOmJhcg==';
-      sinon.stub(authenticator, 'isValidBasic').resolves(expected);
-      const result = await authenticator.isValidAuthorization(authorizationHeader, ctx);
-      assert.strictEqual(result, expected);
-    });
-    it('handles other', async function () {
-      const expected = false;
-      const authorizationHeader = 'bearer Zm9vOmJhcg==';
-      const result = await authenticator.isValidAuthorization(authorizationHeader, ctx);
-      assert.strictEqual(result, expected);
-    });
-  }); // isValidAuthorization
-
-  describe('requestBasic', function () {
-    it('covers', function () {
-      try {
-        const res = {
-          setHeader: () => {},
-        };
-        authenticator.requestBasic(res);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert(e instanceof Errors.ResponseError);
-        assert.strictEqual(e.statusCode, Enum.ErrorResponse.Unauthorized.statusCode);
-      }
-    });
-  }); // requestBasic
-
-  describe('isValidCookieAuth', function () {
-    beforeEach(function () {
-      sinon.stub(authenticator.mysteryBox, 'unpack');
-    });
-    it('covers identifier success', async function () {
-      authenticator.mysteryBox.unpack.resolves({
-        authenticatedIdentifier: 'identifier',
-      });
-      const result = await authenticator.isValidCookieAuth(ctx, 'WSHas=dummy');
-      assert.strictEqual(result, true);
-    });
-    it('covers profile success', async function () {
-      authenticator.mysteryBox.unpack.resolves({
-        authenticatedProfile: 'profile',
-      });
-      const result = await authenticator.isValidCookieAuth(ctx, 'WSHas=dummy');
-      assert.strictEqual(result, true);
-    });
-    it('covers missing cookie', async function () {
-      const result = await authenticator.isValidCookieAuth(ctx, 'wrongCookie');
-      assert.strictEqual(result, false);
-    });
-    it('covers bad cookie', async function () {
-      authenticator.mysteryBox.unpack.rejects();
-      const result = await authenticator.isValidCookieAuth(ctx, 'WSHas=dummy');
-      assert.strictEqual(result, false);
-    });
-  }); // isValidCookieAuth
-
-  describe('required', function () {
-    let req, res;
-    beforeEach(function () {
-      ctx.clientProtocol = 'https';
-      req = {
-        getHeader: sinon.stub(),
-      };
-      res = {
-        end: sinon.stub(),
-        setHeader: sinon.stub(),
-      }
-    });
-    it('succeeds', async function() {
-      req.getHeader.returns('auth header');
-      sinon.stub(authenticator, 'isValidAuthorization').resolves(true);
-      const result = await authenticator.required(req, res, ctx);
-      assert.strictEqual(result, true);
-    });
-    it('covers valid cookie session', async function () {
-      req.getHeader.returns('WSHas=sessionCookie');
-      sinon.stub(authenticator, 'isValidCookieAuth').resolves(true);
-      const result = await authenticator.required(req, res, ctx);
-      assert.strictEqual(result, true);
-    });
-    it('rejects insecure connection', async function () {
-      ctx.clientProtocol = 'http';
-      try {
-        await authenticator.required(req, res, ctx);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert(e instanceof Errors.ResponseError);
-        assert.strictEqual(e.statusCode, Enum.ErrorResponse.Forbidden.statusCode);
-      }
-    });
-    it('rejects invalid auth', async function () {
-      try {
-        req.getHeader.returns('auth header');
-        sinon.stub(authenticator, 'isValidAuthorization').resolves(false);
-        await authenticator.required(req, res, ctx);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert(e instanceof Errors.ResponseError);
-        assert.strictEqual(e.statusCode, Enum.ErrorResponse.Unauthorized.statusCode);
-      }
-    });
-    it('redirects without any auth', async function () {
-      await authenticator.required(req, res, ctx);
-      assert(res.end.called);
-      assert(res.setHeader.called);
-    });
-  }); // required
-
-  describe('requiredLocal', function () {
-    let req, res;
-    beforeEach(function () {
-      ctx.clientProtocol = 'https';
-      req = {
-        getHeader: sinon.stub(),
-      };
-      res = {
-        end: sinon.stub(),
-        setHeader: sinon.stub(),
-      }
-    });
-    it('succeeds', async function() {
-      req.getHeader.returns('auth header');
-      sinon.stub(authenticator, 'isValidAuthorization').resolves(true);
-      const result = await authenticator.requiredLocal(req, res, ctx);
-      assert.strictEqual(result, true);
-    });
-    it('covers valid cookie session', async function () {
-      req.getHeader.returns('WSHas=sessionCookie');
-      sinon.stub(authenticator, 'isValidCookieAuth').resolves(true);
-      ctx.session = {
-        authenticatedIdentifier: identifier,
-      };
-      const result = await authenticator.requiredLocal(req, res, ctx);
-      assert.strictEqual(result, true);
-    });
-    it('rejects insecure connection', async function () {
-      ctx.clientProtocol = 'http';
-      try {
-        await authenticator.requiredLocal(req, res, ctx);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert(e instanceof Errors.ResponseError);
-        assert.strictEqual(e.statusCode, Enum.ErrorResponse.Forbidden.statusCode);
-      }
-    });
-    it('rejects invalid auth', async function () {
-      try {
-        req.getHeader.returns('auth header');
-        sinon.stub(authenticator, 'isValidAuthorization').resolves(false);
-        await authenticator.requiredLocal(req, res, ctx);
-        assert.fail(noExpectedException);
-      } catch (e) {
-        assert(e instanceof Errors.ResponseError);
-        assert.strictEqual(e.statusCode, Enum.ErrorResponse.Unauthorized.statusCode);
-      }
-    });
-    it('redirects without any auth', async function () {
-      await authenticator.requiredLocal(req, res, ctx);
-      assert(res.end.called);
-      assert(res.setHeader.called);
-    });
-  }); // requiredLocal
-
-}); // Authenticator