From 88aad0803df2f95cbb2b09efbfbbd97f05ad65c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 30 Dec 2021 11:39:23 +0100 Subject: [PATCH] remove frontend parts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- docs/auth/google/gcp-iap-auth.md | 137 ------------------ packages/core-app-api/api-report.md | 37 ----- .../auth/gcp-iap/GcpIapIdentity.ts | 74 ---------- .../implementations/auth/gcp-iap/index.ts | 18 --- .../auth/gcp-iap/types.test.ts | 50 ------- .../implementations/auth/gcp-iap/types.ts | 63 -------- .../src/apis/implementations/auth/index.ts | 1 - 7 files changed, 380 deletions(-) delete mode 100644 docs/auth/google/gcp-iap-auth.md delete mode 100644 packages/core-app-api/src/apis/implementations/auth/gcp-iap/GcpIapIdentity.ts delete mode 100644 packages/core-app-api/src/apis/implementations/auth/gcp-iap/index.ts delete mode 100644 packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.test.ts delete mode 100644 packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.ts diff --git a/docs/auth/google/gcp-iap-auth.md b/docs/auth/google/gcp-iap-auth.md deleted file mode 100644 index 3c2cf68872..0000000000 --- a/docs/auth/google/gcp-iap-auth.md +++ /dev/null @@ -1,137 +0,0 @@ ---- -id: provider -title: Google Identity-Aware Proxy Provider -sidebar_label: Google IAP -# prettier-ignore -description: Adding Google Identity-Aware Proxy as an authentication provider in Backstage ---- - -# Using Google Identity-Aware Proxy to authenticate requests - -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 the latter. - -This tutorial shows how to use authentication on an IAP sitting in front of -Backstage. - -It is assumed an IAP is already serving traffic in front of a Backstage instance -configured to serve the frontend app from the backend. - -## Frontend Changes - -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 fetch the token and other -information from the backend. - -Create a sign-in page component in your app, for example in -`packages/app/src/components/SignInPage.tsx`. - -```tsx -import { GcpIapIdentity } from '@backstage/core-app-api'; -import { ErrorPanel, Progress } from '@backstage/core-components'; -import { - discoveryApiRef, - fetchApiRef, - SignInPageProps, - useApi, -} from '@backstage/core-plugin-api'; -import { ResponseError } from '@backstage/errors'; -import React from 'react'; -import { useAsync } from 'react-use'; - -export const GcpIapSignInPage = (props: SignInPageProps) => { - const discovery = useApi(discoveryApiRef); - const { fetch } = useApi(fetchApiRef); - - const { loading, error } = useAsync(async () => { - const base = await discovery.getBaseUrl('auth'); - const response = await fetch(`${base}/gcp-iap/refresh`, { - headers: { 'x-requested-with': 'XMLHttpRequest' }, - credentials: 'include', - }); - if (!response.ok) { - throw await ResponseError.fromResponse(response); - } - props.onSignInSuccess(GcpIapIdentity.fromResponse(await response.json())); - }, []); - - if (loading) return ; - if (error) return ; - return null; -}; -``` - -Pass this sign in page to your `createApp` function, in -`packages/app/src/App.tsx`. - -```diff -+import { GcpIapSignInPage } from './components/SignInPage'; - - const app = createApp({ - components: { -+ SignInPage: GcpIapSignInPage -``` - -## Backend Changes - -- Add a `providerFactories` entry to the router in - `packages/backend/plugin/auth.ts`. - -```ts -import { createGcpIapProvider } from '@backstage/plugin-auth-backend'; - -export default async function createPlugin({ - logger, - database, - config, - discovery, -}: PluginEnvironment): Promise { - return await createRouter({ - logger, - config, - database, - discovery, - providerFactories: { - 'gcp-iap': createGcpIapProvider({ - // Replace the auth handler if you want to customize the returned user - // profile info (can be left out; default implementation shown below - // which only returns the email. - async authHandler({ iapToken }) { - return { profile: { email: iapToken.email } }; - }, - signIn: { - // You need to supply an identity resolver, that takes the profile - // and the IAP token and produces the Backstage token with the - // relevant user info. - async resolver({ profile, result: { iapToken } }, ctx) { - // Somehow compute the Backstage token claims, just some dummy code - // shown here, but you may want to query your LDAP server, or - // GSuite or similar, based on the IAP token sub/email claims - const id = `user:default/${iapToken.email.split('@')[0]}`; - const fullEnt = ['group:default/team-name']; - const token = await ctx.tokenIssuer.issueToken({ - claims: { sub: id, ent: fullEnt }, - }); - return { id, token }; - }, - }, - }), - }, - }); -} -``` - -## Configuration - -Use the following `auth` configuration: - -```yaml -auth: - providers: - gcp-iap: - audience: - '/projects//global/backendServices/' -``` diff --git a/packages/core-app-api/api-report.md b/packages/core-app-api/api-report.md index ece34959de..f94979f975 100644 --- a/packages/core-app-api/api-report.md +++ b/packages/core-app-api/api-report.md @@ -21,9 +21,7 @@ import { AuthProviderInfo } from '@backstage/core-plugin-api'; import { AuthRequestOptions } from '@backstage/core-plugin-api'; import { BackstageIdentity } from '@backstage/core-plugin-api'; import { BackstageIdentityApi } from '@backstage/core-plugin-api'; -import { BackstageIdentityResponse } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; -import { BackstageUserIdentity } from '@backstage/core-plugin-api'; import { bitbucketAuthApiRef } from '@backstage/core-plugin-api'; import { ComponentType } from 'react'; import { Config } from '@backstage/config'; @@ -390,41 +388,6 @@ export type FlatRoutesProps = { children: ReactNode; }; -// @public -export class GcpIapIdentity implements IdentityApi { - constructor(session: GcpIapSession); - static fromResponse(data: unknown): GcpIapIdentity; - // (undocumented) - getBackstageIdentity(): Promise; - // (undocumented) - getCredentials(): Promise<{ - token?: string | undefined; - }>; - // (undocumented) - getIdToken(): Promise; - // (undocumented) - getProfile(): ProfileInfo; - // (undocumented) - getProfileInfo(): Promise; - // (undocumented) - getUserId(): string; - // (undocumented) - signOut(): Promise; -} - -// @public -export type GcpIapSession = { - providerInfo: { - iapToken: { - sub: string; - email: string; - [key: string]: unknown; - }; - }; - profile: ProfileInfo; - backstageIdentity: BackstageIdentityResponse; -}; - // @public export class GithubAuth implements OAuthApi, SessionApi { // (undocumented) diff --git a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/GcpIapIdentity.ts b/packages/core-app-api/src/apis/implementations/auth/gcp-iap/GcpIapIdentity.ts deleted file mode 100644 index 0df14e1d99..0000000000 --- a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/GcpIapIdentity.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2021 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 { - BackstageUserIdentity, - IdentityApi, - ProfileInfo, -} from '@backstage/core-plugin-api'; -import { GcpIapSession, gcpIapSessionSchema } from './types'; - -/** - * An identity API based on a Google Identity-Aware Proxy auth response. - * - * @public - */ -export class GcpIapIdentity implements IdentityApi { - /** - * Creates an identity instance based on the auth-backend API response. - * - * @param data - The raw JSON response from the auth-backend. - */ - static fromResponse(data: unknown): GcpIapIdentity { - const parsed = gcpIapSessionSchema.parse(data); - return new GcpIapIdentity(parsed); - } - - constructor(private readonly session: GcpIapSession) {} - - /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getUserId} */ - getUserId(): string { - return this.session.backstageIdentity.id; - } - - /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getIdToken} */ - async getIdToken(): Promise { - return this.session.backstageIdentity.token; - } - - /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getProfile} */ - getProfile(): ProfileInfo { - return this.session.profile; - } - - /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getProfileInfo} */ - async getProfileInfo(): Promise { - return this.session.profile; - } - - /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getBackstageIdentity} */ - async getBackstageIdentity(): Promise { - return this.session.backstageIdentity.identity; - } - - /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.getCredentials} */ - async getCredentials(): Promise<{ token?: string | undefined }> { - return { token: this.session.backstageIdentity.token }; - } - - /** {@inheritdoc @backstage/core-plugin-api#IdentityApi.signOut} */ - async signOut(): Promise {} -} diff --git a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/index.ts b/packages/core-app-api/src/apis/implementations/auth/gcp-iap/index.ts deleted file mode 100644 index 8133061f20..0000000000 --- a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2021 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. - */ - -export { GcpIapIdentity } from './GcpIapIdentity'; -export type { GcpIapSession } from './types'; diff --git a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.test.ts b/packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.test.ts deleted file mode 100644 index cb185103e2..0000000000 --- a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2021 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 { TypeOf } from 'zod'; -import { GcpIapSession, gcpIapSessionSchema } from './types'; - -describe('types', () => { - const responseData: GcpIapSession = { - providerInfo: { - iapToken: { - sub: 's', - email: 'e', - other: 7, - }, - }, - profile: { - email: 'e', - displayName: 'd', - picture: 'p', - }, - backstageIdentity: { - id: 'i', - token: 't', - identity: { - type: 'user', - userEntityRef: 'ue', - ownershipEntityRefs: ['oe'], - }, - }, - }; - - it('has a compatible schema type', () => { - function f(_b: TypeOf) {} - f(responseData); // no tsc errors - expect(gcpIapSessionSchema.parse(responseData)).toEqual(responseData); - }); -}); diff --git a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.ts b/packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.ts deleted file mode 100644 index 98c728785d..0000000000 --- a/packages/core-app-api/src/apis/implementations/auth/gcp-iap/types.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2021 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 { - BackstageIdentityResponse, - ProfileInfo, -} from '@backstage/core-plugin-api'; -import { z } from 'zod'; - -export const gcpIapSessionSchema = z.object({ - providerInfo: z.object({ - iapToken: z - .object({ - sub: z.string(), - email: z.string(), - }) - .catchall(z.unknown()), - }), - profile: z.object({ - email: z.string().optional(), - displayName: z.string().optional(), - picture: z.string().optional(), - }), - backstageIdentity: z.object({ - id: z.string(), - token: z.string(), - identity: z.object({ - type: z.literal('user'), - userEntityRef: z.string(), - ownershipEntityRefs: z.array(z.string()), - }), - }), -}); - -/** - * Session information for Google Identity-Aware Proxy auth. - * - * @public - */ -export type GcpIapSession = { - providerInfo: { - iapToken: { - sub: string; - email: string; - [key: string]: unknown; - }; - }; - profile: ProfileInfo; - backstageIdentity: BackstageIdentityResponse; -}; diff --git a/packages/core-app-api/src/apis/implementations/auth/index.ts b/packages/core-app-api/src/apis/implementations/auth/index.ts index c53c9b7c76..50333f07a0 100644 --- a/packages/core-app-api/src/apis/implementations/auth/index.ts +++ b/packages/core-app-api/src/apis/implementations/auth/index.ts @@ -25,5 +25,4 @@ export * from './microsoft'; export * from './onelogin'; export * from './bitbucket'; export * from './atlassian'; -export * from './gcp-iap'; export type { OAuthApiCreateOptions, AuthApiCreateOptions } from './types';