From 521728348d0939f4695d64f7793d409dd598e6ca Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 22 Sep 2020 14:56:52 +0200 Subject: [PATCH] backend: change the default backend plugin mount point to /api --- CHANGELOG.md | 4 +++ app-config.yaml | 4 +-- docs/auth/add-auth-provider.md | 7 ++--- .../software-templates/adding-templates.md | 4 +-- docs/features/techdocs/getting-started.md | 4 +-- docs/openapi/definitions/auth.yaml | 6 ++--- docs/tutorials/quickstart-app-auth.md | 2 +- packages/app/src/App.test.tsx | 2 +- packages/app/src/apis.ts | 12 --------- packages/backend/package.json | 1 + packages/backend/src/index.ts | 26 ++++++++++++------- packages/backend/src/plugins/auth.ts | 11 ++++---- .../templates/default-app/app-config.yaml.hbs | 4 +-- .../default-app/packages/app/src/App.test.tsx | 2 +- .../packages/backend/package.json.hbs | 1 + .../default-app/packages/backend/src/index.ts | 18 ++++++++----- packages/e2e-test/src/e2e-test.ts | 2 +- plugins/auth-backend/README.md | 6 ++--- .../auth-backend/scripts/start-saml-idp.sh | 2 +- plugins/auth-backend/src/service/router.ts | 4 ++- plugins/techdocs-backend/README.md | 4 +-- .../src/techdocs/stages/publish/local.ts | 2 +- 22 files changed, 68 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25360f3e1e..d360dd995d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ If you encounter issues while upgrading to a newer version, don't hesitate to re - Renamed `SessionStateApi` to `SessionApi` and `logout` to `signOut`. Custom implementations of the `SingInPage` app-component will need to rename their `logout` function. The different auth provider items for the `UserSettingsMenu` have been consolidated into a single `ProviderSettingsItem`, meaning you need to replace existing usages of `OAuthProviderSettings` and `OIDCProviderSettings`. [#2555](https://github.com/spotify/backstage/pull/2555). +### @backstage/auth-backend + +- The default mount path of backend plugins was changed to `/api/:pluginId`, and as part of that it was needed to enable configuration of the base path of the auth backend, so that it can construct redirect URLs correctly. The default base path is `/api/auth`, but you need to set this to `/auth` if you want to keep using the old path. Note that you will also need to reconfigure any allowed redirect URLs to include `/api` if you switch to the new recommended pattern. [#2562](https://github.com/spotify/backstage/pull/2562) + ## v0.1.1-alpha.22 ### @backstage/core diff --git a/app-config.yaml b/app-config.yaml index 60ecb813f7..fca0a39496 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -33,8 +33,8 @@ organization: name: Spotify techdocs: - storageUrl: http://localhost:7000/techdocs/static/docs - requestUrl: http://localhost:7000/techdocs/docs + storageUrl: http://localhost:7000/api/techdocs/static/docs + requestUrl: http://localhost:7000/api/techdocs/docs generators: techdocs: 'docker' diff --git a/docs/auth/add-auth-provider.md b/docs/auth/add-auth-provider.md index c5f7645a49..56586cbfc6 100644 --- a/docs/auth/add-auth-provider.md +++ b/docs/auth/add-auth-provider.md @@ -229,9 +229,10 @@ name. ### Test the new provider -You can `curl -i localhost:7000/auth/providerA/start` and which should provide a -`302` redirect with a `Location` header. Paste the url from that header into a -web browser and you should be able to trigger the authorization flow. +You can `curl -i localhost:7000/api/auth/providerA/start` and which should +provide a `302` redirect with a `Location` header. Paste the url from that +header into a web browser and you should be able to trigger the authorization +flow. --- diff --git a/docs/features/software-templates/adding-templates.md b/docs/features/software-templates/adding-templates.md index fad5c68e41..59019e754e 100644 --- a/docs/features/software-templates/adding-templates.md +++ b/docs/features/software-templates/adding-templates.md @@ -88,7 +88,7 @@ running: ```sh curl \ --location \ - --request POST 'localhost:7000/catalog/locations' \ + --request POST 'localhost:7000/api/catalog/locations' \ --header 'Content-Type: application/json' \ --data-raw "{\"type\": \"file\", \"target\": \"${YOUR PATH HERE}/template.yaml\"}" ``` @@ -98,7 +98,7 @@ If loading from a Git location, you can run the following ```sh curl \ --location \ - --request POST 'localhost:7000/catalog/locations' \ + --request POST 'localhost:7000/api/catalog/locations' \ --header 'Content-Type: application/json' \ --data-raw "{\"type\": \"github\", \"target\": \"https://${YOUR GITHUB REPO}blob/master/${PATH TO FOLDER}/template.yaml\"}" ``` diff --git a/docs/features/techdocs/getting-started.md b/docs/features/techdocs/getting-started.md index b9d215fd8a..03494564c3 100644 --- a/docs/features/techdocs/getting-started.md +++ b/docs/features/techdocs/getting-started.md @@ -57,8 +57,8 @@ The default storage and request URLs: ```yaml techdocs: - storageUrl: http://localhost:7000/techdocs/static/docs - requestUrl: http://localhost:7000/techdocs/docs + storageUrl: http://localhost:7000/api/techdocs/static/docs + requestUrl: http://localhost:7000/api/techdocs/docs ``` If you want `techdocs-backend` to manage building and publishing, you want diff --git a/docs/openapi/definitions/auth.yaml b/docs/openapi/definitions/auth.yaml index eb96d434c2..cb736fd2a9 100644 --- a/docs/openapi/definitions/auth.yaml +++ b/docs/openapi/definitions/auth.yaml @@ -6,10 +6,10 @@ info: **Provided by `@backstage/auth-backend`.** - The purpose of the Auth APIs in Backstage are to identify the user, and to provide a way for plugins + The purpose of the Auth APIs in Backstage are to identify the user, and to provide a way for plugins to request access to 3rd party services on behalf of that user. - The API is supplied with a list of providers - such as `Google` or `Github` - and will add the endpoints + The API is supplied with a list of providers - such as `Google` or `Github` - and will add the endpoints described below to each of those providers. Read more about [User Authentication and Authorization in Backstage](https://github.com/spotify/backstage/blob/master/docs/auth/overview.md). @@ -21,7 +21,7 @@ externalDocs: description: Backstage official documentation url: https://github.com/spotify/backstage/blob/master/docs/README.md servers: - - url: http://localhost:7000/auth/ + - url: http://localhost:7000/api/auth/ tags: - name: provider description: List of endpoints per provider diff --git a/docs/tutorials/quickstart-app-auth.md b/docs/tutorials/quickstart-app-auth.md index 2615e37633..ad2bf1af88 100644 --- a/docs/tutorials/quickstart-app-auth.md +++ b/docs/tutorials/quickstart-app-auth.md @@ -115,7 +115,7 @@ export AUTH_GITHUB_CLIENT_SECRET=xxx > Log into http://github.com > Navigate to (Settings > Developer Settings > OAuth Apps > New OAuth App)[https://github.com/settings/applications/new] > Set Homepage URL = http://localhost:3000 -> Set Callback URL = http://localhost:7000/auth/github +> Set Callback URL = http://localhost:7000/api/auth/github > Click [Register application] > On the next page, copy and paste your new Client ID and Client Secret to the environment variables above, `AUTH_GITHUB_CLIENT_ID` & `AUTH_GITHUB_CLIENT_SECRET` > Don't forget to `source` that profile file again if necessary. diff --git a/packages/app/src/App.test.tsx b/packages/app/src/App.test.tsx index cddd093855..40c49416bf 100644 --- a/packages/app/src/App.test.tsx +++ b/packages/app/src/App.test.tsx @@ -31,7 +31,7 @@ describe('App', () => { baseUrl: 'http://localhost:3003', }, techdocs: { - storageUrl: 'http://localhost:7000/techdocs/static/docs', + storageUrl: 'http://localhost:7000/api/techdocs/static/docs', }, }, context: 'test', diff --git a/packages/app/src/apis.ts b/packages/app/src/apis.ts index 7f57f6f970..581a591152 100644 --- a/packages/app/src/apis.ts +++ b/packages/app/src/apis.ts @@ -16,11 +16,8 @@ import { errorApiRef, - discoveryApiRef, - UrlPatternDiscovery, githubAuthApiRef, createApiFactory, - configApiRef, } from '@backstage/core'; import { @@ -38,15 +35,6 @@ import { } from '@roadiehq/backstage-plugin-github-pull-requests'; export const apis = [ - // TODO(Rugvip): migrate to use /api - createApiFactory({ - api: discoveryApiRef, - deps: { configApi: configApiRef }, - factory: ({ configApi }) => - UrlPatternDiscovery.compile( - `${configApi.getString('backend.baseUrl')}/{{ pluginId }}`, - ), - }), createApiFactory({ api: graphQlBrowseApiRef, deps: { errorApi: errorApiRef, githubAuthApi: githubAuthApiRef }, diff --git a/packages/backend/package.json b/packages/backend/package.json index 147ea630c2..9e14062992 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -37,6 +37,7 @@ "dockerode": "^3.2.0", "example-app": "^0.1.1-alpha.22", "express": "^4.17.1", + "express-promise-router": "^3.0.3", "knex": "^0.21.1", "pg": "^8.3.0", "pg-connection-string": "^2.3.0", diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 7c52175d76..9d4a738ecf 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -22,12 +22,14 @@ * Happy hacking! */ +import Router from 'express-promise-router'; import { createDatabaseClient, createServiceBuilder, loadBackendConfig, getRootLogger, useHotMemoize, + notFoundHandler, } from '@backstage/backend-common'; import { ConfigReader, AppConfig } from '@backstage/config'; import healthcheck from './plugins/healthcheck'; @@ -78,19 +80,23 @@ async function main() { const graphqlEnv = useHotMemoize(module, () => createEnv('graphql')); const appEnv = useHotMemoize(module, () => createEnv('app')); + const apiRouter = Router(); + apiRouter.use('/catalog', await catalog(catalogEnv)); + apiRouter.use('/rollbar', await rollbar(rollbarEnv)); + apiRouter.use('/scaffolder', await scaffolder(scaffolderEnv)); + apiRouter.use('/sentry', await sentry(sentryEnv)); + apiRouter.use('/auth', await auth(authEnv, '/api/auth')); + apiRouter.use('/identity', await identity(identityEnv)); + apiRouter.use('/techdocs', await techdocs(techdocsEnv)); + apiRouter.use('/kubernetes', await kubernetes(kubernetesEnv)); + apiRouter.use('/proxy', await proxy(proxyEnv, '/api/proxy')); + apiRouter.use('/graphql', await graphql(graphqlEnv)); + apiRouter.use(notFoundHandler()); + const service = createServiceBuilder(module) .loadConfig(configReader) .addRouter('', await healthcheck(healthcheckEnv)) - .addRouter('/catalog', await catalog(catalogEnv)) - .addRouter('/rollbar', await rollbar(rollbarEnv)) - .addRouter('/scaffolder', await scaffolder(scaffolderEnv)) - .addRouter('/sentry', await sentry(sentryEnv)) - .addRouter('/auth', await auth(authEnv)) - .addRouter('/identity', await identity(identityEnv)) - .addRouter('/techdocs', await techdocs(techdocsEnv)) - .addRouter('/kubernetes', await kubernetes(kubernetesEnv)) - .addRouter('/proxy', await proxy(proxyEnv, '/proxy')) - .addRouter('/graphql', await graphql(graphqlEnv)) + .addRouter('/api', apiRouter) .addRouter('', await app(appEnv)); await service.start().catch(err => { diff --git a/packages/backend/src/plugins/auth.ts b/packages/backend/src/plugins/auth.ts index b24dd6ca6b..60baaff6b7 100644 --- a/packages/backend/src/plugins/auth.ts +++ b/packages/backend/src/plugins/auth.ts @@ -17,10 +17,9 @@ import { createRouter } from '@backstage/plugin-auth-backend'; import { PluginEnvironment } from '../types'; -export default async function createPlugin({ - logger, - database, - config, -}: PluginEnvironment) { - return await createRouter({ logger, config, database }); +export default async function createPlugin( + { logger, database, config }: PluginEnvironment, + basePath: string, +) { + return await createRouter({ logger, config, database, basePath }); } diff --git a/packages/create-app/templates/default-app/app-config.yaml.hbs b/packages/create-app/templates/default-app/app-config.yaml.hbs index a7d7aa8010..92c517bf93 100644 --- a/packages/create-app/templates/default-app/app-config.yaml.hbs +++ b/packages/create-app/templates/default-app/app-config.yaml.hbs @@ -44,8 +44,8 @@ proxy: changeOrigin: true techdocs: - storageUrl: http://localhost:7000/techdocs/static/docs - requestUrl: http://localhost:7000/techdocs/docs + storageUrl: http://localhost:7000/api/techdocs/static/docs + requestUrl: http://localhost:7000/api/techdocs/docs generators: techdocs: 'docker' diff --git a/packages/create-app/templates/default-app/packages/app/src/App.test.tsx b/packages/create-app/templates/default-app/packages/app/src/App.test.tsx index e88c3b47dd..21a2eaa703 100644 --- a/packages/create-app/templates/default-app/packages/app/src/App.test.tsx +++ b/packages/create-app/templates/default-app/packages/app/src/App.test.tsx @@ -12,7 +12,7 @@ describe('App', () => { app: { title: 'Test' }, backend: { baseUrl: 'http://localhost:7000' }, techdocs: { - storageUrl: 'http://localhost:7000/techdocs/static/docs', + storageUrl: 'http://localhost:7000/api/techdocs/static/docs', }, }, context: 'test', diff --git a/packages/create-app/templates/default-app/packages/backend/package.json.hbs b/packages/create-app/templates/default-app/packages/backend/package.json.hbs index adde81e830..b70f36650e 100644 --- a/packages/create-app/templates/default-app/packages/backend/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/backend/package.json.hbs @@ -31,6 +31,7 @@ "@gitbeaker/node": "^23.5.0", "dockerode": "^3.2.0", "express": "^4.17.1", + "express-promise-router": "^3.0.3", "knex": "^0.21.1", {{#if dbTypePG}} "pg": "^8.3.0", diff --git a/packages/create-app/templates/default-app/packages/backend/src/index.ts b/packages/create-app/templates/default-app/packages/backend/src/index.ts index 6a014727e9..457b95a7a9 100644 --- a/packages/create-app/templates/default-app/packages/backend/src/index.ts +++ b/packages/create-app/templates/default-app/packages/backend/src/index.ts @@ -6,12 +6,14 @@ * Happy hacking! */ +import Router from 'express-promise-router'; import { createDatabaseClient, createServiceBuilder, loadBackendConfig, getRootLogger, useHotMemoize, + notFoundHandler, } from '@backstage/backend-common'; import { ConfigReader, AppConfig } from '@backstage/config'; import auth from './plugins/auth'; @@ -51,14 +53,18 @@ async function main() { const proxyEnv = useHotMemoize(module, () => createEnv('proxy')); const techdocsEnv = useHotMemoize(module, () => createEnv('techdocs')); + const apiRouter = Router(); + apiRouter.use('/catalog', await catalog(catalogEnv)) + apiRouter.use('/scaffolder', await scaffolder(scaffolderEnv)) + apiRouter.use('/auth', await auth(authEnv)) + apiRouter.use('/identity', await identity(identityEnv)) + apiRouter.use('/techdocs', await techdocs(techdocsEnv)) + apiRouter.use('/proxy', await proxy(proxyEnv, '/api/proxy')) + apiRouter.use(notFoundHandler()); + const service = createServiceBuilder(module) .loadConfig(configReader) - .addRouter('/catalog', await catalog(catalogEnv)) - .addRouter('/scaffolder', await scaffolder(scaffolderEnv)) - .addRouter('/auth', await auth(authEnv)) - .addRouter('/identity', await identity(identityEnv)) - .addRouter('/techdocs', await techdocs(techdocsEnv)) - .addRouter('/proxy', await proxy(proxyEnv, '/proxy')); + .addRouter('/api', apiRouter) await service.start().catch(err => { console.log(err); diff --git a/packages/e2e-test/src/e2e-test.ts b/packages/e2e-test/src/e2e-test.ts index 969a77cb2a..ec34f48959 100644 --- a/packages/e2e-test/src/e2e-test.ts +++ b/packages/e2e-test/src/e2e-test.ts @@ -384,7 +384,7 @@ async function testBackendStart(appDir: string, isPostgres: boolean) { print('Try to fetch entities from the backend'); // Try fetch entities, should be ok - await fetch('http://localhost:7000/catalog/entities').then(res => + await fetch('http://localhost:7000/api/catalog/entities').then(res => res.json(), ); print('Entities fetched successfully'); diff --git a/plugins/auth-backend/README.md b/plugins/auth-backend/README.md index 9af90df3f2..868d88b3d0 100644 --- a/plugins/auth-backend/README.md +++ b/plugins/auth-backend/README.md @@ -34,7 +34,7 @@ Follow this link, [Create new OAuth App](https://github.com/settings/application 1. Set Application Name to `backstage-dev` or something along those lines. 1. You can set the Homepage URL to whatever you want to. 1. The Authorization Callback URL should match the redirect URI set in Backstage. - 1. Set this to `http://localhost:7000/auth/github` for local development. + 1. Set this to `http://localhost:7000/api/auth/github` for local development. 1. Set this to `http://{APP_FQDN}:{APP_BACKEND_PORT}/auth/github` for non-local deployments. ```bash @@ -78,14 +78,14 @@ export AUTH_AUTH0_CLIENT_SECRET=x #### Creating an Azure AD App Registration -An Azure AD App Registration is required to be able to sign in using Azure AD and the Microsoft Graph API. +An Azure AD App Registration is required to be able to sign in using Azure AD and the Microsoft Graph API. Click [here](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps) to create a new one. - Click on the `New Registration` button. - Give the app a name. e.g. `backstage-dev` - Select `Accounts in this organizational directory only` under supported account types. - Enter the callback URL for your backstage backend instance: - - For local development, this is likely `http://localhost:7000/auth/microsoft/handler/frame` + - For local development, this is likely `http://localhost:7000/api/auth/microsoft/handler/frame` - For non-local deployments, this will be `https://{APP_FQDN}:{APP_BACKEND_PORT}/auth/microsoft/handler/frame` - Click `Register`. diff --git a/plugins/auth-backend/scripts/start-saml-idp.sh b/plugins/auth-backend/scripts/start-saml-idp.sh index 33217f7978..b312a4b85e 100755 --- a/plugins/auth-backend/scripts/start-saml-idp.sh +++ b/plugins/auth-backend/scripts/start-saml-idp.sh @@ -18,4 +18,4 @@ fi echo "Downloading and starting SAML-IdP" export NPM_CONFIG_REGISTRY=https://registry.npmjs.org -exec npx saml-idp --acsUrl "http://localhost:7000/auth/saml/handler/frame" --audience "http://localhost:7000" --port 7001 +exec npx saml-idp --acsUrl "http://localhost:7000/api/auth/saml/handler/frame" --audience "http://localhost:7000" --port 7001 diff --git a/plugins/auth-backend/src/service/router.ts b/plugins/auth-backend/src/service/router.ts index 19a74d47c5..e70e687879 100644 --- a/plugins/auth-backend/src/service/router.ts +++ b/plugins/auth-backend/src/service/router.ts @@ -28,6 +28,7 @@ export interface RouterOptions { logger: Logger; database: Knex; config: Config; + basePath?: string; } export async function createRouter( @@ -38,7 +39,8 @@ export async function createRouter( const appUrl = options.config.getString('app.baseUrl'); const backendUrl = options.config.getString('backend.baseUrl'); - const authUrl = `${backendUrl}/auth`; + // TODO(Rugvip): Replace with service discovery of external URL + const authUrl = backendUrl + (options.basePath ?? '/api/auth'); const keyDurationSeconds = 3600; diff --git a/plugins/techdocs-backend/README.md b/plugins/techdocs-backend/README.md index 2185c3b3e4..b7eca2c5cb 100644 --- a/plugins/techdocs-backend/README.md +++ b/plugins/techdocs-backend/README.md @@ -18,11 +18,11 @@ yarn start ## What techdocs-backend does -This plugin is the backend part of the techdocs plugin. It provides building and serving of your docs without having to use another service and hosting provider. To use it set your techdocs storageUrl in your `app-config.yml` to `http://localhost:7000/techdocs/static/docs`. +This plugin is the backend part of the techdocs plugin. It provides building and serving of your docs without having to use another service and hosting provider. To use it set your techdocs storageUrl in your `app-config.yml` to `http://localhost:7000/api/techdocs/static/docs`. ```yaml techdocs: - storageUrl: http://localhost:7000/techdocs/static/docs + storageUrl: http://localhost:7000/api/techdocs/static/docs ``` ## Extending techdocs-backend diff --git a/plugins/techdocs-backend/src/techdocs/stages/publish/local.ts b/plugins/techdocs-backend/src/techdocs/stages/publish/local.ts index e33c6fa17d..f328443965 100644 --- a/plugins/techdocs-backend/src/techdocs/stages/publish/local.ts +++ b/plugins/techdocs-backend/src/techdocs/stages/publish/local.ts @@ -64,7 +64,7 @@ export class LocalPublish implements PublisherBase { } resolve({ - remoteUrl: `http://localhost:7000/techdocs/static/docs/${entity.metadata.name}`, + remoteUrl: `http://localhost:7000/api/techdocs/static/docs/${entity.metadata.name}`, }); }); });