mirror of
https://github.com/seerr-team/seerr.git
synced 2026-06-15 11:59:11 -04:00
fix: ensure that OIDC correlation cookies are present in callback
This commit is contained in:
@@ -768,5 +768,63 @@ describe('OpenID Connect', () => {
|
||||
assert.strictEqual(response.status, 403);
|
||||
assert.strictEqual(response.body.error, ApiErrorCode.Unauthorized);
|
||||
});
|
||||
|
||||
it('rejects callback when correlation cookies are missing', async function () {
|
||||
await setupFetchMock();
|
||||
|
||||
const callbackUrl = new URL(OIDC_REDIRECT_URL);
|
||||
callbackUrl.searchParams.set('code', '123456');
|
||||
callbackUrl.searchParams.set('state', 'somestate');
|
||||
|
||||
// Send callback with no signed cookies at all
|
||||
const response = await request(app)
|
||||
.post('/auth/oidc/callback/test')
|
||||
.set('Accept', 'application/json')
|
||||
.send({ callbackUrl: callbackUrl.toString() });
|
||||
|
||||
assert.strictEqual(response.status, 400);
|
||||
assert.strictEqual(
|
||||
response.body.error,
|
||||
ApiErrorCode.OidcAuthorizationFailed
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects callback when only one correlation cookie is present', async function () {
|
||||
await setupFetchMock();
|
||||
|
||||
// Perform login to get only the state cookie
|
||||
const loginResponse = await request(app)
|
||||
.get('/auth/oidc/login/test')
|
||||
.set('Accept', 'application/json');
|
||||
|
||||
assert.strictEqual(loginResponse.status, 200);
|
||||
|
||||
const redirectUrl = new URL(loginResponse.body.redirectUrl);
|
||||
const state = redirectUrl.searchParams.get('state');
|
||||
|
||||
// Extract only the state cookie, dropping the PKCE verifier cookie
|
||||
const cookies = loginResponse.get('Set-Cookie');
|
||||
assert.notStrictEqual(cookies, undefined);
|
||||
const stateCookieOnly = cookies!
|
||||
.filter((c) => c.includes('oidc-state'))
|
||||
.map((c) => c.split(';')[0])
|
||||
.join('; ');
|
||||
|
||||
const callbackUrl = new URL(OIDC_REDIRECT_URL);
|
||||
callbackUrl.searchParams.set('code', '123456');
|
||||
if (state) callbackUrl.searchParams.set('state', state);
|
||||
|
||||
const response = await request(app)
|
||||
.post('/auth/oidc/callback/test')
|
||||
.set('Accept', 'application/json')
|
||||
.set('Cookie', stateCookieOnly)
|
||||
.send({ callbackUrl: callbackUrl.toString() });
|
||||
|
||||
assert.strictEqual(response.status, 400);
|
||||
assert.strictEqual(
|
||||
response.body.error,
|
||||
ApiErrorCode.OidcAuthorizationFailed
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -798,6 +798,19 @@ authRoutes.post(
|
||||
const pkceCodeVerifier: string | undefined =
|
||||
req.signedCookies[OIDC_CODE_VERIFIER_KEY];
|
||||
const expectedState: string | undefined = req.signedCookies[OIDC_STATE_KEY];
|
||||
|
||||
if (!pkceCodeVerifier || !expectedState) {
|
||||
logger.warn('Rejected OIDC callback without correlation cookies', {
|
||||
label: 'Auth',
|
||||
provider: provider.slug,
|
||||
ip: req.ip,
|
||||
});
|
||||
return next({
|
||||
status: 400,
|
||||
error: ApiErrorCode.OidcAuthorizationFailed,
|
||||
});
|
||||
}
|
||||
|
||||
res.clearCookie(OIDC_CODE_VERIFIER_KEY);
|
||||
res.clearCookie(OIDC_STATE_KEY);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user