move IdentityClient.getBearerToken
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
@@ -2,4 +2,10 @@
|
||||
'@backstage/plugin-auth-backend': minor
|
||||
---
|
||||
|
||||
Made `IdentityClient.listPublicKeys` private. It was only used in tests, and should not be part of the API surface of that class. The interface is marked as experimental, and therefore this is a breaking change without a deprecation period.
|
||||
- Made `IdentityClient.listPublicKeys` private. It was only used in tests, and
|
||||
should not be part of the API surface of that class.
|
||||
- Removed the static `IdentityClient.getBearerToken`. It is now replaced by
|
||||
`getBearerTokenFromAuthorizationHeader` from `@backstage/plugin-auth-node`.
|
||||
|
||||
Since the `IdentityClient` interface is marked as experimental, this is a
|
||||
breaking change without a deprecation period.
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-permission-backend': patch
|
||||
'@backstage/plugin-search-backend': patch
|
||||
---
|
||||
|
||||
Use `getBearerTokenFromAuthorizationHeader` from `@backstage/plugin-auth-node` instead of the deprecated `IdentityClient` method.
|
||||
@@ -428,9 +428,6 @@ export type GoogleProviderOptions = {
|
||||
export class IdentityClient {
|
||||
constructor(options: { discovery: PluginEndpointDiscovery; issuer: string });
|
||||
authenticate(token: string | undefined): Promise<BackstageIdentityResponse>;
|
||||
static getBearerToken(
|
||||
authorizationHeader: string | undefined,
|
||||
): string | undefined;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "microsoftEmailSignInResolver" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/plugin-auth-node": "^0.0.0",
|
||||
"@backstage/backend-common": "^0.10.7-next.0",
|
||||
"@backstage/catalog-client": "^0.5.5",
|
||||
"@backstage/catalog-model": "^0.9.10",
|
||||
|
||||
@@ -199,38 +199,6 @@ describe('IdentityClient', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getBearerToken', () => {
|
||||
it('should return undefined on undefined input', async () => {
|
||||
const token = IdentityClient.getBearerToken(undefined);
|
||||
expect(token).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return undefined on malformed input', async () => {
|
||||
const token = IdentityClient.getBearerToken('malformed');
|
||||
expect(token).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return undefined on unexpected scheme', async () => {
|
||||
const token = IdentityClient.getBearerToken('Basic token');
|
||||
expect(token).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return Bearer token', async () => {
|
||||
const token = IdentityClient.getBearerToken('Bearer token');
|
||||
expect(token).toEqual('token');
|
||||
});
|
||||
|
||||
it('should return Bearer token despite extra space', async () => {
|
||||
const token = IdentityClient.getBearerToken('Bearer \n token ');
|
||||
expect(token).toEqual('token');
|
||||
});
|
||||
|
||||
it('should return Bearer token despite unconventionial case', async () => {
|
||||
const token = IdentityClient.getBearerToken('bEARER token');
|
||||
expect(token).toEqual('token');
|
||||
});
|
||||
});
|
||||
|
||||
describe('listPublicKeys', () => {
|
||||
const defaultServiceResponse: {
|
||||
keys: JSONWebKey[];
|
||||
|
||||
@@ -84,20 +84,6 @@ export class IdentityClient {
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given authorization header and returns
|
||||
* the bearer token, or null if no bearer token is given
|
||||
*/
|
||||
static getBearerToken(
|
||||
authorizationHeader: string | undefined,
|
||||
): string | undefined {
|
||||
if (typeof authorizationHeader !== 'string') {
|
||||
return undefined;
|
||||
}
|
||||
const matches = authorizationHeader.match(/Bearer\s+(\S+)/i);
|
||||
return matches?.[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public signing key matching the given jwt token,
|
||||
* or null if no matching key was found
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
import express from 'express';
|
||||
import { Logger } from 'winston';
|
||||
import { AuthenticationError } from '@backstage/errors';
|
||||
import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node';
|
||||
import {
|
||||
AuthHandler,
|
||||
SignInResolver,
|
||||
@@ -26,7 +27,6 @@ import {
|
||||
} from '../types';
|
||||
import { CatalogIdentityClient } from '../../lib/catalog';
|
||||
import { JWT } from 'jose';
|
||||
import { IdentityClient } from '../../identity';
|
||||
import { TokenIssuer } from '../../identity/types';
|
||||
import { prepareBackstageIdentityResponse } from '../prepareBackstageIdentityResponse';
|
||||
|
||||
@@ -156,7 +156,7 @@ export class Oauth2ProxyAuthProvider<JWTPayload>
|
||||
|
||||
private getResult(req: express.Request): OAuth2ProxyResult<JWTPayload> {
|
||||
const authHeader = req.header(OAUTH2_PROXY_JWT_HEADER);
|
||||
const jwt = IdentityClient.getBearerToken(authHeader);
|
||||
const jwt = getBearerTokenFromAuthorizationHeader(authHeader);
|
||||
|
||||
if (!jwt) {
|
||||
throw new AuthenticationError(
|
||||
|
||||
@@ -4,5 +4,7 @@
|
||||
|
||||
```ts
|
||||
// @public
|
||||
export const COMMON_CONSTANT = 1;
|
||||
export function getBearerTokenFromAuthorizationHeader(
|
||||
authorizationHeader: unknown,
|
||||
): string | undefined;
|
||||
```
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
"clean": "backstage-cli clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-common": "^0.10.6",
|
||||
"@backstage/backend-common": "^0.10.7-next.0",
|
||||
"@backstage/config": "^0.1.13",
|
||||
"winston": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.13.1"
|
||||
"@backstage/cli": "^0.13.2-next.0"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2022 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 { getBearerTokenFromAuthorizationHeader } from './getBearerTokenFromAuthorizationHeader';
|
||||
|
||||
describe('getBearerToken', () => {
|
||||
it('should return undefined on bad input', async () => {
|
||||
expect(getBearerTokenFromAuthorizationHeader(undefined)).toBeUndefined();
|
||||
expect(getBearerTokenFromAuthorizationHeader(7)).toBeUndefined();
|
||||
expect(
|
||||
getBearerTokenFromAuthorizationHeader('Bearer \n token'),
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
getBearerTokenFromAuthorizationHeader('Bearer token '),
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return undefined on malformed input', async () => {
|
||||
const token = getBearerTokenFromAuthorizationHeader('malformed');
|
||||
expect(token).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return undefined on unexpected scheme', async () => {
|
||||
const token = getBearerTokenFromAuthorizationHeader('Basic token');
|
||||
expect(token).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return Bearer token', async () => {
|
||||
const token = getBearerTokenFromAuthorizationHeader('Bearer token');
|
||||
expect(token).toEqual('token');
|
||||
});
|
||||
|
||||
it('should return Bearer token despite unconventional case', async () => {
|
||||
const token = getBearerTokenFromAuthorizationHeader('bEARER token');
|
||||
expect(token).toEqual('token');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Parses the given authorization header and returns the bearer token, or
|
||||
* undefined if no bearer token is given.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* This function is explicitly built to tolerate bad inputs safely, so you may
|
||||
* call it directly with e.g. the output of `req.header('authorization')`
|
||||
* without first checking that it exists.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function getBearerTokenFromAuthorizationHeader(
|
||||
authorizationHeader: unknown,
|
||||
): string | undefined {
|
||||
if (typeof authorizationHeader !== 'string') {
|
||||
return undefined;
|
||||
}
|
||||
const matches = authorizationHeader.match(/^Bearer[ ]+(\S+)$/i);
|
||||
return matches?.[1];
|
||||
}
|
||||
@@ -20,9 +20,4 @@
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
/**
|
||||
* Dummy.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const COMMON_CONSTANT = 1;
|
||||
export { getBearerTokenFromAuthorizationHeader } from './getBearerTokenFromAuthorizationHeader';
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"@backstage/config": "^0.1.13",
|
||||
"@backstage/errors": "^0.2.0",
|
||||
"@backstage/plugin-auth-backend": "^0.10.0-next.0",
|
||||
"@backstage/plugin-auth-node": "^0.0.0",
|
||||
"@backstage/plugin-permission-common": "^0.4.0",
|
||||
"@backstage/plugin-permission-node": "^0.4.3-next.0",
|
||||
"@types/express": "*",
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
BackstageIdentityResponse,
|
||||
IdentityClient,
|
||||
} from '@backstage/plugin-auth-backend';
|
||||
import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node';
|
||||
import {
|
||||
AuthorizeResult,
|
||||
AuthorizeDecision,
|
||||
@@ -157,7 +158,9 @@ export async function createRouter(
|
||||
req: Request<AuthorizeRequest>,
|
||||
res: Response<AuthorizeResponse>,
|
||||
) => {
|
||||
const token = IdentityClient.getBearerToken(req.header('authorization'));
|
||||
const token = getBearerTokenFromAuthorizationHeader(
|
||||
req.header('authorization'),
|
||||
);
|
||||
const user = token ? await identity.authenticate(token) : undefined;
|
||||
|
||||
const parseResult = requestSchema.safeParse(req.body);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"@backstage/config": "^0.1.13",
|
||||
"@backstage/errors": "^0.2.0",
|
||||
"@backstage/search-common": "^0.2.2",
|
||||
"@backstage/plugin-auth-backend": "^0.10.0-next.0",
|
||||
"@backstage/plugin-auth-node": "^0.0.0",
|
||||
"@backstage/plugin-permission-common": "^0.4.0-next.0",
|
||||
"@backstage/plugin-permission-node": "^0.4.3-next.0",
|
||||
"@backstage/plugin-search-backend-node": "^0.4.5",
|
||||
|
||||
@@ -22,7 +22,7 @@ import { errorHandler } from '@backstage/backend-common';
|
||||
import { InputError } from '@backstage/errors';
|
||||
import { Config } from '@backstage/config';
|
||||
import { JsonObject, JsonValue } from '@backstage/types';
|
||||
import { IdentityClient } from '@backstage/plugin-auth-backend';
|
||||
import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node';
|
||||
import { PermissionAuthorizer } from '@backstage/plugin-permission-common';
|
||||
import { DocumentTypeInfo, SearchResultSet } from '@backstage/search-common';
|
||||
import { SearchEngine } from '@backstage/plugin-search-backend-node';
|
||||
@@ -106,7 +106,9 @@ export async function createRouter(
|
||||
}, pageCursor=${query.pageCursor ?? ''}`,
|
||||
);
|
||||
|
||||
const token = IdentityClient.getBearerToken(req.header('authorization'));
|
||||
const token = getBearerTokenFromAuthorizationHeader(
|
||||
req.header('authorization'),
|
||||
);
|
||||
|
||||
try {
|
||||
const resultSet = await engine?.query(query, { token });
|
||||
|
||||
Reference in New Issue
Block a user