Merge pull request #16401 from jamieklassen/gitlab-oidc-k8s
GitLab auth provider gets ID tokens and be used as a k8s oidcTokenProvider
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes': patch
|
||||
---
|
||||
|
||||
GitLab can now be used as an `oidcTokenProvider` for Kubernetes clusters
|
||||
@@ -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.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-plugin-api': minor
|
||||
---
|
||||
|
||||
The GitLab auth provider can now be used to get OpenID tokens.
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 () => {
|
||||
|
||||
@@ -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 ?? '';
|
||||
}
|
||||
|
||||
|
||||
@@ -482,7 +482,11 @@ export const githubAuthApiRef: ApiRef<
|
||||
|
||||
// @public
|
||||
export const gitlabAuthApiRef: ApiRef<
|
||||
OAuthApi & ProfileInfoApi & BackstageIdentityApi & SessionApi
|
||||
OAuthApi &
|
||||
OpenIdConnectApi &
|
||||
ProfileInfoApi &
|
||||
BackstageIdentityApi &
|
||||
SessionApi
|
||||
>;
|
||||
|
||||
// @public
|
||||
|
||||
@@ -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',
|
||||
});
|
||||
|
||||
@@ -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 &
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user