Skip to content

Commit

Permalink
Merge pull request #75 from kbaseIncubator/PUBLIC-1549-fix-logout
Browse files Browse the repository at this point in the history
PUBLIC-1549: Fix logout url & request
  • Loading branch information
dakotablair authored Mar 10, 2021
2 parents e46a0d5 + 0ca0bcb commit 2e2e73d
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 10 deletions.
17 changes: 11 additions & 6 deletions src/client/components/global_header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,22 @@ export class Header extends Component<Props, State> {
}
const headers = {
Authorization: token,
Accept: 'application/json',
};
fetch(Runtime.getConfig().service_routes.auth + '/logout', {
method: 'POST',
headers,
})
.then(() => {
// Remove the cookie
removeCookie('kbase_session');
// Redirect to the legacy signed-out page
window.location.href =
Runtime.getConfig().host_root + '/#auth2/signedout';
.then(resp => {
if (resp.ok) {
// Remove the cookie
removeCookie('kbase_session');
// Redirect to the legacy signed-out page
window.location.href =
Runtime.getConfig().host_root + '/#auth2/signedout';
} else {
throw new Error(`${resp.status}: Failed to log out`);
}
})
.catch(err => {
console.error('Error signing out: ' + err);
Expand Down
74 changes: 74 additions & 0 deletions src/client/components/global_header/__tests__/Header.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,84 @@

import React from 'react';
import { shallow } from 'enzyme';
import {
enableFetchMocks,
FetchMock,
MockResponseInitFunction,
} from 'jest-fetch-mock';

import { Header } from '../Header';

import * as auth from '../../../utils/auth';
import * as cookies from '../../../utils/cookies';
import Runtime from '../../../utils/runtime';

enableFetchMocks();

describe('Header tests', () => {
it('<Header> should render', () =>
expect(shallow(<Header title="title" />)).toBeTruthy());

describe('Logout tests', () => {
let getTokenMock: jest.SpyInstance<string, []>;
let removeCookieMock: jest.SpyInstance<void, [string]>;
let logoutMock: FetchMock | undefined;
let header: Header;

const setLogoutMock = (respFunc: MockResponseInitFunction) => {
logoutMock = fetchMock.doMockIf(
Runtime.getConfig().service_routes.auth + '/logout',
respFunc
);
};

beforeAll(() => {
getTokenMock = jest.spyOn(auth, 'getToken').mockReturnValue('someToken');
removeCookieMock = jest.spyOn(cookies, 'removeCookie');
header = shallow<Header>(<Header title="title" />).instance();
});

afterEach(() => {
removeCookieMock.mockClear();
if (logoutMock) {
logoutMock.mockRestore();
logoutMock = undefined;
}
});

afterAll(() => {
getTokenMock.mockRestore();
removeCookieMock.mockRestore();
});

it('200 should trigger token purge', async () => {
setLogoutMock(async () => ({
status: 200,
}));

header.signOut();
await new Promise(setImmediate); // yield to event loop to allow pending promises to resolve
expect(removeCookieMock).toBeCalledWith('kbase_session');
});

it('404 should not trigger token purge', async () => {
setLogoutMock(async () => ({
status: 404,
}));

header.signOut();
await new Promise(setImmediate);
expect(removeCookieMock).not.toBeCalledWith('kbase_session');
});

it('Fetch failure (i.e. CORS failure) should not trigger token purge', async () => {
setLogoutMock(async () => {
throw new Error('test error');
});

header.signOut();
await new Promise(setImmediate);
expect(removeCookieMock).not.toBeCalledWith('kbase_session');
});
});
});
2 changes: 1 addition & 1 deletion src/client/utils/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function makeAuthCall(operation: string): Promise<any> {
throw new Error('Auth token not available.');
}
const headers = { Authorization: token };
return fetch(CONFIG.service_routes.auth + operation, {
return fetch(`${CONFIG.service_routes.auth}/api/V2${operation}`, {
method: 'GET',
headers,
}).then(resp => resp.json());
Expand Down
4 changes: 2 additions & 2 deletions src/client/utils/searchNarratives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ export default async function searchNarratives(
* sort parameter, auth (boolean, true if we're looking up personal data), and pageSize
*/
async function makeRequest(params: SearchParams): Promise<JSONRPCResponse> {
const headers: { [key: string]: string; } = {
const headers: { [key: string]: string } = {
'Content-Type': 'application/json',
};
if (!params.access || !params.access.only_public) {
Expand Down Expand Up @@ -248,7 +248,7 @@ async function makeRequest(params: SearchParams): Promise<JSONRPCResponse> {
// properties of that indicating the nature of the error, the most important
// of which is the "code" and "message".
// And, reporting the status to the user is not very useful, rather better to pick
// up the error message, and even better to process the entire error object which
// up the error message, and even better to process the entire error object which
// typically has useful additional information.
if (!result.ok) {
throw new Error('An error occurred while searching - ' + result.status);
Expand Down
2 changes: 1 addition & 1 deletion src/static/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"service_routes": {
"auth": "/auth/api/V2",
"auth": "/auth",
"narrative_method_store": "/narrative_method_store",
"catalog": "/catalog",
"workspace": "/ws",
Expand Down

0 comments on commit 2e2e73d

Please sign in to comment.