first minor cleanups

Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
Fredrik Adelöw
2021-12-22 16:56:29 +01:00
parent 1e932ee498
commit 59c5c70bf7
6 changed files with 45 additions and 36 deletions
+1 -1
View File
@@ -2,4 +2,4 @@
'@backstage/plugin-auth-backend': patch
---
Added Google Cloud Identity Aware Proxy as an identiy Provider - based on aws-elb
Added Google Cloud Identity-Aware Proxy as an identity provider.
+13 -10
View File
@@ -2,15 +2,15 @@
id: provider
title: Google Identity Aware Proxy Provider
sidebar_label: Google IAP
description:
Adding Google Identity Aware Proxy as an authentication provider in Backstage
# prettier-ignore
description: Adding Google Identity-Aware Proxy as an authentication provider in Backstage
---
# Using Google Identity Aware Proxy to authenticate requests
# Using Google Identity-Aware Proxy to authenticate requests
Backstage allows offloading the responsibility of authenticating users to an
Backstage allows offloading the responsibility of authenticating users to the
Google HTTPS Load Balancer & [IAP](https://cloud.google.com/iap), leveraging the
authentication support on IAP.
authentication support on the latter.
This tutorial shows how to use authentication on an ALB sitting in front of
Backstage.
@@ -24,10 +24,11 @@ configured to serve the frontend app from the backend.
### Frontend
The Backstage App needs a SignInPage when authentication is required. When using
IAP Proxy authentication Backstage will only be loaded once the user has
successfully authenticated; we won't need to display a SignIn page, however we
will need to create a dummy SignIn component that can refresh the token.
The Backstage App needs a `SignInPage` to be configured. When using IAP Proxy
authentication Backstage will only be loaded once the user has successfully
authenticated; we won't need to display a sign-in page as such, however we will
need to create a dummy `SignInPage` component that can decode and refresh the
token.
- edit `packages/app/src/App.tsx`
- import the following two additional definitions from `@backstage/core`:
@@ -52,6 +53,7 @@ const refreshToken = async ({ props, discoveryApiConfig, config }) => {
});
return;
}
try {
const request = await fetch(`${baseUrl}/gcp-iap/refresh`, {
headers: {
@@ -76,6 +78,7 @@ const refreshToken = async ({ props, discoveryApiConfig, config }) => {
});
}
};
const DummySignInComponent: any = (props: any) => {
try {
const config = useApi(configApiRef);
@@ -94,7 +97,7 @@ When using ALB auth it is not possible to leverage the built-in auth config
discovery mechanism implemented in the app created by default; bespoke logic
needs to be implemented.
- replace the content of `packages/backend/plugin/auth.ts` with the below
- Replace the content of `packages/backend/plugin/auth.ts` with the below
```ts
// imports are relative - as this was tested out in repo directly
+4
View File
@@ -45,6 +45,10 @@
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
"express-session": "^1.17.1",
<<<<<<< HEAD
=======
"fs-extra": "9.1.0",
>>>>>>> 4d5fd11228 (first minor cleanups)
"google-auth-library": "^7.2.0",
"helmet": "^4.0.0",
"jose": "^1.27.1",
@@ -13,5 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { createGcpIAPProvider } from './provider';
export type { GcpIAPProviderOptions } from './provider';
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { getVoidLogger } from '@backstage/backend-common';
import express from 'express';
import { GcpIAPProvider } from './provider';
import { AuthResponse } from '../types';
import { GcpIAPProvider } from './provider';
jest.mock('google-auth-library');
@@ -57,22 +57,22 @@ describe('GcpIAPProvider', () => {
getEntityByName: jest.fn(),
};
const mockRequest = ({
const mockRequest = {
header: jest.fn(() => {
return 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImZvbyIsImlzcyI6ImZvbyJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.T2BNS4G-6RoiFnXc8Q8TiwdWzTpNitY8jcsGM3N3-Yo';
}),
} as unknown) as express.Request;
const mockRequestWithoutJwt = ({
} as unknown as express.Request;
const mockRequestWithoutJwt = {
header: jest.fn(() => {
return undefined;
}),
} as unknown) as express.Request;
const mockResponse = ({
} as unknown as express.Request;
const mockResponse = {
end: jest.fn(),
header: () => jest.fn(),
json: jest.fn().mockReturnThis(),
status: jest.fn(),
} as unknown) as express.Response;
} as unknown as express.Response;
describe('should transform to type OAuthResponse', () => {
it('when JWT is valid and identity is resolved successfully', async () => {
@@ -14,19 +14,17 @@
* limitations under the License.
*/
import { CatalogApi } from '@backstage/catalog-client';
import express from 'express';
import { OAuth2Client } from 'google-auth-library';
import { Logger } from 'winston';
import {
AuthProviderRouteHandlers,
AuthProviderFactory,
AuthProviderFactoryOptions,
AuthProviderRouteHandlers,
ExperimentalIdentityResolver,
} from '../types';
import express from 'express';
import { Logger } from 'winston';
import { CatalogApi } from '@backstage/catalog-client';
import { OAuth2Client } from 'google-auth-library';
const IAP_JWT_HEADER = 'x-goog-iap-jwt-assertion';
export type GcpIAPProviderOptions = {
@@ -47,6 +45,7 @@ export class GcpIAPProvider implements AuthProviderRouteHandlers {
this.catalogClient = catalogClient;
this.options = options;
}
frameHandler(): Promise<void> {
return Promise.resolve(undefined);
}
@@ -102,7 +101,9 @@ export class GcpIAPProvider implements AuthProviderRouteHandlers {
}
}
export const createGcpIAPProvider = (_options?: GcpIAPProviderOptions) => {
export function createGcpIapProvider(
_options?: GcpIAPProviderOptions,
): AuthProviderFactory {
return ({
logger,
catalogApi,
@@ -111,13 +112,13 @@ export const createGcpIAPProvider = (_options?: GcpIAPProviderOptions) => {
}: AuthProviderFactoryOptions) => {
const audience = config.getString('audience');
if (identityResolver !== undefined) {
return new GcpIAPProvider(logger, catalogApi, {
audience,
identityResolutionCallback: identityResolver,
});
throw new Error(
'Identity resolver is required to use this authentication provider',
);
}
throw new Error(
'Identity resolver is required to use this authentication provider',
);
return new GcpIAPProvider(logger, catalogApi, {
audience,
identityResolutionCallback: identityResolver,
});
};
};
}