diff --git a/ansible/roles/schulcloud-server-core/templates/deployment.yml.j2 b/ansible/roles/schulcloud-server-core/templates/deployment.yml.j2 index 0750bf91495..965408c0910 100644 --- a/ansible/roles/schulcloud-server-core/templates/deployment.yml.j2 +++ b/ansible/roles/schulcloud-server-core/templates/deployment.yml.j2 @@ -35,6 +35,9 @@ spec: - containerPort: 3030 name: api protocol: TCP + - containerPort: 4030 + name: api-admin + protocol: TCP - containerPort: 9090 name: api-metrics protocol: TCP diff --git a/apps/server/src/modules/authentication/strategy/x-api-key.strategy.spec.ts b/apps/server/src/modules/authentication/strategy/x-api-key.strategy.spec.ts new file mode 100644 index 00000000000..7dd9f45f2f8 --- /dev/null +++ b/apps/server/src/modules/authentication/strategy/x-api-key.strategy.spec.ts @@ -0,0 +1,72 @@ +import { UnauthorizedException } from '@nestjs/common'; +import { Test, TestingModule } from '@nestjs/testing'; +import { Configuration } from '@hpi-schul-cloud/commons/lib'; +import { ConfigService } from '@nestjs/config'; +import { createMock } from '@golevelup/ts-jest'; +import { XApiKeyStrategy } from './x-api-key.strategy'; +import { IXApiKeyConfig } from '../config/x-api-key.config'; + +describe('XApiKeyStrategy', () => { + let module: TestingModule; + let strategy: XApiKeyStrategy; + let configService: ConfigService; + Configuration.set('ADMIN_API__ALLOWED_API_KEYS', '1ab2c3d4e5f61ab2c3d4e5f6'); + + beforeAll(async () => { + module = await Test.createTestingModule({ + imports: [], + providers: [ + XApiKeyStrategy, + { + provide: ConfigService, + useValue: createMock>({ get: () => ['1ab2c3d4e5f61ab2c3d4e5f6'] }), + }, + ], + }).compile(); + + strategy = module.get(XApiKeyStrategy); + configService = module.get(ConfigService); + }); + + afterAll(async () => { + await module.close(); + }); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + describe('validate', () => { + const setup = () => { + const CORRECT_API_KEY = '1ab2c3d4e5f61ab2c3d4e5f6'; + const INVALID_API_KEY = '1ab2c3d4e5f61ab2c3d4e5f6778173'; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const done = jest.fn((error: Error | null, data: boolean | null) => {}); + + return { CORRECT_API_KEY, INVALID_API_KEY, done }; + }; + describe('when a valid api key is provided', () => { + it('should do nothing', () => { + const { CORRECT_API_KEY, done } = setup(); + strategy.validate(CORRECT_API_KEY, done); + expect(done).toBeCalledWith(null, true); + }); + }); + + describe('when a invalid api key is provided', () => { + it('should throw error', () => { + const { INVALID_API_KEY, done } = setup(); + strategy.validate(INVALID_API_KEY, done); + expect(done).toBeCalledWith(new UnauthorizedException(), null); + }); + }); + }); + + describe('constructor', () => { + it('should create strategy', () => { + const ApiKeyStrategy = new XApiKeyStrategy(configService); + expect(ApiKeyStrategy).toBeDefined(); + expect(ApiKeyStrategy).toBeInstanceOf(XApiKeyStrategy); + }); + }); +}); diff --git a/config/default.json b/config/default.json index f4ebccc4627..c3f1ade0738 100644 --- a/config/default.json +++ b/config/default.json @@ -43,6 +43,7 @@ "EXTERNAL_TOOL_MAX_LOGO_SIZE_IN_BYTES": 300000 }, "ADMIN_API": { - "ENABLED": true + "ENABLED": true, + "ALLOWED_API_KEYS": "1ab2c3d4e5f61ab2c3d4e5f6" } }