const Authenticator = require('../../lib/authenticator');
const stubLogger = require('../stub-logger');
const stubDb = require('../stub-db');
-const Errors = require('../../lib/errors');
const Enum = require('../../lib/enum');
const Config = require('../stub-config');
-const noExpectedException = 'did not receive expected exception';
-
describe('Authenticator', function () {
let authenticator, credential, ctx, identifier, password, options;
function _authMechanismRequired(a, m) {
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');
- }
+ assert.throws(() => new Authenticator(stubLogger, stubDb, options), {
+ message: 'no authentication mechanisms available',
+ });
});
it('covers empty realm', 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);
- }
+ assert.rejects(() => authenticator._isValidPAMIdentifier(identifier, credential), expected);
});
it('covers forbidden', async function () {
identifier = 'root';
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);
- }
+ const res = {
+ setHeader: () => {},
+ };
+ assert.throws(() => authenticator.requestBasic(res), {
+ name: 'ResponseError',
+ statusCode: Enum.ErrorResponse.Unauthorized.statusCode,
+ });
});
}); // requestBasic
});
}); // isValidCookieAuth
+ describe('checkOTP', function () {
+ let state, otp;
+ this.beforeEach(function () {
+ sinon.stub(authenticator.TOTP.prototype, 'validate').returns(true);
+ state = {
+ key: Buffer.from('12345678901234567890'),
+ attempt: 0,
+ epochMs: Date.now(),
+ };
+ otp = '000000';
+ });
+ it('covers valid OTP entry', function () {
+ const result = authenticator.checkOTP(state, otp);
+ assert.strictEqual(result, Enum.OTPResult.Valid);
+ });
+ it('covers invalid OTP entry', function () {
+ authenticator.TOTP.prototype.validate.returns(false);
+ const result = authenticator.checkOTP(state, otp);
+ assert.strictEqual(result, Enum.OTPResult.InvalidSoftFail);
+ });
+ it('covers invalid OTP entry, too many failures', function () {
+ state.attempt = 10;
+ authenticator.TOTP.prototype.validate.returns(false);
+ const result = authenticator.checkOTP(state, otp);
+ assert.strictEqual(result, Enum.OTPResult.InvalidHardFail);
+ });
+ it('covers invalid OTP entry', function () {
+ state.epochMs = 0;
+ authenticator.TOTP.prototype.validate.returns(false);
+ const result = authenticator.checkOTP(state, otp);
+ assert.strictEqual(result, Enum.OTPResult.InvalidHardFail);
+ });
+ }); // checkOTP
+
describe('sessionCheck', function () {
let cookie, req, res, loginPath, required, profilesAllowed;
beforeEach(function () {
const result = await authenticator.sessionCheck(req, res, ctx, loginPath, required, profilesAllowed);
assert.strictEqual(result, true);
});
+ it('covers valid insecure cookie session', async function () {
+ authenticator.secureAuthOnly = false;
+ req.getHeader.returns(cookie);
+ sinon.stub(authenticator, 'isValidCookieAuth').resolves(true);
+ ctx.session = {
+ authenticatedIdentifier: 'user',
+ };
+ const result = await authenticator.sessionCheck(req, res, ctx, loginPath, required, profilesAllowed);
+ assert.strictEqual(result, true);
+ });
it('rejects insecure connection', async function () {
ctx.clientProtocol = 'http';
- try {
- await authenticator.sessionCheck(req, res, ctx, loginPath, required, profilesAllowed);
- assert.fail(noExpectedException);
- } catch (e) {
- assert(e instanceof Errors.ResponseError);
- assert.strictEqual(e.statusCode, Enum.ErrorResponse.Forbidden.statusCode);
- }
+ assert.rejects(() => authenticator.sessionCheck(req, res, ctx, loginPath, required, profilesAllowed), {
+ name: 'ResponseError',
+ sttausCode: Enum.ErrorResponse.Forbidden.statusCode,
+ });
});
it('ignores insecure connection if auth not required', async function () {
ctx.clientProtocol = 'http';
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);
- }
+ assert.rejects(() => authenticator.apiRequiredLocal(req, res, ctx), {
+ name: 'ResponseError',
+ statusCode: 401,
+ });
+ assert(!authenticator.sessionCheck.called);
+ assert(authenticator.isValidAuthorization.called);
});
it('covers missing basic auth, valid session', async function () {
req.getHeader.returns();
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) {
- assert.strictEqual(e.statusCode, 401);
- assert(!authenticator.sessionCheck.called);
- assert(!authenticator.isValidAuthorization.called);
- assert(res.setHeader.called);
- }
+ assert.rejects(authenticator.apiRequiredLocal(req, res, ctx, false), {
+ name: 'ResponseError',
+ statusCode: 401,
+ });
+ assert(!authenticator.sessionCheck.called);
+ assert(!authenticator.isValidAuthorization.called);
+ assert(res.setHeader.called);
});
}); // apiRequiredLocal