socketio: Delete redundant authentication check

There's no need to perform an authentication check in the socket.io
middleware because `PadMessageHandler.handleMessage` calls
`SecurityMananger.checkAccess` and that now performs authentication
and authorization checks.

This change also improves the user experience: Before, access denials
caused socket.io error events in the client, which `pad.js` mostly
ignores (the user doesn't see anything). Now a deny message is sent
back to the client, which causes `pad.js` to display an obvious
permission denied message.

This also fixes a minor bug: `settings.loadTest` is supposed to bypass
authentication and authorization checks, but they weren't bypassed
because `SecurityManager.checkAccess` did not check
`settings.loadTest`.
This commit is contained in:
Richard Hansen 2020-10-03 17:52:10 -04:00 committed by John McLear
parent 3f8365a995
commit f7953ece85
3 changed files with 18 additions and 40 deletions

View file

@ -155,20 +155,17 @@ describe('socket.io access checks', function() {
describe('Normal accesses', function() {
it('!authn anonymous cookie /p/pad -> 200, ok', async function() {
const res = await agent.get('/p/pad').expect(200);
// Should not throw.
socket = await connect(res);
const clientVars = await handshake(socket, 'pad');
assert.equal(clientVars.type, 'CLIENT_VARS');
});
it('!authn !cookie -> ok', async function() {
// Should not throw.
socket = await connect(null);
const clientVars = await handshake(socket, 'pad');
assert.equal(clientVars.type, 'CLIENT_VARS');
});
it('!authn user /p/pad -> 200, ok', async function() {
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
// Should not throw.
socket = await connect(res);
const clientVars = await handshake(socket, 'pad');
assert.equal(clientVars.type, 'CLIENT_VARS');
@ -176,7 +173,6 @@ describe('socket.io access checks', function() {
it('authn user /p/pad -> 200, ok', async function() {
settings.requireAuthentication = true;
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
// Should not throw.
socket = await connect(res);
const clientVars = await handshake(socket, 'pad');
assert.equal(clientVars.type, 'CLIENT_VARS');
@ -185,7 +181,6 @@ describe('socket.io access checks', function() {
settings.requireAuthentication = true;
settings.requireAuthorization = true;
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
// Should not throw.
socket = await connect(res);
const clientVars = await handshake(socket, 'pad');
assert.equal(clientVars.type, 'CLIENT_VARS');
@ -199,7 +194,6 @@ describe('socket.io access checks', function() {
settings.requireAuthorization = true;
const encodedPadId = encodeURIComponent('päd');
const res = await agent.get(`/p/${encodedPadId}`).auth('user', 'user-password').expect(200);
// Should not throw.
socket = await connect(res);
const clientVars = await handshake(socket, 'päd');
assert.equal(clientVars.type, 'CLIENT_VARS');
@ -211,11 +205,15 @@ describe('socket.io access checks', function() {
settings.requireAuthentication = true;
const res = await agent.get('/p/pad').expect(401);
// Despite the 401, try to create the pad via a socket.io connection anyway.
await assert.rejects(connect(res), {message: /authentication required/i});
socket = await connect(res);
const message = await handshake(socket, 'pad');
assert.equal(message.accessStatus, 'deny');
});
it('authn !cookie -> error', async function() {
settings.requireAuthentication = true;
await assert.rejects(connect(null), {message: /signed express_sid cookie is required/i});
socket = await connect(null);
const message = await handshake(socket, 'pad');
assert.equal(message.accessStatus, 'deny');
});
it('authorization bypass attempt -> error', async function() {
// Only allowed to access /p/pad.
@ -224,7 +222,6 @@ describe('socket.io access checks', function() {
settings.requireAuthorization = true;
// First authenticate and establish a session.
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
// Connecting should work because the user successfully authenticated.
socket = await connect(res);
// Accessing /p/other-pad should fail, despite the successful fetch of /p/pad.
const message = await handshake(socket, 'other-pad');