Skip to content

Commit

Permalink
unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bgerrity committed Mar 18, 2024
1 parent 3bb6156 commit 1a24d07
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 16 deletions.
1 change: 1 addition & 0 deletions src/lib/stores/auth-user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const setAuthUser = (user: User, oidcFlow: OIDCFlow) => {

switch (oidcFlow) {
case OIDCFlow.AuthorizationCode:
default:
if (!accessToken) {
throw new Error('No access token');
}
Expand Down
52 changes: 40 additions & 12 deletions src/lib/utilities/is-authorized.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@ import { describe, expect, it } from 'vitest';

import { isAuthorized } from './is-authorized';

const user = {
accessToken: 'xxx',
const codeUser = {
accessToken: 'accessToken',
};

const implicitUser = {
idToken: 'idToken',
};

const noUser = {
name: 'name',
email: 'email',
picture: 'picture',
idToken: 'idToken',
};

const getSettings = (enabled: boolean) => ({
const getSettings = (enabled: boolean, flow: string) => ({
auth: {
enabled,
flow,
options: [],
},
baseUrl: 'www.base.com',
Expand All @@ -29,16 +33,40 @@ const getSettings = (enabled: boolean) => ({
});

describe('isAuthorized', () => {
it('should return true if auth no enabled and no user', () => {
expect(isAuthorized(getSettings(false), noUser)).toBe(true);
it('should return true if auth not enabled and no user', () => {
expect(isAuthorized(getSettings(false, 'authorization-code'), noUser)).toBe(
true,
);
});
it('should return true if auth not enabled and user', () => {
expect(
isAuthorized(getSettings(false, 'authorization-code'), codeUser),
).toBe(true);
});
it('should return false if code auth enabled and no user', () => {
expect(isAuthorized(getSettings(true, 'authorization-code'), noUser)).toBe(
false,
);
});
it('should return false if code auth enabled and implicit user', () => {
expect(
isAuthorized(getSettings(true, 'authorization-code'), implicitUser),
).toBe(false);
});
it('should return true if code auth enabled and code user', () => {
expect(
isAuthorized(getSettings(true, 'authorization-code'), codeUser),
).toBe(true);
});
it('should return true if auth no enabled and user', () => {
expect(isAuthorized(getSettings(false), user)).toBe(true);
it('should return false if implicit auth enabled and no user', () => {
expect(isAuthorized(getSettings(true, 'implicit'), noUser)).toBe(false);
});
it('should return false if auth enabled and no user', () => {
expect(isAuthorized(getSettings(true), noUser)).toBe(false);
it('should return false if implicit auth enabled and implicit user', () => {
expect(isAuthorized(getSettings(true, 'implicit'), codeUser)).toBe(false);
});
it('should return true if auth enabled and user', () => {
expect(isAuthorized(getSettings(true), user)).toBe(true);
it('should return true if implicit auth enabled and implicit user', () => {
expect(isAuthorized(getSettings(true, 'implicit'), implicitUser)).toBe(
true,
);
});
});
2 changes: 1 addition & 1 deletion src/lib/utilities/request-from-api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ describe('requestFromAPI', () => {
});
});

it('should not add csrf cookie to headers if not presdent', async () => {
it('should not add csrf cookie to headers if not present', async () => {
const token = 'token';

const request = fetchMock();
Expand Down
70 changes: 67 additions & 3 deletions src/lib/utilities/route-for.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ describe('routeFor SSO authentication ', () => {
it('Options added through settings should be passed in the url', () => {
const settings = {
auth: {
flow: 'authorization-code',
options: ['one'],
},
baseUrl: 'https://localhost/',
Expand All @@ -192,6 +193,7 @@ describe('routeFor SSO authentication ', () => {
it('should fallback to the originUrl if returnUrl is not provided', () => {
const settings = {
auth: {
flow: 'authorization-code',
options: ['one'],
},
baseUrl: 'https://localhost/',
Expand All @@ -210,6 +212,7 @@ describe('routeFor SSO authentication ', () => {
it('should use the returnUrl if provided', () => {
const settings = {
auth: {
flow: 'authorization-code',
options: ['one'],
},
baseUrl: 'https://localhost/',
Expand All @@ -229,6 +232,7 @@ describe('routeFor SSO authentication ', () => {
it("should not add the options from the search param if they don't exist in the current url params", () => {
const settings = {
auth: {
flow: 'authorization-code',
options: ['one'],
},
baseUrl: 'https://localhost/',
Expand All @@ -245,7 +249,10 @@ describe('routeFor SSO authentication ', () => {
});

it('Should render a login url', () => {
const settings = { auth: {}, baseUrl: 'https://localhost' };
const settings = {
auth: { flow: 'authorization-code' },
baseUrl: 'https://localhost',
};
const searchParams = new URLSearchParams();

const sso = routeForAuthentication({ settings, searchParams });
Expand All @@ -254,7 +261,10 @@ describe('routeFor SSO authentication ', () => {
});

it('Should add return URL search param', () => {
const settings = { auth: {}, baseUrl: 'https://localhost' };
const settings = {
auth: { flow: 'authorization-code' },
baseUrl: 'https://localhost',
};

const searchParams = new URLSearchParams();
searchParams.set('returnUrl', 'https://localhost/some/path');
Expand All @@ -271,7 +281,10 @@ describe('routeFor SSO authentication ', () => {
});

it('Should not add return URL search param if undefined', () => {
const settings = { auth: {}, baseUrl: 'https://localhost' };
const settings = {
auth: { flow: 'authorization-code' },
baseUrl: 'https://localhost',
};

const searchParams = new URLSearchParams();
const sso = routeForAuthentication({ settings, searchParams });
Expand All @@ -283,6 +296,7 @@ describe('routeFor SSO authentication ', () => {
it('test of the signin flow', () => {
const settings = {
auth: {
flow: 'authorization-code',
options: ['organization_name', 'invitation'],
},
baseUrl: 'https://localhost/',
Expand All @@ -302,6 +316,56 @@ describe('routeFor SSO authentication ', () => {
);
});

describe('implicit oidc flow', () => {
it('should add a nonce', () => {
const settings = {
auth: {
flow: 'implicit',
authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
scopes: ['openid', 'email', 'profile'],
},
baseUrl: 'https://localhost',
};

const searchParams = new URLSearchParams();

const sso = routeForAuthentication({
settings,
searchParams,
});

const ssoUrl = new URL(sso);
expect(window.localStorage.getItem('nonce')).toBe(
ssoUrl.searchParams.get('nonce'),
);
});

it('should manage state', () => {
const settings = {
auth: {
flow: 'implicit',
authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
scopes: ['openid', 'email', 'profile'],
},
baseUrl: 'https://localhost',
};

const searchParams = new URLSearchParams();
searchParams.set('returnUrl', 'https://localhost/some/path');

const sso = routeForAuthentication({
settings,
searchParams,
});

const ssoUrlStateKey = new URL(sso).searchParams.get('state');
expect(ssoUrlStateKey).not.toBeNull();
expect(window.sessionStorage.getItem(ssoUrlStateKey as string)).toBe(
'https://localhost/some/path',
);
});
});

describe('routeForLoginPage', () => {
afterEach(() => {
vi.clearAllMocks();
Expand Down
6 changes: 6 additions & 0 deletions src/lib/utilities/route-for.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ export const routeForAuthentication = (
const { settings, searchParams: currentSearchParams, originUrl } = parameters;
switch (settings.auth.flow) {
case OIDCFlow.AuthorizationCode:
default:
return routeForAuthorizationCodeFlow(
settings,
currentSearchParams,
Expand Down Expand Up @@ -298,6 +299,11 @@ export const routeForOIDCImplicitCallback = (): string => {

// TODO: support optional issuer validation with settings.auth.issuerUrl and token.iss

if (!token.nonce) {
throw new OIDCImplicitCallbackError('No nonce in token');
} else if (token.nonce !== nonce) {
throw new OIDCImplicitCallbackError('Mismatched nonces');
}
if (!token.nonce) {
throw new OIDCImplicitCallbackError('No nonce in token');
} else if (token.nonce !== nonce) {
Expand Down

0 comments on commit 1a24d07

Please sign in to comment.