backend-{plugin,app}-api: added addAuthPolicy to HttpRouterService + implementation
Co-authored-by: Fredrik Adelöw <freben@gmail.com> Co-authored-by: Carl-Erik Bergström <cbergstrom@spotify.com> Co-authored-by: blam <ben@blam.sh> Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -73,6 +73,7 @@
|
||||
"minimist": "^1.2.5",
|
||||
"morgan": "^1.10.0",
|
||||
"node-forge": "^1.3.1",
|
||||
"path-to-regexp": "^6.2.1",
|
||||
"selfsigned": "^2.0.0",
|
||||
"stoppable": "^1.1.0",
|
||||
"winston": "^3.2.1",
|
||||
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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,
|
||||
HttpRouterServiceAuthPolicy,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { RequestHandler } from 'express';
|
||||
import { pathToRegexp } from 'path-to-regexp';
|
||||
|
||||
export function createPathPolicyPredicate(policyPath: string) {
|
||||
if (policyPath === '/' || policyPath === '*') {
|
||||
return () => true;
|
||||
}
|
||||
|
||||
const pathRegex = pathToRegexp(policyPath, undefined, {
|
||||
end: false,
|
||||
});
|
||||
|
||||
return (path: string): boolean => {
|
||||
return pathRegex.test(path);
|
||||
};
|
||||
}
|
||||
|
||||
export function createCredentialsBarrier(options: {
|
||||
httpAuth: HttpAuthService;
|
||||
}): {
|
||||
middleware: RequestHandler;
|
||||
addAuthPolicy: (policy: HttpRouterServiceAuthPolicy) => void;
|
||||
} {
|
||||
const { httpAuth } = options;
|
||||
|
||||
const unauthenticatedPredicates = new Array<(path: string) => boolean>();
|
||||
const cookiePredicates = new Array<(path: string) => boolean>();
|
||||
|
||||
const middleware: RequestHandler = async (req, _, next) => {
|
||||
const allowsUnauthenticated = unauthenticatedPredicates.some(predicate =>
|
||||
predicate(req.path),
|
||||
);
|
||||
|
||||
if (allowsUnauthenticated) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
const allowsCookie = cookiePredicates.some(predicate =>
|
||||
predicate(req.path),
|
||||
);
|
||||
|
||||
if (allowsCookie) {
|
||||
// don't we need a user-cookie allow type here?
|
||||
await httpAuth.credentials(req, {
|
||||
allow: ['user-cookie', 'user', 'service'],
|
||||
});
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
await httpAuth.credentials(req, {
|
||||
allow: ['user', 'service'],
|
||||
});
|
||||
next();
|
||||
};
|
||||
|
||||
const addAuthPolicy = (policy: HttpRouterServiceAuthPolicy) => {
|
||||
if (policy.allow === 'unauthenticated') {
|
||||
unauthenticatedPredicates.push(createPathPolicyPredicate(policy.path));
|
||||
} else if (policy.allow === 'user-cookie') {
|
||||
cookiePredicates.push(createPathPolicyPredicate(policy.path));
|
||||
}
|
||||
|
||||
throw new Error('Invalid auth policy');
|
||||
};
|
||||
|
||||
return { middleware, addAuthPolicy };
|
||||
}
|
||||
@@ -299,10 +299,20 @@ export interface HttpAuthService {
|
||||
|
||||
// @public (undocumented)
|
||||
export interface HttpRouterService {
|
||||
// (undocumented)
|
||||
addAuthPolicy(policy: HttpRouterServiceAuthPolicy): void;
|
||||
// (undocumented)
|
||||
use(handler: Handler): void;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface HttpRouterServiceAuthPolicy {
|
||||
// (undocumented)
|
||||
allow: 'unauthenticated' | 'user-cookie';
|
||||
// (undocumented)
|
||||
path: string;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface IdentityService extends IdentityApi {}
|
||||
|
||||
|
||||
@@ -16,9 +16,17 @@
|
||||
|
||||
import { Handler } from 'express';
|
||||
|
||||
/** @public */
|
||||
export interface HttpRouterServiceAuthPolicy {
|
||||
path: string;
|
||||
allow: 'unauthenticated' | 'user-cookie';
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export interface HttpRouterService {
|
||||
use(handler: Handler): void;
|
||||
|
||||
addAuthPolicy(policy: HttpRouterServiceAuthPolicy): void;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,10 @@ export type {
|
||||
export type { RootConfigService } from './RootConfigService';
|
||||
export type { DatabaseService } from './DatabaseService';
|
||||
export type { DiscoveryService } from './DiscoveryService';
|
||||
export type { HttpRouterService } from './HttpRouterService';
|
||||
export type {
|
||||
HttpRouterService,
|
||||
HttpRouterServiceAuthPolicy,
|
||||
} from './HttpRouterService';
|
||||
export type {
|
||||
HttpAuthService,
|
||||
BackstageCredentialTypes,
|
||||
|
||||
@@ -182,6 +182,7 @@ export namespace mockServices {
|
||||
export const factory = httpRouterServiceFactory;
|
||||
export const mock = simpleMock(coreServices.httpRouter, () => ({
|
||||
use: jest.fn(),
|
||||
addAuthPolicy: jest.fn(),
|
||||
}));
|
||||
}
|
||||
export namespace rootHttpRouter {
|
||||
|
||||
@@ -3258,6 +3258,7 @@ __metadata:
|
||||
minimist: ^1.2.5
|
||||
morgan: ^1.10.0
|
||||
node-forge: ^1.3.1
|
||||
path-to-regexp: ^6.2.1
|
||||
selfsigned: ^2.0.0
|
||||
stoppable: ^1.1.0
|
||||
supertest: ^6.1.3
|
||||
@@ -37508,10 +37509,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-to-regexp@npm:^6.2.0":
|
||||
version: 6.2.0
|
||||
resolution: "path-to-regexp@npm:6.2.0"
|
||||
checksum: a6aca74d2d6e2e7594d812f653cf85e9cb5054d3a8d80f099722a44ef6ad22639b02078e5ea83d11db16321c3e4359e3f1ab0274fa78dad0754a6e53f630b0fc
|
||||
"path-to-regexp@npm:^6.2.0, path-to-regexp@npm:^6.2.1":
|
||||
version: 6.2.1
|
||||
resolution: "path-to-regexp@npm:6.2.1"
|
||||
checksum: f0227af8284ea13300f4293ba111e3635142f976d4197f14d5ad1f124aebd9118783dd2e5f1fe16f7273743cc3dbeddfb7493f237bb27c10fdae07020cc9b698
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user