Merge pull request #498 from lowdefy/fix-netlify-openid

fix(server-netlify): Fix auth token cookie path.
This commit is contained in:
Gervwyk 2021-03-18 11:53:49 +02:00 committed by GitHub
commit ec980dfaa7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 81 additions and 7 deletions

View File

@ -22,11 +22,12 @@ import createGetLoader from './getLoader';
import verifyAccessToken from './verifyAccessToken';
function createContext(config) {
const { CONFIGURATION_BASE_PATH, development, getSecrets, logger } = config;
const { CONFIGURATION_BASE_PATH, development, getSecrets, logger, gqlUri } = config;
const bootstrapContext = {
CONFIGURATION_BASE_PATH,
development,
getSecrets,
gqlUri,
logger,
};

View File

@ -19,7 +19,7 @@
import { get } from '@lowdefy/helpers';
import cookie from 'cookie';
async function verifyAccessToken({ development, headers, getController, setHeader }) {
async function verifyAccessToken({ development, headers, getController, gqlUri, setHeader }) {
const cookieHeader = get(headers, 'Cookie') || get(headers, 'cookie') || '';
const { authorization } = cookie.parse(cookieHeader);
if (!authorization) return {};
@ -37,7 +37,7 @@ async function verifyAccessToken({ development, headers, getController, setHeade
} catch (error) {
const setCookieHeader = cookie.serialize('authorization', '', {
httpOnly: true,
path: '/api/graphql',
path: gqlUri || '/api/graphql',
sameSite: 'lax',
secure: !development,
maxAge: 0,

View File

@ -122,3 +122,22 @@ test('development header', async () => {
['Set-Cookie', 'authorization=; Max-Age=0; Path=/api/graphql; HttpOnly; SameSite=Lax'],
]);
});
test('configure gqlUri', async () => {
const cookie = await createCookieHeader({ expired: true });
let bootstrapContext = testBootstrapContext({
headers: { cookie },
getSecrets,
gqlUri: '/custom/graphql',
setHeader,
});
await expect(verifyAccessToken(bootstrapContext)).rejects.toThrow(TokenExpiredError);
expect(setHeader.mock.calls).toEqual([
[
'Set-Cookie',
'authorization=; Max-Age=0; Path=/custom/graphql; HttpOnly; Secure; SameSite=Lax',
],
]);
await expect(verifyAccessToken(bootstrapContext)).rejects.toThrow('Token expired.');
});

View File

@ -21,7 +21,7 @@ import cookie from 'cookie';
import { AuthenticationError, ConfigurationError } from '../context/errors';
class OpenIdController {
constructor({ development, getController, getLoader, getSecrets, host, setHeader }) {
constructor({ development, getController, getLoader, getSecrets, gqlUri, host, setHeader }) {
const httpPrefix = development ? 'http' : 'https';
this.development = development;
@ -29,6 +29,7 @@ class OpenIdController {
this.getSecrets = getSecrets;
this.host = host;
this.redirectUri = `${httpPrefix}://${host}/auth/openid-callback`;
this.gqlUri = gqlUri || '/api/graphql';
this.setHeader = setHeader;
this.tokenController = getController('token');
}
@ -102,7 +103,7 @@ class OpenIdController {
const accessToken = await this.tokenController.issueAccessToken(claims);
const setCookieHeader = cookie.serialize('authorization', accessToken, {
httpOnly: true,
path: '/api/graphql',
path: this.gqlUri,
sameSite: 'lax',
secure: !this.development,
});
@ -140,7 +141,7 @@ class OpenIdController {
try {
const setCookieHeader = cookie.serialize('authorization', '', {
httpOnly: true,
path: '/api/graphql',
path: this.gqlUri,
sameSite: 'lax',
secure: !this.development,
maxAge: 0,

View File

@ -320,6 +320,27 @@ describe('callback', () => {
);
expect(setHeader.mock.calls).toEqual([]);
});
test('configure gqlUri', async () => {
getSecrets.mockImplementation(() => secrets);
const testContext = testBootstrapContext({
getSecrets,
gqlUri: '/custom/graphql',
host: 'host',
loaders,
setHeader,
});
const openIdController = createOpenIdController(testContext);
const tokenController = createTokenController(testContext);
const state = await tokenController.issueOpenIdStateToken(authorizationUrlInput);
await openIdController.callback({ code: 'code', state });
expect(setHeader.mock.calls).toEqual([
[
'Set-Cookie',
'authorization=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWIiLCJsb3dkZWZ5X2FjY2Vzc190b2tlbiI6dHJ1ZSwiaWF0IjoxLCJleHAiOjE0NDAxLCJhdWQiOiJob3N0IiwiaXNzIjoiaG9zdCJ9.oADZ37ERfvONPBGiFsStQUOEHO6BaX_zkGXCHY8PbRA; Path=/custom/graphql; HttpOnly; Secure; SameSite=Lax',
],
]);
});
});
describe('logout', () => {
@ -476,4 +497,23 @@ describe('logout', () => {
],
]);
});
test('configure gqlUri', async () => {
const testContext = testBootstrapContext({
getSecrets,
gqlUri: '/custom/graphql',
host: 'host',
loaders,
setHeader,
});
getSecrets.mockImplementation(() => secrets);
const openIdController = createOpenIdController(testContext);
await openIdController.logoutUrl(logoutUrlInput);
expect(setHeader.mock.calls).toEqual([
[
'Set-Cookie',
'authorization=; Max-Age=0; Path=/custom/graphql; HttpOnly; Secure; SameSite=Lax',
],
]);
});
});

View File

@ -19,6 +19,7 @@ import createGetController from '../controllers/getController';
function testBootstrapContext({
development,
getSecrets,
gqlUri,
headers,
host,
loaders,
@ -31,6 +32,7 @@ function testBootstrapContext({
getController: () => {},
getLoader: loaders ? (name) => loaders[name] : () => {},
getSecrets: getSecrets || (() => {}),
gqlUri,
headers: headers || {},
host: host || 'host',
logger: { log: () => {} },
@ -41,11 +43,21 @@ function testBootstrapContext({
return bootstrapContext;
}
function testContext({ development, getSecrets, host, loaders, setHeader, user, headers } = {}) {
function testContext({
development,
getSecrets,
gqlUri,
host,
loaders,
setHeader,
user,
headers,
} = {}) {
const bootstrapContext = {
development,
getLoader: (name) => loaders[name],
getSecrets: getSecrets || (() => {}),
gqlUri,
host: host || 'host',
headers: headers || {},
logger: { log: () => {} },

View File

@ -24,6 +24,7 @@ import { createGetSecretsFromEnv } from '@lowdefy/node-utils';
const config = {
CONFIGURATION_BASE_PATH: path.resolve(__dirname, './build'),
getSecrets: createGetSecretsFromEnv(),
gqlUri: '/.netlify/functions/graphql',
logger: console,
};