Skip to content

Commit 1a24d07

Browse files
committed
unit tests
1 parent 3bb6156 commit 1a24d07

File tree

5 files changed

+115
-16
lines changed

5 files changed

+115
-16
lines changed

src/lib/stores/auth-user.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const setAuthUser = (user: User, oidcFlow: OIDCFlow) => {
1313

1414
switch (oidcFlow) {
1515
case OIDCFlow.AuthorizationCode:
16+
default:
1617
if (!accessToken) {
1718
throw new Error('No access token');
1819
}

src/lib/utilities/is-authorized.test.ts

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,24 @@ import { describe, expect, it } from 'vitest';
22

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

5-
const user = {
6-
accessToken: 'xxx',
5+
const codeUser = {
6+
accessToken: 'accessToken',
7+
};
8+
9+
const implicitUser = {
10+
idToken: 'idToken',
711
};
812

913
const noUser = {
1014
name: 'name',
1115
email: 'email',
1216
picture: 'picture',
13-
idToken: 'idToken',
1417
};
1518

16-
const getSettings = (enabled: boolean) => ({
19+
const getSettings = (enabled: boolean, flow: string) => ({
1720
auth: {
1821
enabled,
22+
flow,
1923
options: [],
2024
},
2125
baseUrl: 'www.base.com',
@@ -29,16 +33,40 @@ const getSettings = (enabled: boolean) => ({
2933
});
3034

3135
describe('isAuthorized', () => {
32-
it('should return true if auth no enabled and no user', () => {
33-
expect(isAuthorized(getSettings(false), noUser)).toBe(true);
36+
it('should return true if auth not enabled and no user', () => {
37+
expect(isAuthorized(getSettings(false, 'authorization-code'), noUser)).toBe(
38+
true,
39+
);
40+
});
41+
it('should return true if auth not enabled and user', () => {
42+
expect(
43+
isAuthorized(getSettings(false, 'authorization-code'), codeUser),
44+
).toBe(true);
45+
});
46+
it('should return false if code auth enabled and no user', () => {
47+
expect(isAuthorized(getSettings(true, 'authorization-code'), noUser)).toBe(
48+
false,
49+
);
50+
});
51+
it('should return false if code auth enabled and implicit user', () => {
52+
expect(
53+
isAuthorized(getSettings(true, 'authorization-code'), implicitUser),
54+
).toBe(false);
55+
});
56+
it('should return true if code auth enabled and code user', () => {
57+
expect(
58+
isAuthorized(getSettings(true, 'authorization-code'), codeUser),
59+
).toBe(true);
3460
});
35-
it('should return true if auth no enabled and user', () => {
36-
expect(isAuthorized(getSettings(false), user)).toBe(true);
61+
it('should return false if implicit auth enabled and no user', () => {
62+
expect(isAuthorized(getSettings(true, 'implicit'), noUser)).toBe(false);
3763
});
38-
it('should return false if auth enabled and no user', () => {
39-
expect(isAuthorized(getSettings(true), noUser)).toBe(false);
64+
it('should return false if implicit auth enabled and implicit user', () => {
65+
expect(isAuthorized(getSettings(true, 'implicit'), codeUser)).toBe(false);
4066
});
41-
it('should return true if auth enabled and user', () => {
42-
expect(isAuthorized(getSettings(true), user)).toBe(true);
67+
it('should return true if implicit auth enabled and implicit user', () => {
68+
expect(isAuthorized(getSettings(true, 'implicit'), implicitUser)).toBe(
69+
true,
70+
);
4371
});
4472
});

src/lib/utilities/request-from-api.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ describe('requestFromAPI', () => {
110110
});
111111
});
112112

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

116116
const request = fetchMock();

src/lib/utilities/route-for.test.ts

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ describe('routeFor SSO authentication ', () => {
172172
it('Options added through settings should be passed in the url', () => {
173173
const settings = {
174174
auth: {
175+
flow: 'authorization-code',
175176
options: ['one'],
176177
},
177178
baseUrl: 'https://localhost/',
@@ -192,6 +193,7 @@ describe('routeFor SSO authentication ', () => {
192193
it('should fallback to the originUrl if returnUrl is not provided', () => {
193194
const settings = {
194195
auth: {
196+
flow: 'authorization-code',
195197
options: ['one'],
196198
},
197199
baseUrl: 'https://localhost/',
@@ -210,6 +212,7 @@ describe('routeFor SSO authentication ', () => {
210212
it('should use the returnUrl if provided', () => {
211213
const settings = {
212214
auth: {
215+
flow: 'authorization-code',
213216
options: ['one'],
214217
},
215218
baseUrl: 'https://localhost/',
@@ -229,6 +232,7 @@ describe('routeFor SSO authentication ', () => {
229232
it("should not add the options from the search param if they don't exist in the current url params", () => {
230233
const settings = {
231234
auth: {
235+
flow: 'authorization-code',
232236
options: ['one'],
233237
},
234238
baseUrl: 'https://localhost/',
@@ -245,7 +249,10 @@ describe('routeFor SSO authentication ', () => {
245249
});
246250

247251
it('Should render a login url', () => {
248-
const settings = { auth: {}, baseUrl: 'https://localhost' };
252+
const settings = {
253+
auth: { flow: 'authorization-code' },
254+
baseUrl: 'https://localhost',
255+
};
249256
const searchParams = new URLSearchParams();
250257

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

256263
it('Should add return URL search param', () => {
257-
const settings = { auth: {}, baseUrl: 'https://localhost' };
264+
const settings = {
265+
auth: { flow: 'authorization-code' },
266+
baseUrl: 'https://localhost',
267+
};
258268

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

273283
it('Should not add return URL search param if undefined', () => {
274-
const settings = { auth: {}, baseUrl: 'https://localhost' };
284+
const settings = {
285+
auth: { flow: 'authorization-code' },
286+
baseUrl: 'https://localhost',
287+
};
275288

276289
const searchParams = new URLSearchParams();
277290
const sso = routeForAuthentication({ settings, searchParams });
@@ -283,6 +296,7 @@ describe('routeFor SSO authentication ', () => {
283296
it('test of the signin flow', () => {
284297
const settings = {
285298
auth: {
299+
flow: 'authorization-code',
286300
options: ['organization_name', 'invitation'],
287301
},
288302
baseUrl: 'https://localhost/',
@@ -302,6 +316,56 @@ describe('routeFor SSO authentication ', () => {
302316
);
303317
});
304318

319+
describe('implicit oidc flow', () => {
320+
it('should add a nonce', () => {
321+
const settings = {
322+
auth: {
323+
flow: 'implicit',
324+
authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
325+
scopes: ['openid', 'email', 'profile'],
326+
},
327+
baseUrl: 'https://localhost',
328+
};
329+
330+
const searchParams = new URLSearchParams();
331+
332+
const sso = routeForAuthentication({
333+
settings,
334+
searchParams,
335+
});
336+
337+
const ssoUrl = new URL(sso);
338+
expect(window.localStorage.getItem('nonce')).toBe(
339+
ssoUrl.searchParams.get('nonce'),
340+
);
341+
});
342+
343+
it('should manage state', () => {
344+
const settings = {
345+
auth: {
346+
flow: 'implicit',
347+
authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
348+
scopes: ['openid', 'email', 'profile'],
349+
},
350+
baseUrl: 'https://localhost',
351+
};
352+
353+
const searchParams = new URLSearchParams();
354+
searchParams.set('returnUrl', 'https://localhost/some/path');
355+
356+
const sso = routeForAuthentication({
357+
settings,
358+
searchParams,
359+
});
360+
361+
const ssoUrlStateKey = new URL(sso).searchParams.get('state');
362+
expect(ssoUrlStateKey).not.toBeNull();
363+
expect(window.sessionStorage.getItem(ssoUrlStateKey as string)).toBe(
364+
'https://localhost/some/path',
365+
);
366+
});
367+
});
368+
305369
describe('routeForLoginPage', () => {
306370
afterEach(() => {
307371
vi.clearAllMocks();

src/lib/utilities/route-for.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ export const routeForAuthentication = (
188188
const { settings, searchParams: currentSearchParams, originUrl } = parameters;
189189
switch (settings.auth.flow) {
190190
case OIDCFlow.AuthorizationCode:
191+
default:
191192
return routeForAuthorizationCodeFlow(
192193
settings,
193194
currentSearchParams,
@@ -298,6 +299,11 @@ export const routeForOIDCImplicitCallback = (): string => {
298299

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

302+
if (!token.nonce) {
303+
throw new OIDCImplicitCallbackError('No nonce in token');
304+
} else if (token.nonce !== nonce) {
305+
throw new OIDCImplicitCallbackError('Mismatched nonces');
306+
}
301307
if (!token.nonce) {
302308
throw new OIDCImplicitCallbackError('No nonce in token');
303309
} else if (token.nonce !== nonce) {

0 commit comments

Comments
 (0)