core-app-api: make fetch auth middleware of discovery config

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2025-03-11 14:11:03 +01:00
parent ae33d1635a
commit 9262001323
3 changed files with 75 additions and 1 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-app-api': minor
---
The default auth injection middleware for the `FetchApi` will now also take configuration under `discovery.endpoints` into consideration when deciding whether to include credentials or not.
@@ -115,4 +115,49 @@ describe('IdentityAuthInjectorFetchMiddleware', () => {
['authorization', 'do-not-clobber'],
]);
});
describe('.getDiscoveryUrlPrefixes', () => {
it('works with no endpoints', () => {
const config = new ConfigReader({
backend: { baseUrl: 'https://a.com' },
});
expect(
IdentityAuthInjectorFetchMiddleware.getDiscoveryUrlPrefixes(config),
).toEqual([]);
});
it('works with endpoints', () => {
const config = new ConfigReader({
backend: { baseUrl: 'https://a.com' },
discovery: {
endpoints: [
{ target: 'https://b.com', plugins: ['p1'] },
{ target: 'https://c.com/{{pluginId}}', plugins: ['p2', 'p3'] },
{ target: { external: 'https://d.com' }, plugins: ['q1'] },
{
target: { external: 'https://e.com/{{pluginId}}' },
plugins: ['q2', 'q3'],
},
{
target: {
external: 'https://{{ pluginId }}.e.com/{{pluginId}}',
},
plugins: ['q4'],
},
],
},
});
expect(
IdentityAuthInjectorFetchMiddleware.getDiscoveryUrlPrefixes(config),
).toEqual([
'https://b.com',
'https://c.com/p2',
'https://c.com/p3',
'https://d.com',
'https://e.com/q2',
'https://e.com/q3',
'https://q4.e.com/q4',
]);
});
});
});
@@ -45,6 +45,25 @@ export class IdentityAuthInjectorFetchMiddleware implements FetchMiddleware {
);
}
/**
* Returns an array of plugin URL prefixes derived from the static `discovery`
* configuration, to be used as `urlPrefixAllowlist` option of {@link create}.
*/
static getDiscoveryUrlPrefixes(config: Config): string[] {
const endpointConfigs =
config.getOptionalConfigArray('discovery.endpoints') || [];
return endpointConfigs.flatMap(c => {
const target =
typeof c.get('target') === 'object'
? c.getString('target.external')
: c.getString('target');
const plugins = c.getStringArray('plugins');
return plugins.map(pluginId =>
target.replace(/\{\{\s*pluginId\s*\}\}/g, pluginId),
);
});
}
constructor(
public readonly identityApi: IdentityApi,
public readonly allowUrl: (url: string) => boolean,
@@ -87,7 +106,12 @@ function buildMatcher(options: {
} else if (options.urlPrefixAllowlist) {
return buildPrefixMatcher(options.urlPrefixAllowlist);
} else if (options.config) {
return buildPrefixMatcher([options.config.getString('backend.baseUrl')]);
return buildPrefixMatcher([
options.config.getString('backend.baseUrl'),
...IdentityAuthInjectorFetchMiddleware.getDiscoveryUrlPrefixes(
options.config,
),
]);
}
return () => false;
}