From 456eaa8cf8378a7fad044abc20baa970aae0cd13 Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Mon, 27 Feb 2023 21:16:02 -0500 Subject: [PATCH 1/3] request `openid` scope for ID tokens The changeset justifies this choice Signed-off-by: Jamie Klassen --- .changeset/rotten-cats-matter.md | 19 +++++++++++++++ .../auth/oauth2/OAuth2.test.ts | 24 ++++++++++++------- .../implementations/auth/oauth2/OAuth2.ts | 5 +++- 3 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 .changeset/rotten-cats-matter.md diff --git a/.changeset/rotten-cats-matter.md b/.changeset/rotten-cats-matter.md new file mode 100644 index 0000000000..2515db9991 --- /dev/null +++ b/.changeset/rotten-cats-matter.md @@ -0,0 +1,19 @@ +--- +'@backstage/core-app-api': minor +--- + +`OAuth2` now gets ID tokens from a session with the `openid` scope explicitly +requested. + +This should not be considered a breaking change, because spec-compliant OIDC +providers will already be returning ID tokens if and only if the `openid` scope +is granted. + +This change makes the dependence explicit, and removes the burden on +OAuth2-based providers which require an ID token (e.g. this is done by various +default [auth +handlers](https://backstage.io/docs/auth/identity-resolver/#authhandler)) to add +`openid` to their default scopes. _That_ could carry another indirect benefit: +by removing `openid` from the default scopes for a provider, grants for +resource-specific access tokens can avoid requesting excess ID token-related +scopes. diff --git a/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.test.ts b/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.test.ts index 0bb40c23fc..63070120ef 100644 --- a/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.test.ts +++ b/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.test.ts @@ -48,9 +48,8 @@ describe('OAuth2', () => { expect(await oauth2.getAccessToken('my-scope my-scope2')).toBe( 'access-token', ); - expect(getSession).toHaveBeenCalledTimes(1); - expect(getSession.mock.calls[0][0].scopes).toEqual( - new Set(['my-scope', 'my-scope2']), + expect(getSession).toHaveBeenCalledWith( + expect.objectContaining({ scopes: new Set(['my-scope', 'my-scope2']) }), ); }); @@ -65,9 +64,10 @@ describe('OAuth2', () => { }); expect(await oauth2.getAccessToken('my-scope')).toBe('access-token'); - expect(getSession).toHaveBeenCalledTimes(1); - expect(getSession.mock.calls[0][0].scopes).toEqual( - new Set(['my-prefix/my-scope']), + expect(getSession).toHaveBeenCalledWith( + expect.objectContaining({ + scopes: new Set(['my-prefix/my-scope']), + }), ); }); @@ -82,7 +82,11 @@ describe('OAuth2', () => { }); expect(await oauth2.getIdToken()).toBe('id-token'); - expect(getSession).toHaveBeenCalledTimes(1); + expect(getSession).toHaveBeenCalledWith( + expect.objectContaining({ + scopes: new Set(['openid']), + }), + ); }); it('should get optional id token', async () => { @@ -96,7 +100,11 @@ describe('OAuth2', () => { }); expect(await oauth2.getIdToken({ optional: true })).toBe('id-token'); - expect(getSession).toHaveBeenCalledTimes(1); + expect(getSession).toHaveBeenCalledWith( + expect.objectContaining({ + scopes: new Set(['openid']), + }), + ); }); it('should share popup closed errors', async () => { diff --git a/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts b/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts index ad2d04cb56..6f88178415 100644 --- a/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts +++ b/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts @@ -153,7 +153,10 @@ export default class OAuth2 } async getIdToken(options: AuthRequestOptions = {}) { - const session = await this.sessionManager.getSession(options); + const session = await this.sessionManager.getSession({ + ...options, + scopes: new Set(['openid']), + }); return session?.providerInfo.idToken ?? ''; } From ab750ddc4f2b3deac7eb0aabb797b99673647f43 Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Mon, 27 Feb 2023 21:03:56 -0500 Subject: [PATCH 2/3] GitLab is an OpenIdConnectApi Signed-off-by: Jamie Klassen --- .changeset/young-walls-prove.md | 5 +++++ packages/core-plugin-api/api-report.md | 6 +++++- packages/core-plugin-api/src/apis/definitions/auth.ts | 6 +++++- packages/integration-react/api-report.md | 6 +++++- 4 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 .changeset/young-walls-prove.md diff --git a/.changeset/young-walls-prove.md b/.changeset/young-walls-prove.md new file mode 100644 index 0000000000..33fafa1548 --- /dev/null +++ b/.changeset/young-walls-prove.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-plugin-api': minor +--- + +The GitLab auth provider can now be used to get OpenID tokens. diff --git a/packages/core-plugin-api/api-report.md b/packages/core-plugin-api/api-report.md index 4887f0b7f2..eabd300fc6 100644 --- a/packages/core-plugin-api/api-report.md +++ b/packages/core-plugin-api/api-report.md @@ -482,7 +482,11 @@ export const githubAuthApiRef: ApiRef< // @public export const gitlabAuthApiRef: ApiRef< - OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi + OAuthApi & + OpenIdConnectApi & + ProfileInfoApi & + BackstageIdentityApi & + SessionApi >; // @public diff --git a/packages/core-plugin-api/src/apis/definitions/auth.ts b/packages/core-plugin-api/src/apis/definitions/auth.ts index 43597639b6..62d0d5c810 100644 --- a/packages/core-plugin-api/src/apis/definitions/auth.ts +++ b/packages/core-plugin-api/src/apis/definitions/auth.ts @@ -357,7 +357,11 @@ export const oktaAuthApiRef: ApiRef< * for a full list of supported scopes. */ export const gitlabAuthApiRef: ApiRef< - OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi + OAuthApi & + OpenIdConnectApi & + ProfileInfoApi & + BackstageIdentityApi & + SessionApi > = createApiRef({ id: 'core.auth.gitlab', }); diff --git a/packages/integration-react/api-report.md b/packages/integration-react/api-report.md index 5b0c9d6174..3af0704990 100644 --- a/packages/integration-react/api-report.md +++ b/packages/integration-react/api-report.md @@ -23,7 +23,11 @@ export class ScmAuth implements ScmAuthApi { ScmAuthApi, { github: OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi; - gitlab: OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi; + gitlab: OAuthApi & + OpenIdConnectApi & + ProfileInfoApi & + BackstageIdentityApi & + SessionApi; azure: OAuthApi & OpenIdConnectApi & ProfileInfoApi & From 8adeb19b37d60f55c6b2a906a630e13f05befbb3 Mon Sep 17 00:00:00 2001 From: Jamie Klassen Date: Thu, 16 Feb 2023 14:02:58 -0500 Subject: [PATCH 3/3] GitLab is an oidcTokenProvider Signed-off-by: Jamie Klassen --- .changeset/light-bees-end.md | 5 +++++ docs/auth/gitlab/provider.md | 6 +++++- docs/features/kubernetes/configuration.md | 5 +++-- plugins/kubernetes/src/plugin.ts | 4 ++++ 4 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 .changeset/light-bees-end.md diff --git a/.changeset/light-bees-end.md b/.changeset/light-bees-end.md new file mode 100644 index 0000000000..9fbbc44da0 --- /dev/null +++ b/.changeset/light-bees-end.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes': patch +--- + +GitLab can now be used as an `oidcTokenProvider` for Kubernetes clusters diff --git a/docs/auth/gitlab/provider.md b/docs/auth/gitlab/provider.md index 5041e161c5..dc41617812 100644 --- a/docs/auth/gitlab/provider.md +++ b/docs/auth/gitlab/provider.md @@ -18,7 +18,11 @@ Settings for local development: - Name: Backstage (or your custom app name) - Redirect URI: `http://localhost:7007/api/auth/gitlab/handler/frame` -- Scopes: `read_api` and `read_user` +- Scopes: `read_user` for sign-in. If you also need ID tokens (e.g. if you are + using the Kubernetes plugin and have clusters with `authProvider: oidc` and + [`oidcTokenProvider: +gitlab`](https://backstage.io/docs/features/kubernetes/configuration/#clustersoidctokenprovider-optional)), + add the `openid` scope. ## Configuration diff --git a/docs/features/kubernetes/configuration.md b/docs/features/kubernetes/configuration.md index 837574aa9e..458637f316 100644 --- a/docs/features/kubernetes/configuration.md +++ b/docs/features/kubernetes/configuration.md @@ -160,8 +160,9 @@ auth: audience: ${AUTH_OKTA_AUDIENCE} ``` -The following values are supported out-of-the-box by the frontend: `google`, `microsoft`, -`okta`, `onelogin`. +The following values are supported out-of-the-box by the frontend: `gitlab` (the +application whose `clientId` is used by the auth provider should be granted the +`openid` scope), `google`, `microsoft`, `okta`, `onelogin`. Take note that `oidcTokenProvider` is just the issuer for the token, you can use any of these with an OIDC enabled cluster, like using `microsoft` as the issuer for a EKS diff --git a/plugins/kubernetes/src/plugin.ts b/plugins/kubernetes/src/plugin.ts index 124bff831b..e2b13f43fe 100644 --- a/plugins/kubernetes/src/plugin.ts +++ b/plugins/kubernetes/src/plugin.ts @@ -23,6 +23,7 @@ import { createRouteRef, discoveryApiRef, identityApiRef, + gitlabAuthApiRef, googleAuthApiRef, microsoftAuthApiRef, oktaAuthApiRef, @@ -49,18 +50,21 @@ export const kubernetesPlugin = createPlugin({ createApiFactory({ api: kubernetesAuthProvidersApiRef, deps: { + gitlabAuthApi: gitlabAuthApiRef, googleAuthApi: googleAuthApiRef, microsoftAuthApi: microsoftAuthApiRef, oktaAuthApi: oktaAuthApiRef, oneloginAuthApi: oneloginAuthApiRef, }, factory: ({ + gitlabAuthApi, googleAuthApi, microsoftAuthApi, oktaAuthApi, oneloginAuthApi, }) => { const oidcProviders = { + gitlab: gitlabAuthApi, google: googleAuthApi, microsoft: microsoftAuthApi, okta: oktaAuthApi,