Skip to content

Commit

Permalink
Merge pull request #2902 from Gkrumbach07/bug/RHOAIENG-8473-incorrect…
Browse files Browse the repository at this point in the history
…-token-setting-for-s3-download-api

Fix authorization header casing in storageUtils
  • Loading branch information
openshift-merge-bot[bot] authored Jun 11, 2024
2 parents efd0faf + d6bd7d7 commit 74513a0
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 61 deletions.
5 changes: 4 additions & 1 deletion backend/src/routes/api/k8s/pass-through.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
K8sResourceCommon,
K8sResourceListResult,
K8sStatus,
KubeFastifyInstance,
OauthFastifyRequest,
Expand Down Expand Up @@ -51,7 +52,9 @@ export const passThroughText = (
);
};

export const passThroughResource = <T extends K8sResourceCommon>(
export const passThroughResource = <
T extends K8sResourceCommon | K8sResourceListResult<K8sResourceCommon>,
>(
fastify: KubeFastifyInstance,
request: OauthFastifyRequest,
data: PassThroughData,
Expand Down
12 changes: 2 additions & 10 deletions backend/src/routes/api/storage/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { FastifyInstance, FastifyReply } from 'fastify';
import { getObjectSize, getObjectStream, setupMinioClient } from './storageUtils';
import { getDashboardConfig } from '../../../utils/resourceUtils';
import { getDirectCallOptions } from '../../../utils/directCallUtils';
import { getAccessToken } from '../../../utils/directCallUtils';
import { OauthFastifyRequest } from '../../../types';

export default async (fastify: FastifyInstance): Promise<void> => {
Expand All @@ -25,10 +23,7 @@ export default async (fastify: FastifyInstance): Promise<void> => {
const { namespace } = request.params;
const { key } = request.query;

const requestOptions = await getDirectCallOptions(fastify, request, request.url);
const token = getAccessToken(requestOptions);

const { client, bucket } = await setupMinioClient(fastify, token, namespace);
const { client, bucket } = await setupMinioClient(fastify, request, namespace);

const size = await getObjectSize({
client,
Expand Down Expand Up @@ -63,10 +58,7 @@ export default async (fastify: FastifyInstance): Promise<void> => {
const { namespace } = request.params;
const { key, peek } = request.query;

const requestOptions = await getDirectCallOptions(fastify, request, request.url);
const token = getAccessToken(requestOptions);

const { client, bucket } = await setupMinioClient(fastify, token, namespace);
const { client, bucket } = await setupMinioClient(fastify, request, namespace);

const stream = await getObjectStream({
client,
Expand Down
112 changes: 62 additions & 50 deletions backend/src/routes/api/storage/storageUtils.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
import { Client as MinioClient } from 'minio';
import { DSPipelineKind, KubeFastifyInstance } from '../../../types';
import {
DSPipelineKind,
K8sResourceCommon,
K8sResourceListResult,
KubeFastifyInstance,
OauthFastifyRequest,
SecretKind,
} from '../../../types';
import { Transform, TransformOptions } from 'stream';
import { passThroughResource } from '../k8s/pass-through';

export interface PreviewStreamOptions extends TransformOptions {
peek: number;
}
const DataSciencePipelineApplicationModel = {
apiVersion: 'v1alpha1',
apiGroup: 'datasciencepipelinesapplications.opendatahub.io',
kind: 'DataSciencePipelinesApplication',
plural: 'datasciencepipelinesapplications',
};

/**
* Transform stream that only stream the first X number of bytes.
Expand Down Expand Up @@ -34,40 +48,37 @@ export class PreviewStream extends Transform {

export async function getDspa(
fastify: KubeFastifyInstance,
token: string,
request: OauthFastifyRequest,
namespace: string,
): Promise<DSPipelineKind> {
const dspaResponse = await fastify.kube.customObjectsApi
.listNamespacedCustomObject(
'datasciencepipelinesapplications.opendatahub.io',
'v1alpha1',
namespace,
'datasciencepipelinesapplications',
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
{
headers: {
authorization: `Bearer ${token}`,
},
},
)
.catch((e) => {
throw `A ${e.statusCode} error occurred when trying to fetch dspa aws storage credentials: ${
e.response?.body?.message || e?.response?.statusMessage
}`;
});
const kc = fastify.kube.config;
const cluster = kc.getCurrentCluster();

// retreive the gating resource by name and namespace
const dspaResponse = await passThroughResource<K8sResourceListResult<DSPipelineKind>>(
fastify,
request,
{
url: `${cluster.server}/apis/${DataSciencePipelineApplicationModel.apiGroup}/${DataSciencePipelineApplicationModel.apiVersion}/namespaces/${namespace}/${DataSciencePipelineApplicationModel.plural}`,
method: 'GET',
},
).catch((e) => {
throw `A ${e.statusCode} error occurred when trying to fetch dspa aws storage credentials: ${
e.response?.body?.message || e?.response?.statusMessage
}`;
});

function isK8sResourceList<T extends K8sResourceCommon>(
data: any,
): data is K8sResourceListResult<T> {
return data && data.items !== undefined;
}

const dspas = (
dspaResponse?.body as {
items: DSPipelineKind[];
}
)?.items;
if (!isK8sResourceList(dspaResponse)) {
throw `A ${dspaResponse.code} error occurred when trying to fetch dspa aws storage credentials: ${dspaResponse.message}`;
}

const dspas = dspaResponse.items;

if (!dspas || !dspas.length) {
throw 'No Data Science Pipeline Application found';
Expand All @@ -78,29 +89,30 @@ export async function getDspa(

async function getDspaSecretKeys(
fastify: KubeFastifyInstance,
token: string,
request: OauthFastifyRequest,
namespace: string,
dspa: DSPipelineKind,
): Promise<{ accessKey: string; secretKey: string }> {
try {
const secret = await fastify.kube.coreV1Api.readNamespacedSecret(
dspa.spec.objectStorage.externalStorage.s3CredentialsSecret.secretName,
namespace,
undefined,
undefined,
undefined,
{
headers: {
authorization: `Bearer ${token}`,
},
},
);
const kc = fastify.kube.config;
const cluster = kc.getCurrentCluster();

const secretResp = await passThroughResource<SecretKind>(fastify, request, {
url: `${cluster.server}/api/v1/namespaces/${namespace}/secrets/${dspa.spec.objectStorage.externalStorage.s3CredentialsSecret.secretName}`,
method: 'GET',
}).catch((e) => {
throw `A ${e.statusCode} error occurred when trying to fetch secret for aws credentials: ${
e.response?.body?.message || e?.response?.statusMessage
}`;
});

const secret = secretResp as SecretKind;

const accessKey = atob(
secret.body.data[dspa.spec.objectStorage.externalStorage.s3CredentialsSecret.accessKey],
secret.data[dspa.spec.objectStorage.externalStorage.s3CredentialsSecret.accessKey],
);
const secretKey = atob(
secret.body.data[dspa.spec.objectStorage.externalStorage.s3CredentialsSecret.secretKey],
secret.data[dspa.spec.objectStorage.externalStorage.s3CredentialsSecret.secretKey],
);

if (!accessKey || !secretKey) {
Expand All @@ -120,11 +132,11 @@ async function getDspaSecretKeys(
*/
export async function setupMinioClient(
fastify: KubeFastifyInstance,
token: string,
request: OauthFastifyRequest,
namespace: string,
): Promise<{ client: MinioClient; bucket: string }> {
try {
const dspa = await getDspa(fastify, token, namespace);
const dspa = await getDspa(fastify, request, namespace);

// check if object storage connection is available
if (
Expand All @@ -139,7 +151,7 @@ export async function setupMinioClient(
const externalStorage = dspa.spec.objectStorage.externalStorage;
if (externalStorage) {
const { region, host: endPoint, bucket } = externalStorage;
const { accessKey, secretKey } = await getDspaSecretKeys(fastify, token, namespace, dspa);
const { accessKey, secretKey } = await getDspaSecretKeys(fastify, request, namespace, dspa);
return {
client: new MinioClient({ accessKey, secretKey, endPoint, region }),
bucket,
Expand Down
19 changes: 19 additions & 0 deletions backend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,15 @@ export type K8sResourceCommon = {
};
} & K8sResourceBase;

export type K8sResourceListResult<TResource extends K8sResourceCommon> = {
apiVersion: string;
items: TResource[];
metadata: {
resourceVersion: string;
continue: string;
};
};

/**
* A status object when Kube backend can't handle a request.
*/
Expand All @@ -160,6 +169,16 @@ export type K8sStatus = {
status: string;
};

export type SecretKind = K8sResourceCommon & {
metadata: {
name: string;
namespace: string;
};
data?: Record<string, string>;
stringData?: Record<string, string>;
type?: string;
};

export enum BUILD_PHASE {
none = 'Not started',
new = 'New',
Expand Down

0 comments on commit 74513a0

Please sign in to comment.