diff --git a/public.pem b/public.pem new file mode 100644 index 0000000000..c87f4cc4bb --- /dev/null +++ b/public.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxmXH/2XHkkpsxldCK7bx +cZKf0jgPTRFMXnoZRdPe1n8I8feRTm2SMHUf2DuXoLtueHYn1vT2H/fMZ4E1DXA2 +2sxKfKjzXMroKg+jbEtHNkIV2wypE+Jpw3iGrHY9axpFv9M6sD7VSXbeBWrDvMEb +StSdMSaHQfgaCMun3VGwzspZSOkfIO+cENTfvEClh+eans00o3L8aAmUWJjqku04 +ZiyrLmIMPV0rrmsukd+D1UDO65Oz4k/bewZNAxrgn06sPvMjjsK6Is5ceppc/zCn +AHWJcmhX9L+x96ZNV068/wypMtYJ8GM9UnBlSlQPRaPQoPoeKd7Y1FNPB66ybvwd +rwIDAQAB +-----END PUBLIC KEY----- diff --git a/src/lib/routes/logout.js b/src/lib/routes/logout.js deleted file mode 100644 index 01da843c1d..0000000000 --- a/src/lib/routes/logout.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -const Controller = require('./controller'); - -class LogoutController extends Controller { - constructor(config) { - super(config); - this.baseUri = config.server.baseUriPath; - this.get('/', this.logout); - } - - logout(req, res) { - if (req.session) { - req.session.destroy(); - } - if (req.logout) { - req.logout(); - } - res.set('Clear-Site-Data', '"cookies"'); - res.redirect(`${this.baseUri}/`); - } -} - -module.exports = LogoutController; diff --git a/src/lib/routes/logout.test.js b/src/lib/routes/logout.test.js deleted file mode 100644 index 90134bd8f2..0000000000 --- a/src/lib/routes/logout.test.js +++ /dev/null @@ -1,52 +0,0 @@ -'use strict'; - -const supertest = require('supertest'); -const { EventEmitter } = require('events'); -const { createServices } = require('../services'); -const { createTestConfig } = require('../../test/config/test-config'); - -const store = require('../../test/fixtures/store'); -const getApp = require('../app'); -const User = require('../types/user'); - -const eventBus = new EventEmitter(); - -const currentUser = new User({ id: 1337, email: 'test@mail.com' }); - -function getSetup() { - const base = `/random${Math.round(Math.random() * 1000)}`; - const stores = store.createStores(); - const config = createTestConfig({ - server: { baseUriPath: base }, - preHook: a => { - a.use((req, res, next) => { - req.user = currentUser; - next(); - }); - }, - }); - const services = createServices(stores, config); - - const app = getApp(config, stores, services, eventBus); - - return { - base, - strategyStore: stores.strategyStore, - request: supertest(app), - destroy: () => { - services.versionService.destroy(); - services.clientMetricsService.destroy(); - services.apiTokenService.destroy(); - }, - }; -} - -test('should logout and redirect', async () => { - expect.assertions(0); - const { base, request, destroy } = getSetup(); - await request - .get(`${base}/logout`) - .expect(302) - .expect('Location', `${base}/`); - destroy(); -}); diff --git a/src/lib/routes/logout.test.ts b/src/lib/routes/logout.test.ts new file mode 100644 index 0000000000..4b6a8576d3 --- /dev/null +++ b/src/lib/routes/logout.test.ts @@ -0,0 +1,82 @@ +import supertest from 'supertest'; +import express from 'express'; +import { createTestConfig } from '../../test/config/test-config'; + +import LogoutController from './logout'; +import { IAuthRequest } from './unleash-types'; + +test('should redirect to "/" after logout', async () => { + const baseUriPath = ''; + const app = express(); + const config = createTestConfig({ server: { baseUriPath } }); + app.use('/logout', new LogoutController(config).router); + const request = supertest(app); + expect.assertions(0); + await request + .get(`${baseUriPath}/logout`) + .expect(302) + .expect('Location', `${baseUriPath}/`); +}); + +test('should redirect to "/basePath" after logout when baseUriPath is set', async () => { + const baseUriPath = '/basePath'; + const app = express(); + const config = createTestConfig({ server: { baseUriPath } }); + app.use('/logout', new LogoutController(config).router); + const request = supertest(app); + expect.assertions(0); + await request + .get(`/logout`) + .expect(302) + .expect('Location', `${baseUriPath}/`); +}); + +test('should set "Clear-Site-Data" header', async () => { + const baseUriPath = ''; + const app = express(); + const config = createTestConfig({ server: { baseUriPath } }); + app.use('/logout', new LogoutController(config).router); + const request = supertest(app); + expect.assertions(0); + await request + .get(`${baseUriPath}/logout`) + .expect(302) + .expect('Clear-Site-Data', '"cookies", "storage"'); +}); + +test('should call destroy on session', async () => { + const baseUriPath = ''; + const fakeSession = { + destroy: jest.fn(), + }; + const app = express(); + const config = createTestConfig({ server: { baseUriPath } }); + app.use((req: IAuthRequest, res, next) => { + req.session = fakeSession; + next(); + }); + app.use('/logout', new LogoutController(config).router); + const request = supertest(app); + await request.get(`${baseUriPath}/logout`); + + expect(fakeSession.destroy.mock.calls.length).toBe(1); +}); + +test('should redirect to alternative logoutUrl', async () => { + const fakeSession = { + destroy: jest.fn(), + logoutUrl: '/some-other-path', + }; + const app = express(); + const config = createTestConfig(); + app.use((req: IAuthRequest, res, next) => { + req.session = fakeSession; + next(); + }); + app.use('/logout', new LogoutController(config).router); + const request = supertest(app); + await request + .get(`/logout`) + .expect(302) + .expect('Location', '/some-other-path'); +}); diff --git a/src/lib/routes/logout.ts b/src/lib/routes/logout.ts new file mode 100644 index 0000000000..a14db86b33 --- /dev/null +++ b/src/lib/routes/logout.ts @@ -0,0 +1,36 @@ +import { Response } from 'express'; +import { IUnleashConfig } from '../types/option'; +import Controller from './controller'; +import { IAuthRequest } from './unleash-types'; + +class LogoutController extends Controller { + private baseUri: string; + + constructor(config: IUnleashConfig) { + super(config); + this.baseUri = config.server.baseUriPath; + this.get('/', this.logout); + } + + async logout(req: IAuthRequest, res: Response): Promise { + if (req.session) { + // Allow SSO to register custom logout logic. + if (req.session.logoutUrl) { + res.redirect(req.session.logoutUrl); + return; + } + + req.session.destroy(); + } + + if (req.logout) { + req.logout(); + } + + res.set('Clear-Site-Data', '"cookies", "storage"'); + res.redirect(`${this.baseUri}/`); + } +} + +module.exports = LogoutController; +export default LogoutController;