overleaf/services/history-v1/test/acceptance/js/api/auth.test.js
Alf Eaton ee85d948e2 Avoid duplicating a math-closing dollar sign (#11227)
GitOrigin-RevId: ef2ef77e26df59d1af3df6dc664e284d3c70102d
2023-01-16 08:41:42 +00:00

195 lines
5.8 KiB
JavaScript

const config = require('config')
const fetch = require('node-fetch')
const sinon = require('sinon')
const { expect } = require('chai')
const cleanup = require('../storage/support/cleanup')
const expectResponse = require('./support/expect_response')
const fixtures = require('../storage/support/fixtures')
const HTTPStatus = require('http-status')
const testServer = require('./support/test_server')
describe('auth', function () {
beforeEach(cleanup.everything)
beforeEach(fixtures.create)
beforeEach('Set up stubs', function () {
sinon.stub(config, 'has').callThrough()
sinon.stub(config, 'get').callThrough()
})
afterEach(sinon.restore)
it('renders 401 on swagger docs endpoint without auth', async function () {
const response = await fetch(testServer.url('/docs'))
expect(response.status).to.equal(HTTPStatus.UNAUTHORIZED)
expect(response.headers.get('www-authenticate')).to.match(/^Basic/)
})
it('renders swagger docs endpoint with auth', async function () {
const response = await fetch(testServer.url('/docs'), {
headers: {
Authorization: testServer.basicAuthHeader,
},
})
expect(response.ok).to.be.true
})
it('takes an old basic auth password during a password change', async function () {
setMockConfig('basicHttpAuth.oldPassword', 'foo')
// Primary should still work.
const response1 = await fetch(testServer.url('/docs'), {
headers: {
Authorization: testServer.basicAuthHeader,
},
})
expect(response1.ok).to.be.true
// Old password should also work.
const response2 = await fetch(testServer.url('/docs'), {
headers: {
Authorization: 'Basic ' + Buffer.from('staging:foo').toString('base64'),
},
})
expect(response2.ok).to.be.true
// Incorrect password should not work.
const response3 = await fetch(testServer.url('/docs'), {
header: {
Authorization: 'Basic ' + Buffer.from('staging:bar').toString('base64'),
},
})
expect(response3.status).to.equal(HTTPStatus.UNAUTHORIZED)
})
it('renders 401 on ProjectImport endpoints', async function () {
const unauthenticatedClient = testServer.client
try {
await unauthenticatedClient.apis.ProjectImport.importSnapshot1({
project_id: '1',
snapshot: { files: {} },
})
expect.fail()
} catch (err) {
expectResponse.unauthorized(err)
expect(err.response.headers['www-authenticate']).to.match(/^Basic/)
}
// check that the snapshot was not persisted even if the response was a 401
const projectClient = await testServer.createClientForProject('1')
try {
await projectClient.apis.Project.getLatestHistory({ project_id: '1' })
expect.fail()
} catch (err) {
expectResponse.notFound(err)
}
})
it('renders 401 for JWT endpoints', function () {
return testServer.client.apis.Project.getLatestHistory({
project_id: '10000',
})
.then(() => {
expect.fail()
})
.catch(err => {
expectResponse.unauthorized(err)
expect(err.response.headers['www-authenticate']).to.equal('Bearer')
})
})
it('accepts basic auth in place of JWT (for now)', function () {
const projectId = fixtures.docs.initializedProject.id
return testServer.pseudoJwtBasicAuthClient.apis.Project.getLatestHistory({
project_id: projectId,
}).then(response => {
expect(response.obj.chunk).to.exist
})
})
it('uses JWT', function () {
const projectId = fixtures.docs.initializedProject.id
return testServer
.createClientForProject(projectId)
.then(client => {
return client.apis.Project.getLatestHistory({
project_id: projectId,
})
})
.then(response => {
expect(response.obj.chunk).to.exist
})
})
it('checks for project id', function () {
return testServer
.createClientForProject('1')
.then(client => {
return client.apis.Project.getLatestHistory({
project_id: '2',
})
})
.then(() => {
expect.fail()
})
.catch(expectResponse.forbidden)
})
it('does not accept jwt for ProjectUpdate endpoints', function () {
return testServer.createClientForProject('1').then(client => {
return client.apis.ProjectImport.importSnapshot1({
project_id: '1',
snapshot: {},
})
.then(() => {
expect.fail()
})
.catch(expectResponse.unauthorized)
})
})
describe('when an old JWT key is defined', function () {
beforeEach(function () {
setMockConfig('jwtAuth.oldKey', 'old-secret')
})
it('accepts the old key', async function () {
const projectId = fixtures.docs.initializedProject.id
const client = await testServer.createClientForProject(projectId, {
jwtKey: 'old-secret',
})
const response = await client.apis.Project.getLatestHistory({
project_id: projectId,
})
expect(response.obj.chunk).to.exist
})
it('accepts the new key', async function () {
const projectId = fixtures.docs.initializedProject.id
const client = await testServer.createClientForProject(projectId)
const response = await client.apis.Project.getLatestHistory({
project_id: projectId,
})
expect(response.obj.chunk).to.exist
})
it('rejects other keys', async function () {
const projectId = fixtures.docs.initializedProject.id
const client = await testServer.createClientForProject(projectId, {
jwtKey: 'bad-secret',
})
try {
await client.apis.Project.getLatestHistory({
project_id: projectId,
})
expect.fail()
} catch (err) {
expectResponse.unauthorized(err)
}
})
})
})
function setMockConfig(path, value) {
config.has.withArgs(path).returns(true)
config.get.withArgs(path).returns(value)
}