diff --git a/lib/http/service.js b/lib/http/service.js index 19d6070dc2..071615e81 100644 --- a/lib/http/service.js +++ b/lib/http/service.js @@ -63,6 +63,7 @@ module.exports = (container) => { const { builder } = require('./endpoint'); const { emptyAuthInjector, authHandler, queryOptionsHandler, userAgentHandler } = require('./preprocessors'); const endpoint = builder(container, [ emptyAuthInjector, authHandler, queryOptionsHandler, userAgentHandler ]); + const anonymousEndpoint = builder(container, [ emptyAuthInjector, queryOptionsHandler, userAgentHandler ]); //////////////////////////////////////////////////////////////////////////////// @@ -73,7 +74,7 @@ module.exports = (container) => { require('../resources/odata-entities')(service, endpoint); require('../resources/forms')(service, endpoint); require('../resources/users')(service, endpoint); - require('../resources/sessions')(service, endpoint); + require('../resources/sessions')(service, endpoint, anonymousEndpoint); require('../resources/submissions')(service, endpoint); require('../resources/config')(service, endpoint); require('../resources/projects')(service, endpoint); diff --git a/lib/resources/sessions.js b/lib/resources/sessions.js index 7ffa1891d..c646bae6a 100644 --- a/lib/resources/sessions.js +++ b/lib/resources/sessions.js @@ -15,10 +15,10 @@ const { success } = require('../util/http'); const { SESSION_COOKIE, createUserSession } = require('../http/sessions'); const oidc = require('../util/oidc'); -module.exports = (service, endpoint) => { +module.exports = (service, endpoint, anonymousEndpoint) => { if (!oidc.isEnabled()) { - service.post('/sessions', endpoint(({ Audits, Users, Sessions }, { body, headers }) => { + service.post('/sessions', anonymousEndpoint(({ Audits, Users, Sessions }, { body, headers }) => { // TODO if we're planning to offer multiple authN methods, we should be looking for // any calls to verifyPassword(), and blocking them if that authN method is not // appropriate for the current user. diff --git a/test/integration/api/sessions.js b/test/integration/api/sessions.js index f61102de5..86671cd41 100644 --- a/test/integration/api/sessions.js +++ b/test/integration/api/sessions.js @@ -14,6 +14,32 @@ describe('api: /sessions', () => { body.should.be.a.Session(); }))); + [ + { desc: 'invalid session cookie', header: 'Cookie', value: 'session=invalid' }, + { desc: 'invalid bearer token', header: 'Authorization', value: 'Bearer invalid' }, + { desc: 'invalid basic auth', header: 'Authorization', value: 'Basic invalid' }, + ].forEach(t => { + it(`should return a new session even if invalid auth is passed in the header - ${t.desc}`, testService((service) => + service.post('/v1/sessions') + .set(t.header, t.value) + .set('x-forwarded-proto', 'https') + .send({ email: 'chelsea@getodk.org', password: 'password4chelsea' }) + .expect(200) + .then(({ body }) => { + body.should.be.a.Session(); + }))); + }); + + it('should return a new session even valid cookie is passed', testService((service) => + service.post('/v1/sessions') + .send({ email: 'chelsea@getodk.org', password: 'password4chelsea' }) + .expect(200) + .then(({ body }) => service.post('/v1/sessions') + .set('x-forwarded-proto', 'https') + .set('Cookie', `session=${body.token}`) + .send({ email: 'chelsea@getodk.org', password: 'password4chelsea' }) + .expect(200)))); + // These demonstrate a strange feature of bcrypt - a valid password can be // repeated multiple times and still validate successfully. An alternative // to these tests would be to check for NUL characters in supplied passwords