mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-11 03:26:58 +02:00
[Plugins] [Auth] [oauth2] Support identity platforms with underlying IDPs (#261)
Co-authored-by: Gregory Schier <gschier1990@gmail.com>
This commit is contained in:
109
plugins/auth-oauth2/tests/util.test.ts
Normal file
109
plugins/auth-oauth2/tests/util.test.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { extractCode } from '../src/util';
|
||||
|
||||
describe('extractCode', () => {
|
||||
test('extracts code from query when same origin + path', () => {
|
||||
const url = 'https://app.example.com/cb?code=abc123&state=xyz';
|
||||
const redirect = 'https://app.example.com/cb';
|
||||
expect(extractCode(url, redirect)).toBe('abc123');
|
||||
});
|
||||
|
||||
test('extracts code from query with weird path', () => {
|
||||
const url = 'https://app.example.com/cbwithextra?code=abc123&state=xyz';
|
||||
const redirect = 'https://app.example.com/cb';
|
||||
expect(extractCode(url, redirect)).toBeNull();
|
||||
});
|
||||
|
||||
test('allows trailing slash differences', () => {
|
||||
expect(extractCode('https://app.example.com/cb/?code=abc', 'https://app.example.com/cb')).toBe(
|
||||
'abc',
|
||||
);
|
||||
expect(extractCode('https://app.example.com/cb?code=abc', 'https://app.example.com/cb/')).toBe(
|
||||
'abc',
|
||||
);
|
||||
});
|
||||
|
||||
test('treats default ports as equal (https:443, http:80)', () => {
|
||||
expect(
|
||||
extractCode('https://app.example.com/cb?code=abc', 'https://app.example.com:443/cb'),
|
||||
).toBe('abc');
|
||||
expect(extractCode('http://app.example.com/cb?code=abc', 'http://app.example.com:80/cb')).toBe(
|
||||
'abc',
|
||||
);
|
||||
});
|
||||
|
||||
test('rejects different port', () => {
|
||||
expect(
|
||||
extractCode('https://app.example.com/cb?code=abc', 'https://app.example.com:8443/cb'),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
test('rejects different hostname (including subdomain changes)', () => {
|
||||
expect(
|
||||
extractCode('https://evil.example.com/cb?code=abc', 'https://app.example.com/cb'),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
test('requires path to start with redirect path (ignoring query/hash)', () => {
|
||||
// same origin but wrong path -> null
|
||||
expect(
|
||||
extractCode('https://app.example.com/other?code=abc', 'https://app.example.com/cb'),
|
||||
).toBeNull();
|
||||
|
||||
// deeper subpath under the redirect path -> allowed (prefix match)
|
||||
expect(
|
||||
extractCode('https://app.example.com/cb/deep?code=abc', 'https://app.example.com/cb'),
|
||||
).toBe('abc');
|
||||
});
|
||||
|
||||
test('works with custom schemes', () => {
|
||||
expect(extractCode('myapp://cb?code=abc', 'myapp://cb')).toBe('abc');
|
||||
});
|
||||
|
||||
test('prefers query over fragment when both present', () => {
|
||||
const url = 'https://app.example.com/cb?code=queryCode#code=hashCode';
|
||||
const redirect = 'https://app.example.com/cb';
|
||||
expect(extractCode(url, redirect)).toBe('queryCode');
|
||||
});
|
||||
|
||||
test('extracts code from fragment when query lacks code', () => {
|
||||
const url = 'https://app.example.com/cb#code=fromHash&state=xyz';
|
||||
const redirect = 'https://app.example.com/cb';
|
||||
expect(extractCode(url, redirect)).toBe('fromHash');
|
||||
});
|
||||
|
||||
test('returns null if no code present (query or fragment)', () => {
|
||||
const url = 'https://app.example.com/cb?state=only';
|
||||
const redirect = 'https://app.example.com/cb';
|
||||
expect(extractCode(url, redirect)).toBeNull();
|
||||
});
|
||||
|
||||
test('returns null when provider reports an error', () => {
|
||||
const url = 'https://app.example.com/cb?error=access_denied&error_description=oopsy';
|
||||
const redirect = 'https://app.example.com/cb';
|
||||
expect(() => extractCode(url, redirect)).toThrow('Failed to authorize: access_denied');
|
||||
});
|
||||
|
||||
test('when redirectUri is null, extracts code from any URL', () => {
|
||||
expect(extractCode('https://random.example.com/whatever?code=abc', null)).toBe('abc');
|
||||
});
|
||||
|
||||
test('handles extra params gracefully', () => {
|
||||
const url = 'https://app.example.com/cb?foo=1&bar=2&code=abc&baz=3';
|
||||
const redirect = 'https://app.example.com/cb';
|
||||
expect(extractCode(url, redirect)).toBe('abc');
|
||||
});
|
||||
|
||||
test('ignores fragment noise when code is in query', () => {
|
||||
const url = 'https://app.example.com/cb?code=abc#some=thing';
|
||||
const redirect = 'https://app.example.com/cb';
|
||||
expect(extractCode(url, redirect)).toBe('abc');
|
||||
});
|
||||
|
||||
// If you decide NOT to support fragment-based codes, flip these to expect null or mark as .skip
|
||||
test('supports fragment-only code for response_mode=fragment providers', () => {
|
||||
const url = 'https://app.example.com/cb#state=xyz&code=abc';
|
||||
const redirect = 'https://app.example.com/cb';
|
||||
expect(extractCode(url, redirect)).toBe('abc');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user