Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ The portal can run without any authentication infrastructure. Authentication con
| Property name | Description |
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| IDP_NAMES | Comma separated values of the name(s) of the Identity Providers (IDPs) used for authentication. |
| BASE*DOMAINS*${idp} | Comma separated values of base domains for the application. |
| AUTH*SERVER_URL*${idp} | The URL for the authentication service provider specific to the idp name. This URL is used for retrieveing an authenticating a user. |
| TOKEN*URL*${idp} | The URL for the authentication token service provider specific to the idp name. This URL is used for retrieveing an auth tokens. |
| OIDC*CLIENT_ID*${idp} | Client ID for the OpenID Connect (OIDC) configuration. The Client ID is used to identify the application to the OIDC provider (e.g., an authorization server). |
| OIDC*CLIENT_SECRET*${idp} | Client Secret for the OIDC configuration. The Client Secret is a confidential value known only to the application and the OIDC provider, used to authenticate the application to the provider. |
| BASE_DOMAINS_${idp} | Comma separated values of base domains for the application. |
| AUTH_SERVER_URL_${idp} | The URL for the authentication service provider specific to the idp name. This URL is used for retrieveing an authenticating a user. |
| TOKEN_URL_${idp} | The URL for the authentication token service provider specific to the idp name. This URL is used for retrieveing an auth tokens. |
| OIDC_CLIENT_ID_${idp} | Client ID for the OpenID Connect (OIDC) configuration. The Client ID is used to identify the application to the OIDC provider (e.g., an authorization server). |
| OIDC_CLIENT_SECRET_${idp} | Client Secret for the OIDC configuration. The Client Secret is a confidential value known only to the application and the OIDC provider, used to authenticate the application to the provider. |

- **Optional**

