diff --git a/plugins/auth-backend/report.sql.md b/plugins/auth-backend/report.sql.md index b135414af6..7622a5750e 100644 --- a/plugins/auth-backend/report.sql.md +++ b/plugins/auth-backend/report.sql.md @@ -5,6 +5,59 @@ > [!WARNING] > Failed to migrate down from '20220321100910_timestamptz_again.js' +## Table `oauth_authorization_sessions` + +| Column | Type | Nullable | Max Length | Default | +| ----------------------- | -------------------------- | -------- | ---------- | ----------------- | +| `client_id` | `character varying` | false | 255 | - | +| `code_challenge` | `character varying` | true | 255 | - | +| `code_challenge_method` | `character varying` | true | 255 | - | +| `expires_at` | `timestamp with time zone` | false | - | - | +| `id` | `character varying` | false | 255 | - | +| `nonce` | `character varying` | true | 255 | - | +| `redirect_uri` | `text` | false | - | - | +| `response_type` | `character varying` | false | 255 | - | +| `scope` | `text` | true | - | - | +| `state` | `character varying` | true | 255 | - | +| `status` | `text` | true | - | `'pending'::text` | +| `user_entity_ref` | `character varying` | true | 255 | - | + +### Indices + +- `oauth_authorization_sessions_client_id_user_entity_ref_index` (`client_id`, `user_entity_ref`) +- `oauth_authorization_sessions_pkey` (`id`) unique primary +- `oauth_authorization_sessions_status_expires_at_index` (`status`, `expires_at`) + +## Table `oidc_authorization_codes` + +| Column | Type | Nullable | Max Length | Default | +| ------------ | -------------------------- | -------- | ---------- | ------- | +| `code` | `character varying` | false | 255 | - | +| `expires_at` | `timestamp with time zone` | false | - | - | +| `session_id` | `character varying` | false | 255 | - | +| `used` | `boolean` | true | - | `false` | + +### Indices + +- `oidc_authorization_codes_pkey` (`code`) unique primary + +## Table `oidc_clients` + +| Column | Type | Nullable | Max Length | Default | +| ---------------- | ------------------- | -------- | ---------- | ------- | +| `client_id` | `character varying` | false | 255 | - | +| `client_name` | `character varying` | false | 255 | - | +| `client_secret` | `character varying` | false | 255 | - | +| `grant_types` | `text` | false | - | - | +| `metadata` | `text` | true | - | - | +| `redirect_uris` | `text` | false | - | - | +| `response_types` | `text` | false | - | - | +| `scope` | `text` | true | - | - | + +### Indices + +- `oidc_clients_pkey` (`client_id`) unique primary + ## Table `sessions` | Column | Type | Nullable | Max Length | Default | diff --git a/plugins/auth-backend/src/authPlugin.ts b/plugins/auth-backend/src/authPlugin.ts index f3877d48cd..025d72fcb7 100644 --- a/plugins/auth-backend/src/authPlugin.ts +++ b/plugins/auth-backend/src/authPlugin.ts @@ -66,6 +66,7 @@ export const authPlugin = createBackendPlugin({ database: coreServices.database, discovery: coreServices.discovery, auth: coreServices.auth, + httpAuth: coreServices.httpAuth, catalog: catalogServiceRef, }, async init({ @@ -75,6 +76,7 @@ export const authPlugin = createBackendPlugin({ database, discovery, auth, + httpAuth, catalog, }) { const router = await createRouter({ @@ -86,6 +88,7 @@ export const authPlugin = createBackendPlugin({ catalog, providerFactories: Object.fromEntries(providers), ownershipResolver, + httpAuth, }); httpRouter.addAuthPolicy({ path: '/', diff --git a/plugins/auth-backend/src/service/OidcRouter.test.ts b/plugins/auth-backend/src/service/OidcRouter.test.ts index 579c96470f..fe5182251f 100644 --- a/plugins/auth-backend/src/service/OidcRouter.test.ts +++ b/plugins/auth-backend/src/service/OidcRouter.test.ts @@ -24,7 +24,6 @@ import { startTestBackend, TestDatabases, TestDatabaseId, - mockCredentials, } from '@backstage/backend-test-utils'; import request from 'supertest'; import crypto from 'crypto'; @@ -68,6 +67,7 @@ describe('OidcRouter', () => { } as unknown as jest.Mocked; const mockAuth = mockServices.auth.mock(); + const mockHttpAuth = mockServices.httpAuth.mock(); const oidcService = OidcService.create({ auth: mockAuth, @@ -85,14 +85,13 @@ describe('OidcRouter', () => { logger: mockServices.logger.mock(), userInfo: userInfoDatabase, oidc: oidcDatabase, - httpAuth: mockServices.httpAuth({ - defaultCredentials: mockCredentials.user(), - }), + httpAuth: mockHttpAuth, }); return { router: oidcRouter, mocks: { + httpAuth: mockHttpAuth, auth: mockAuth, oidc: oidcDatabase, userInfo: userInfoDatabase, @@ -138,7 +137,6 @@ describe('OidcRouter', () => { ], }); - auth.authenticate.mockResolvedValueOnce({} as any); auth.isPrincipal.mockReturnValueOnce(true); const response = await request(server) @@ -194,7 +192,6 @@ describe('OidcRouter', () => { ], }); - auth.authenticate.mockResolvedValueOnce({} as any); auth.isPrincipal.mockReturnValueOnce(true); const response = await request(server) @@ -361,9 +358,9 @@ describe('OidcRouter', () => { }); }); - it('should approve consent request', async () => { + it('should approve authorization session', async () => { const { - mocks: { auth, service }, + mocks: { auth, service, httpAuth }, router, } = await createRouter(databaseId); @@ -403,6 +400,14 @@ describe('OidcRouter', () => { ], }); + httpAuth.credentials.mockResolvedValueOnce({ + principal: { + type: 'user', + userEntityRef: 'user:default/test-user', + }, + $$type: '@backstage/BackstageCredentials', + }); + auth.isPrincipal.mockReturnValueOnce(true); const response = await request(server) @@ -474,17 +479,18 @@ describe('OidcRouter', () => { describe('token exchange', () => { it('should exchange authorization code for tokens', async () => { const { - mocks: { auth, service, tokenIssuer }, + mocks: { auth, service, tokenIssuer, httpAuth }, router, } = await createRouter(databaseId); - auth.authenticate.mockResolvedValueOnce({ + httpAuth.credentials.mockResolvedValueOnce({ principal: { type: 'user', userEntityRef: 'user:default/test-user', }, $$type: '@backstage/BackstageCredentials', }); + auth.isPrincipal.mockReturnValueOnce(true); tokenIssuer.issueToken.mockResolvedValue({ @@ -565,7 +571,7 @@ describe('OidcRouter', () => { it('should exchange authorization code for tokens with PKCE', async () => { const { - mocks: { auth, service, tokenIssuer }, + mocks: { auth, service, tokenIssuer, httpAuth }, router, } = await createRouter(databaseId); @@ -573,13 +579,14 @@ describe('OidcRouter', () => { token: 'mock-access-token-pkce', }); - auth.authenticate.mockResolvedValueOnce({ + httpAuth.credentials.mockResolvedValueOnce({ principal: { type: 'user', userEntityRef: 'user:default/test-user-pkce', }, $$type: '@backstage/BackstageCredentials', }); + auth.isPrincipal.mockReturnValueOnce(true); const client = await service.registerClient({ @@ -656,24 +663,25 @@ describe('OidcRouter', () => { expect(tokenIssuer.issueToken).toHaveBeenCalledWith({ claims: { - sub: MOCK_USER_ENTITY_REF, + sub: 'user:default/test-user-pkce', }, }); }); it('should reject token exchange with invalid client credentials', async () => { const { - mocks: { auth, service }, + mocks: { auth, service, httpAuth }, router, } = await createRouter(databaseId); - auth.authenticate.mockResolvedValueOnce({ + httpAuth.credentials.mockResolvedValueOnce({ principal: { type: 'user', userEntityRef: 'user:default/test-user', }, $$type: '@backstage/BackstageCredentials', }); + auth.isPrincipal.mockReturnValueOnce(true); const client = await service.registerClient({ @@ -789,7 +797,7 @@ describe('OidcRouter', () => { it('should exchange authorization code for tokens with PKCE S256', async () => { const { - mocks: { auth, service, tokenIssuer }, + mocks: { auth, service, tokenIssuer, httpAuth }, router, } = await createRouter(databaseId); @@ -797,13 +805,14 @@ describe('OidcRouter', () => { token: 'mock-access-token-s256', }); - auth.authenticate.mockResolvedValueOnce({ + httpAuth.credentials.mockResolvedValueOnce({ principal: { type: 'user', userEntityRef: 'user:default/test-user-s256', }, $$type: '@backstage/BackstageCredentials', }); + auth.isPrincipal.mockReturnValueOnce(true); const client = await service.registerClient({ diff --git a/plugins/auth-backend/src/service/OidcRouter.ts b/plugins/auth-backend/src/service/OidcRouter.ts index c07ffd5adb..a0acc57cec 100644 --- a/plugins/auth-backend/src/service/OidcRouter.ts +++ b/plugins/auth-backend/src/service/OidcRouter.ts @@ -211,7 +211,6 @@ export class OidcRouter { redirectUrl: result.redirectUrl, }); } catch (error) { - console.log(error); this.logger.error( `Failed to approve authorization session: ${ isError(error) ? error.message : 'Unknown error' diff --git a/plugins/auth-backend/src/service/OidcService.test.ts b/plugins/auth-backend/src/service/OidcService.test.ts index 5067cde458..4820559b01 100644 --- a/plugins/auth-backend/src/service/OidcService.test.ts +++ b/plugins/auth-backend/src/service/OidcService.test.ts @@ -28,7 +28,6 @@ import { import { AuthDatabase } from '../database/AuthDatabase'; import { OidcDatabase } from '../database/OidcDatabase'; import { UserInfoDatabase } from '../database/UserInfoDatabase'; -import { InputError, AuthenticationError } from '@backstage/errors'; import crypto from 'crypto'; import { AnyJWK, TokenIssuer } from '../identity/types';