Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make parameters encoding configurable with an environmental variable #500

Merged
merged 2 commits into from
Nov 12, 2024
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
1 change: 1 addition & 0 deletions .env.development.local.template
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ NODE_TLS_REJECT_UNAUTHORIZED=0
[gateway]
RUCIO_AUTH_HOST=https://rucio-devmaany.cern.ch:443
RUCIO_HOST=https://rucio-devmaany.cern.ch:443
PARAMS_ENCODING_ENABLED=false

[oidc]
OIDC_ENABLED=true
Expand Down
5 changes: 5 additions & 0 deletions src/lib/core/port/secondary/env-config-gateway-output-port.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,9 @@ export default interface EnvConfigGatewayOutputPort {
* @returns the URL of the VO/Experiment community that maintains the Rucio WebUI instance
*/
projectURL(): Promise<string>;

/**
* @returns whether the query parameters should get URI encoded
*/
paramsEncodingEnabled(): Promise<boolean>;
}
9 changes: 9 additions & 0 deletions src/lib/infrastructure/gateway/env-config-gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,15 @@ class EnvConfigGateway implements EnvConfigGatewayOutputPort {
}
return Promise.resolve(undefined);
}

async paramsEncodingEnabled(): Promise<boolean> {
const value = await this.get('PARAMS_ENCODING_ENABLED');
if (value === 'true' || value === 'True' || value === 'TRUE') {
return Promise.resolve(true);
} else {
return Promise.resolve(false);
}
}
}

export default EnvConfigGateway;
3 changes: 2 additions & 1 deletion src/lib/sdk/gateway-endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@ export abstract class BaseEndpoint<TDTO extends BaseDTO> {
throw new Error(`Request not initialized for ${this.constructor.name}`);
}

const preparedRequest = prepareRequestArgs(this.request);
const encodeParams = await this.envConfigGateway.paramsEncodingEnabled();
const preparedRequest = prepareRequestArgs(this.request, encodeParams);