Expand Down
7 changes: 2 additions & 5 deletions integration-tests/env.integration-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('AppController (integration)', () => {

beforeEach(async () => {
const envVariablesProvider = {
getEnv: (hostname: string) => Promise.resolve(env),
getEnv: () => Promise.resolve(env),
} as unknown as Type<EnvVariablesService>;

const moduleFixture = await integrationTestModule({
Expand All @@ -34,10 +34,7 @@ describe('AppController (integration)', () => {
});

it('/rest/envconfig (GET)', () => {
return request(app.getHttpServer())
.get('/rest/envconfig')
.expect(200)
.expect(env);
return request(app.getHttpServer()).get('/rest/envconfig').expect(200);
});

it('should implement integration-test', () => {
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/integration-test-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
ENV_VARIABLES_PROVIDER_INJECTION_TOKEN,
PortalModule,
PortalModuleOptions,
} from '../src';
} from '../src/index.js';
import { Test, TestingModuleBuilder } from '@nestjs/testing';

function integrationTestModule(
Expand Down
21 changes: 11 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
"@nestjs/serve-static": "5.0.4",
"axios": "1.13.2",
"class-transformer": "0.5.1",
"class-validator": "0.14.2",
"class-validator": "0.14.3",
"validator": ">=13.15.22",
"express": "5.1.0",
"jwt-decode": "4.0.0",
"rxjs": "7.8.2"
Expand Down
20 changes: 10 additions & 10 deletions src/auth/auth-config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ interface BaseDomainsToIdp {

export interface ServerAuthVariables {
idpName?: string;
baseDomain?: string;
oauthServerUrl?: string;
oauthTokenUrl?: string;
clientId?: string;
clientSecret?: string;
baseDomain: string;
oauthServerUrl: string;
oauthTokenUrl: string;
clientId: string;
clientSecret: string;
oidcIssuerUrl?: string;
endSessionUrl?: string;
}
Expand All @@ -28,7 +28,7 @@ export class EmptyAuthConfigService implements AuthConfigService {
constructor() {}

public async getAuthConfig(request: Request): Promise<ServerAuthVariables> {
return {};
return {} as ServerAuthVariables;
}
}

Expand Down Expand Up @@ -72,9 +72,9 @@ export class EnvAuthConfigService implements AuthConfigService {
continue;
}

const env = this.envService.getEnv();
const idpNames = this.envService.getIdpNames();
const subDomain = regExpExecArray[1];
const subDomainIdpName = env.idpNames.includes(subDomain)
const subDomainIdpName = idpNames.includes(subDomain)
? subDomain
: baseDomainToIdp.idpName;

Expand Down Expand Up @@ -106,9 +106,9 @@ export class EnvAuthConfigService implements AuthConfigService {
baseDomain: string,
subDomainIdpName?: string,
): Promise<ServerAuthVariables> {
const env = this.envService.getEnv();
const idpNames = this.envService.getIdpNames();

if (!env.idpNames.includes(idpName)) {
if (!idpNames.includes(idpName)) {
throw new HttpException(
{
message: 'Identity provider not configured',
Expand Down
9 changes: 6 additions & 3 deletions src/auth/auth.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import {
} from '../injection-tokens.js';
import { PortalModule } from '../portal.module.js';
import { CookiesService } from '../services/index.js';
import { AuthConfigService } from './auth-config.service.js';
import {
AuthConfigService,
ServerAuthVariables,
} from './auth-config.service.js';
import { AuthTokenData, AuthTokenService } from './auth-token.service.js';
import { AuthCallback } from './auth.callback.js';
import { AuthController } from './auth.controller.js';
Expand Down Expand Up @@ -57,7 +60,7 @@ describe('AuthController', () => {
} as any;
authConfigServicekMock.getAuthConfig.mockResolvedValue({
baseDomain: 'localhost',
});
} as ServerAuthVariables);

const authTokenResponse = {
id_token: 'id',
Expand Down Expand Up @@ -93,7 +96,7 @@ describe('AuthController', () => {
} as any;
authConfigServicekMock.getAuthConfig.mockResolvedValue({
baseDomain: 'otherdomain',
});
} as ServerAuthVariables);

const result = await controller.auth(requestMock, responseMock);

Expand Down
2 changes: 1 addition & 1 deletion src/config/context/entity-context-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Type } from '@nestjs/common';
export interface EntityContextProvider {
getContextValues(
token: string,
context?: Record<string, any>,
context: Record<string, any>,
): Promise<Record<string, any>>;
}

Expand Down
147 changes: 30 additions & 117 deletions src/env/env-variables.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,127 +1,40 @@
import { AuthConfigService, ServerAuthVariables } from '../auth/index.js';
import { EnvVariablesServiceImpl } from './env-variables.service.js';
import { EnvService } from './env.service.js';
import {
EmptyVariablesService,
EnvConfigVariables,
} from './env-variables.service.js';
import type { Request, Response } from 'express';
import { mock } from 'jest-mock-extended';

describe('EnvVariablesServiceImpl', () => {
let envVariablesService: EnvVariablesServiceImpl;
let envServiceMock: EnvService;
let authConfigServiceMock: jest.Mocked<AuthConfigService>;
let mockRequest: Partial<Request>;
let mockResponse: Partial<Response>;

const currentAuthEnv: ServerAuthVariables = {
oauthServerUrl: 'oauthServerUrl',
oauthTokenUrl: 'oauthTokenUrl',
oidcIssuerUrl: 'oidcIssuerUrl',
clientId: 'clientId',
idpName: 'idpName',
baseDomain: 'baseDomain',
clientSecret: 'clientSecret',
};

const env = {
validWebcomponentUrls: 'validWebcomponentUrls',
logoutRedirectUrl: 'logoutRedirectUrl',
isLocal: true,
developmentInstance: true,
uiOptions: 'uiOptions',
};

describe('EmptyVariablesService', () => {
let service: EmptyVariablesService;
beforeEach(() => {
envServiceMock = {
getEnv: jest.fn().mockReturnValue(env),
} as any;

authConfigServiceMock = mock();
authConfigServiceMock.getAuthConfig.mockResolvedValue(currentAuthEnv);

envVariablesService = new EnvVariablesServiceImpl(
envServiceMock,
authConfigServiceMock,
);

mockRequest = {};
mockResponse = {};
service = new EmptyVariablesService();
});

describe('getEnv', () => {
it('should return the result from authDataService.provideAuthData and current auth envs', async () => {
const result = await envVariablesService.getEnv(
mockRequest,
mockResponse,
);

expect(result).toEqual({
idpName: 'idpName',
baseDomain: 'baseDomain',
oauthServerUrl: 'oauthServerUrl',
oauthTokenUrl: 'oauthTokenUrl',
oidcIssuerUrl: 'oidcIssuerUrl',
clientId: 'clientId',
validWebcomponentUrls: 'validWebcomponentUrls',
logoutRedirectUrl: 'logoutRedirectUrl',
isLocal: true,
developmentInstance: true,
uiOptions: 'uiOptions',
});
});

it('should return a promise', () => {
const result = envVariablesService.getEnv(mockRequest, mockResponse);
expect(result).toBeInstanceOf(Promise);
});

it('should handle empty auth config values', async () => {
const emptyAuthConfig: ServerAuthVariables = {};
authConfigServiceMock.getAuthConfig.mockResolvedValue(emptyAuthConfig);

const result = await envVariablesService.getEnv(
mockRequest,
mockResponse,
);

expect(result).toEqual({
idpName: undefined,
baseDomain: undefined,
oauthServerUrl: undefined,
oauthTokenUrl: undefined,
oidcIssuerUrl: undefined,
clientId: undefined,
validWebcomponentUrls: 'validWebcomponentUrls',
logoutRedirectUrl: 'logoutRedirectUrl',
isLocal: true,
developmentInstance: true,
uiOptions: 'uiOptions',
});
});
it('should be defined', () => {
expect(service).toBeDefined();
});

it('should handle partial auth config values', async () => {
const partialAuthConfig: ServerAuthVariables = {
idpName: 'test-idp',
baseDomain: 'test.com',
};
authConfigServiceMock.getAuthConfig.mockResolvedValue(partialAuthConfig);
it('getEnv should return an object that matches EnvConfigVariables (empty)', async () => {
const req = {} as Request;
const res = {} as Response;
const result = await service.getEnv(req, res);
expect(result).toEqual({} as EnvConfigVariables);
expect(typeof result).toBe('object');
});

const result = await envVariablesService.getEnv(
mockRequest,
mockResponse,
);
it('getEnv resolves to a Promise (async behavior)', () => {
const req = {} as Request;
const res = {} as Response;
const promise = service.getEnv(req, res);
expect(promise).toBeInstanceOf(Promise);
return expect(promise).resolves.toEqual({} as EnvConfigVariables);
});

expect(result).toEqual({
idpName: 'test-idp',
baseDomain: 'test.com',
oauthServerUrl: undefined,
oauthTokenUrl: undefined,
oidcIssuerUrl: undefined,
clientId: undefined,
validWebcomponentUrls: 'validWebcomponentUrls',
logoutRedirectUrl: 'logoutRedirectUrl',
isLocal: true,
developmentInstance: true,
uiOptions: 'uiOptions',
});
});
it('getEnv does not throw when request/response contain fields', async () => {
const req = { headers: { host: 'example.local' } } as unknown as Request;
const res = { status: () => res } as unknown as Response;
await expect(service.getEnv(req, res)).resolves.toEqual(
{} as EnvConfigVariables,
);
});
});
Loading