refactor: extract a create cookie middleware

Signed-off-by: Camila Belo <camilaibs@gmail.com>
This commit is contained in:
Camila Belo
2024-03-18 10:27:26 +01:00
committed by Patrik Oldsberg
parent 7b77befdfb
commit f17da85b08
9 changed files with 56 additions and 12 deletions
@@ -14,13 +14,14 @@
* limitations under the License.
*/
import { Handler } from 'express';
import PromiseRouter from 'express-promise-router';
import {
coreServices,
createServiceFactory,
HttpRouterServiceAuthPolicy,
} from '@backstage/backend-plugin-api';
import { Handler } from 'express';
import PromiseRouter from 'express-promise-router';
import { createCookieAuthRefreshMiddleware } from '@backstage/plugin-auth-node';
import { createLifecycleMiddleware } from './createLifecycleMiddleware';
import { createCredentialsBarrier } from './createCredentialsBarrier';
import { createAuthIntegrationRouter } from './createAuthIntegrationRouter';
@@ -85,12 +86,8 @@ export const httpRouterServiceFactory = createServiceFactory(
addAuthPolicy(policy: HttpRouterServiceAuthPolicy): void {
credentialsBarrier.addAuthPolicy(policy);
if (policy.allow === 'user-cookie') {
// Endpoint that sets the cookie for the user
// TODO: Extract this to a separate createCookieAuthRefreshMiddleware function
router.get('/.backstage/v1-cookie', async (_, res) => {
const { expiresAt } = await httpAuth.issueUserCookie(res);
res.json({ expiresAt: expiresAt.toISOString() });
});
// TODO: Make sure this is only added once
router.use(createCookieAuthRefreshMiddleware({ httpAuth }));
}
},
};
+1
View File
@@ -51,6 +51,7 @@
"@backstage/config-loader": "workspace:^",
"@backstage/errors": "workspace:^",
"@backstage/plugin-app-node": "workspace:^",
"@backstage/plugin-auth-node": "workspace:^",
"@backstage/types": "workspace:^",
"@types/express": "^4.17.6",
"express": "^4.17.1",
+2 -2
View File
@@ -40,6 +40,7 @@ import {
import { ConfigSchema } from '@backstage/config-loader';
import { AuthService, HttpAuthService } from '@backstage/backend-plugin-api';
import { AuthenticationError } from '@backstage/errors';
import { createCookieAuthRefreshMiddleware } from '@backstage/plugin-auth-node';
// express uses mime v1 while we only have types for mime v2
type Mime = { lookup(arg0: string): string };
@@ -184,8 +185,7 @@ export async function createRouter(
if (enablePublicEntryPoint && auth && httpAuth) {
const publicRouter = Router();
// TODO
// publicRouter.use(createCookieAuthRouter({ httpAuth }))
publicRouter.use(createCookieAuthRefreshMiddleware({ httpAuth }));
publicRouter.use(async (req, _res, next) => {
const credentials = await httpAuth.credentials(req, {
+7
View File
@@ -10,6 +10,7 @@ import { Entity } from '@backstage/catalog-model';
import { EntityFilterQuery } from '@backstage/catalog-client';
import express from 'express';
import { ExtensionPoint } from '@backstage/backend-plugin-api';
import { HttpAuthService } from '@backstage/backend-plugin-api';
import { JsonObject } from '@backstage/types';
import { JsonValue } from '@backstage/types';
import { LoggerService } from '@backstage/backend-plugin-api';
@@ -17,6 +18,7 @@ import { PluginEndpointDiscovery } from '@backstage/backend-common';
import { Profile } from 'passport';
import { Request as Request_2 } from 'express';
import { Response as Response_2 } from 'express';
import { Router } from 'express-serve-static-core';
import { Strategy } from 'passport';
import { ZodSchema } from 'zod';
import { ZodTypeDef } from 'zod';
@@ -148,6 +150,11 @@ export type CookieConfigurer = (ctx: {
sameSite?: 'none' | 'lax' | 'strict';
};
// @public
export function createCookieAuthRefreshMiddleware(options: {
httpAuth: HttpAuthService;
}): Router;
// @public (undocumented)
export function createOAuthAuthenticator<TContext, TProfile>(
authenticator: OAuthAuthenticator<TContext, TProfile>,
@@ -0,0 +1,37 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { HttpAuthService } from '@backstage/backend-plugin-api';
import { Router } from 'express';
/**
* @public
* Creates a middleware that can be used to refresh the cookie for the user.
*/
export function createCookieAuthRefreshMiddleware(options: {
httpAuth: HttpAuthService;
}) {
const { httpAuth } = options;
const router = Router();
// Endpoint that sets the cookie for the user
router.get('/.backstage/v1-cookie', async (_, res) => {
const { expiresAt } = await httpAuth.issueUserCookie(res);
res.json({ expiresAt: expiresAt.toISOString() });
});
return router;
}
+1
View File
@@ -22,3 +22,4 @@ export {
} from './DefaultIdentityClient';
export { IdentityClient } from './IdentityClient';
export type { IdentityApi, IdentityApiGetIdentityRequest } from './IdentityApi';
export { createCookieAuthRefreshMiddleware } from './createCookieAuthRefreshMiddleware';
@@ -119,7 +119,7 @@ describe('CookieAuthRefreshProvider', () => {
await waitFor(() =>
expect(fetchApiMock.fetch).toHaveBeenCalledWith(
'http://localhost:7000/techdocs/api/cookie',
'http://localhost:7000/techdocs/api/.backstage/v1-cookie',
{ credentials: 'include' },
),
);
@@ -236,7 +236,7 @@ describe('useCookieAuthRefresh', () => {
await waitFor(() =>
expect(fetchApiMock.fetch).toHaveBeenCalledWith(
'http://localhost:7000/techdocs/api/cookie',
'http://localhost:7000/techdocs/api/.backstage/v1-cookie',
{ credentials: 'include' },
),
);
+1
View File
@@ -4693,6 +4693,7 @@ __metadata:
"@backstage/config-loader": "workspace:^"
"@backstage/errors": "workspace:^"
"@backstage/plugin-app-node": "workspace:^"
"@backstage/plugin-auth-node": "workspace:^"
"@backstage/types": "workspace:^"
"@types/express": ^4.17.6
"@types/supertest": ^2.0.8