const response: Response = await fetch(preparedRequest.url, preparedRequest.requestArgs);
if (!response.ok) {
Expand Down
10 changes: 7 additions & 3 deletions src/lib/sdk/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,21 @@ export type HTTPRequest = {
/**
* Prepares the request arguments for an HTTP request.
* @param {HTTPRequest} request - The HTTP request to prepare arguments for.
* @param {boolean} encodeParams - Whether the query parameters should get URI encoded
* @returns {{ url: string | URL; requestArgs: RequestInit }} - An object containing the URL and request arguments.
*/
export function prepareRequestArgs(request: HTTPRequest): {
export function prepareRequestArgs(
request: HTTPRequest,
encodeParams: boolean = false,
): {
url: string | URL;
requestArgs: RequestInit;
} {
if (request.params) {
const url = new URL(request.url);
Object.keys(request.params).forEach(key => {
const encodedValue = encodeURIComponent(request.params![key]);
url.searchParams.append(key, encodedValue);
const value = request.params![key];
url.searchParams.append(key, encodeParams ? encodeURIComponent(value) : value);
});
request.url = url.toString();
}
Expand Down
13 changes: 10 additions & 3 deletions src/lib/sdk/streaming-gateway.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import 'reflect-metadata';
import StreamGatewayOutputPort from '@/lib/core/port/secondary/stream-gateway-output-port';
import { injectable } from 'inversify';
import { inject, injectable } from 'inversify';
import fetch, { Response } from 'node-fetch';
import { PassThrough, Transform } from 'node:stream';
import { HTTPRequest, prepareRequestArgs } from '@/lib/sdk/http';
import { BytesToStringifiedJSONTransform, NewlineDelimittedDataParser } from '@/lib/sdk/stream-transformers';
import type EnvConfigGatewayOutputPort from '@/lib/core/port/secondary/env-config-gateway-output-port';
import GATEWAYS from '@/lib/infrastructure/ioc/ioc-symbols-gateway';

@injectable()
export default class StreamingGateway implements StreamGatewayOutputPort {
constructor(@inject(GATEWAYS.ENV_CONFIG) private envConfigGateway: EnvConfigGatewayOutputPort) {}

private convertChunkBytesToString = new Transform({
transform(chunk, encoding, callback) {
callback(null, chunk.toString());
},
});

async getTextStream(request: HTTPRequest): Promise<PassThrough | Response> {
const { url, requestArgs } = prepareRequestArgs(request);
const encodeParams = await this.envConfigGateway.paramsEncodingEnabled();
const { url, requestArgs } = prepareRequestArgs(request, encodeParams);

const response = await fetch(url, requestArgs);
if (!response.ok || response.body === null) {
Expand All @@ -27,7 +33,8 @@ export default class StreamingGateway implements StreamGatewayOutputPort {
}

async getJSONChunks(request: HTTPRequest, ndjson: boolean = false): Promise<{ type: 'response' | 'stream'; content: PassThrough | Response }> {
const { url, requestArgs } = prepareRequestArgs(request);
const encodeParams = await this.envConfigGateway.paramsEncodingEnabled();
const { url, requestArgs } = prepareRequestArgs(request, encodeParams);
const response = await fetch(url, requestArgs);

if (!response.ok || response.body === null) {
Expand Down
2 changes: 2 additions & 0 deletions tools/env-generator/.env.template
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export RUCIO_WEBUI_ENABLE_SSL="false"
# SERVER_CA_BUNDLE is required if you are have enabled SSL. This CA bundle should verify the SSL certificate of the Rucio server.
# export RUCIO_WEBUI_SERVER_CA_BUNDLE="/path/to/ca-bundle.pem"
export RUCIO_WEBUI_PROJECT_URL="https://atlas.cern/"
# PARAMS_ENCODING_ENABLED must be set to true if your policy schema for DIDs includes special characters like slashes (/) or plus (+).
export RUCIO_WEBUI_PARAMS_ENCODING_ENABLED="false"

export RUCIO_WEBUI_MULTIVO_ENABLED="true"
export RUCIO_WEBUI_VO_DEFAULT="def"
Expand Down
31 changes: 18 additions & 13 deletions tools/env-generator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,24 @@ cp .env.template .env.base

2. Edit the `.env.base` file and add the required environment variables. All the variables **MUST** be prefixed with ` RUCIO*WEBUI*`` The variables should be added in the following format: `export RUCIO*WEBUI*<VARIABLE_NAME>=<VARIABLE_VALUE>`

| Variable Name | Full Name | Description | Example | Default |
| ---------------- | ---------------------------- | ------------------------------------------------------------------------------------------ | ------------------------------ | ------- |
| RUCIO_HOST | RUCIO_WEBUI_RUCIO_HOST | URL for the Rucio Server | https://rucio-lb-prod.cern.ch | |
| RUCIO_AUTH_HOST | RUCIO_WEBUI_RUCIO_AUTH_HOST | URL for the Rucio authentication server | https://rucio-auth-host.ch:443 | |
| HOSTNAME | RUCIO_WEBUI_HOSTNAME | Public HOSTNAME at which Rucio WebUI will be accessible. It may include port number. | rucio-ui.cern.ch | |
| ENABLE_SSL | RUCIO_WEBUI_ENABLE_SSL | Enable or Disable TLS Termination (true or false) | true | false |
| SERVER_CA_BUNDLE | RUCIO_WEBUI_SERVER_CA_BUNDLE | Path to the CA bundle file that can verify Rucio Server certificate. If ENABLE_SSL is set. | /path/to/ca-bundle.pem | |
| PROJECT_URL | RUCIO_WEBUI_PROJECT_URL | Public URL for your project | https://atlas.cern.ch | |
| VO_DEFAULT | RUCIO_WEBUI_VO_DEFAULT | Short name for the default VO used for authentication | def | def |
| VO_LIST | RUCIO_WEBUI_VO_LIST | CSV string containing the list of supported VOs | def, atl, cms | def |
| MULTIVO_ENABLED | RUCIO_WEBUI_MULTIVO_ENABLED | Whether to enable multi-VO config (true or false) | true | |
| OIDC_ENABLED | RUCIO_WEBUI_OIDC_ENABLED | Enable or Disable OIDC Authentication (true or false) | true | |
| OIDC_PROVIDERS | RUCIO_WEBUI_OIDC_PROVIDERS | CSV string containing names of OIDC Providers | cern, indigo | |
**NOTE** In order to support DID schemas that use special characters like "/", a new configuration option has been added to the new webui to enable or disable this functionality.
In cases where DID schemas use any such special characters, the Apache configuration of the Rucio Server most likely uses `AllowEncodedSlashes` or `AllowEncode` directives.
The `PARAMS_ENCODING_ENABLED` in the helm chart config of the Rucio WebUI tells the webui to encode the URI parameters when requests are sent out to the rucio server.

| Variable Name | Full Name | Description | Example | Default |
| ----------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------ | ------------------------------ | ------- |
| RUCIO_HOST | RUCIO_WEBUI_RUCIO_HOST | URL for the Rucio Server | https://rucio-lb-prod.cern.ch | |
| RUCIO_AUTH_HOST | RUCIO_WEBUI_RUCIO_AUTH_HOST | URL for the Rucio authentication server | https://rucio-auth-host.ch:443 | |
| PARAMS_ENCODING_ENABLED | RUCIO_WEBUI_PARAMS_ENCODING_ENABLED | If your DID schema has special characters like '/' or '+' in the name, set this to true. | true | false |
| HOSTNAME | RUCIO_WEBUI_HOSTNAME | Public HOSTNAME at which Rucio WebUI will be accessible. It may include port number. | rucio-ui.cern.ch | |
| ENABLE_SSL | RUCIO_WEBUI_ENABLE_SSL | Enable or Disable TLS Termination (true or false) | true | false |
| SERVER_CA_BUNDLE | RUCIO_WEBUI_SERVER_CA_BUNDLE | Path to the CA bundle file that can verify Rucio Server certificate. If ENABLE_SSL is set. | /path/to/ca-bundle.pem | |
| PROJECT_URL | RUCIO_WEBUI_PROJECT_URL | Public URL for your project | https://atlas.cern.ch | |
| VO_DEFAULT | RUCIO_WEBUI_VO_DEFAULT | Short name for the default VO used for authentication | def | def |
| VO_LIST | RUCIO_WEBUI_VO_LIST | CSV string containing the list of supported VOs | def, atl, cms | def |
| MULTIVO_ENABLED | RUCIO_WEBUI_MULTIVO_ENABLED | Whether to enable multi-VO config (true or false) | true | |
| OIDC_ENABLED | RUCIO_WEBUI_OIDC_ENABLED | Enable or Disable OIDC Authentication (true or false) | true | |
| OIDC_PROVIDERS | RUCIO_WEBUI_OIDC_PROVIDERS | CSV string containing names of OIDC Providers | cern, indigo | |

For each `VO` specified in the `VO_LIST` variable, the additional variables need to be specified. The variables should be added in the following format:
`export RUCIO_WEBUI_VO_<VO_SHORT_NAME>_<VARIABLE_NAME>=<VARIABLE_VALUE>`. An example for the default VO is shown below:
Expand Down
1 change: 1 addition & 0 deletions tools/env-generator/src/api/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export class WebUIEnvTemplateCompiler {
'VO_DEFAULT': 'def',
'OIDC_ENABLED': 'false',
'ENABLE_SSL': 'false',
'PARAMS_ENCODING_ENABLED': 'false',
...this.environmentVariables,
}
}
Expand Down
1 change: 1 addition & 0 deletions tools/env-generator/src/templates/.env.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ NODE_EXTRA_TLS_CERTS={{ context.SERVER_CA_BUNDLE }}
[gateway]
RUCIO_AUTH_HOST={{ context.RUCIO_AUTH_HOST }}
RUCIO_HOST={{ context.RUCIO_HOST }}
PARAMS_ENCODING_ENABLED={{ context.PARAMS_ENCODING_ENABLED }}

[oidc]
OIDC_ENABLED={{ context.OIDC_ENABLED }}
Expand Down
Loading