diff --git a/api/src/auth/auth.service.ts b/api/src/auth/auth.service.ts
index 77264edc94394f8702161707b06f89d006086fc4..e992fa760c238d0d475115e87cf52e5e07a0d5f3 100644
--- a/api/src/auth/auth.service.ts
+++ b/api/src/auth/auth.service.ts
@@ -17,10 +17,10 @@ export class AuthService {
return await this.engineService.login?.(username, password);
}
- login(user: User): Pick<AuthenticationOutput, 'accessToken'> {
+ async login(user: User): Promise<Pick<AuthenticationOutput, 'accessToken'>> {
const payload = { username: user.username, sub: user };
- return {
+ return Promise.resolve({
accessToken: this.jwtService.sign(payload),
- };
+ });
}
}
diff --git a/api/src/engine/connectors/datashield/main.connector.ts b/api/src/engine/connectors/datashield/main.connector.ts
index 81f7bf6bb6ecba86cba15b2350d460e57dadf933..2e4f3be2ebce9f21319426a07cda073005fcd4ec 100644
--- a/api/src/engine/connectors/datashield/main.connector.ts
+++ b/api/src/engine/connectors/datashield/main.connector.ts
@@ -1,9 +1,11 @@
import { HttpService } from '@nestjs/axios';
-import { Inject, Logger } from '@nestjs/common';
+import { Inject, Logger, NotImplementedException } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { Request } from 'express';
-import { firstValueFrom, Observable } from 'rxjs';
+import { catchError, firstValueFrom, Observable } from 'rxjs';
+import { User } from 'src/auth/models/user.model';
import { MIME_TYPES } from 'src/common/interfaces/utilities.interface';
+import { errorAxiosHandler } from 'src/common/utilities';
import { ENGINE_MODULE_OPTIONS } from 'src/engine/engine.constants';
import {
IConfiguration,
@@ -43,22 +45,50 @@ export default class DataShieldService implements IEngineService {
return {};
}
- logout(): void {
- throw new Error('Method not implemented.');
+ async login(username: string, password: string): Promise<User> {
+ const loginPath = this.options.baseurl + 'login';
+
+ const user: User = {
+ id: username,
+ username,
+ extraFields: {
+ sid: '',
+ },
+ };
+
+ const loginData = await firstValueFrom(
+ this.httpService
+ .get(loginPath, {
+ auth: { username, password },
+ })
+ .pipe(catchError((e) => errorAxiosHandler(e))),
+ );
+
+ const cookies = (loginData.headers['set-cookie'] as string[]) ?? [];
+ if (loginData.headers && loginData.headers['set-cookie']) {
+ cookies.forEach((cookie) => {
+ const [key, value] = cookie.split(/={1}/);
+ if (key === 'sid') {
+ user.extraFields.sid = value;
+ }
+ });
+ }
+
+ return user;
}
getAlgorithms(): Algorithm[] | Promise<Algorithm[]> {
- throw new Error('Method not implemented.');
+ throw new NotImplementedException();
}
- async getHistogram(variable: string): Promise<RawResult> {
+ async getHistogram(variable: string, cookie?: string): Promise<RawResult> {
const path =
this.options.baseurl + `histogram?var=${variable}&type=combine`;
const response = await firstValueFrom(
this.httpService.get(path, {
headers: {
- cookie: this.req['req'].headers['cookie'],
+ cookie,
},
}),
);
@@ -87,13 +117,16 @@ export default class DataShieldService implements IEngineService {
};
}
- async getDescriptiveStats(variable: string): Promise<TableResult> {
+ async getDescriptiveStats(
+ variable: string,
+ cookie?: string,
+ ): Promise<TableResult> {
const path = this.options.baseurl + `quantiles?var=${variable}&type=split`;
const response = await firstValueFrom(
this.httpService.get(path, {
headers: {
- cookie: this.req['req'].headers['cookie'],
+ cookie,
},
}),
);
@@ -111,6 +144,10 @@ export default class DataShieldService implements IEngineService {
data: ExperimentCreateInput,
isTransient: boolean,
): Promise<Experiment> {
+ const user = this.req.user as User;
+ const cookie = [`sid=${user.extraFields['sid']}`, `user=${user.id}`].join(
+ ';',
+ );
const expResult: Experiment = {
id: `${data.algorithm.id}-${Date.now()}`,
variables: data.variables,
@@ -126,7 +163,7 @@ export default class DataShieldService implements IEngineService {
case 'MULTIPLE_HISTOGRAMS': {
expResult.results = await Promise.all<RawResult>(
data.variables.map(
- async (variable) => await this.getHistogram(variable),
+ async (variable) => await this.getHistogram(variable, cookie),
),
);
break;
@@ -134,7 +171,8 @@ export default class DataShieldService implements IEngineService {
case 'DESCRIPTIVE_STATS': {
expResult.results = await Promise.all<TableResult>(
[...data.variables, ...data.coVariables].map(
- async (variable) => await this.getDescriptiveStats(variable),
+ async (variable) =>
+ await this.getDescriptiveStats(variable, cookie),
),
);
break;
@@ -157,40 +195,23 @@ export default class DataShieldService implements IEngineService {
}
getExperiment(id: string): Experiment | Promise<Experiment> {
- throw new Error('Method not implemented.');
+ throw new NotImplementedException();
}
removeExperiment(id: string): PartialExperiment | Promise<PartialExperiment> {
- throw new Error('Method not implemented.');
+ throw new NotImplementedException();
}
editExperient(
id: string,
expriment: ExperimentEditInput,
): Experiment | Promise<Experiment> {
- throw new Error('Method not implemented.');
+ throw new NotImplementedException();
}
async getDomains(): Promise<Domain[]> {
- const loginPath = this.options.baseurl + 'login';
-
- const loginData = await firstValueFrom(
- this.httpService.get(loginPath, {
- auth: { username: 'guest', password: 'guest123' },
- }),
- );
-
- const cookies = (loginData.headers['set-cookie'] as string[]) ?? [];
- if (loginData.headers && loginData.headers['set-cookie']) {
- cookies.forEach((cookie) => {
- const [key, value] = cookie.split(/={1}/);
- this.req.res.cookie(key, value, {
- httpOnly: true,
- //sameSite: 'none',
- });
- });
- }
-
+ const user = this.req.user as User;
+ const cookies = [`sid=${user.extraFields['sid']}`, `user=${user.id}`];
const path = this.options.baseurl + 'getvars';
const response = await firstValueFrom(
@@ -216,27 +237,27 @@ export default class DataShieldService implements IEngineService {
}
editActiveUser(): Observable<string> {
- throw new Error('Method not implemented.');
+ throw new NotImplementedException();
}
getExperimentREST(): Observable<string> {
- throw new Error('Method not implemented.');
+ throw new NotImplementedException();
}
deleteExperiment(): Observable<string> {
- throw new Error('Method not implemented.');
+ throw new NotImplementedException();
}
editExperimentREST(): Observable<string> {
- throw new Error('Method not implemented.');
+ throw new NotImplementedException();
}
startExperimentTransient(): Observable<string> {
- throw new Error('Method not implemented.');
+ throw new NotImplementedException();
}
startExperiment(): Observable<string> {
- throw new Error('Method not implemented.');
+ throw new NotImplementedException();
}
getExperiments(): string {
diff --git a/api/src/engine/engine.module.ts b/api/src/engine/engine.module.ts
index 59634992441b528ee3eab239cd62342fcc0ff7bf..3f5cf47b16136f4485649ad6ef81b96ed2bc32e5 100644
--- a/api/src/engine/engine.module.ts
+++ b/api/src/engine/engine.module.ts
@@ -2,6 +2,7 @@ import { HttpModule, HttpService } from '@nestjs/axios';
import { DynamicModule, Global, Logger, Module } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { Request } from 'express';
+import { IncomingMessage } from 'http';
import { ENGINE_MODULE_OPTIONS, ENGINE_SERVICE } from './engine.constants';
import { EngineController } from './engine.controller';
import { IEngineOptions, IEngineService } from './engine.interfaces';
@@ -50,7 +51,10 @@ export class EngineModule {
): Promise<IEngineService> {
try {
const service = await import(`./connectors/${opt.type}/main.connector`);
- const engine = new service.default(opt, httpService, req);
+ const gqlRequest = req && req['req']; // graphql headers exception
+ const request =
+ gqlRequest && gqlRequest instanceof IncomingMessage ? gqlRequest : req;
+ const engine = new service.default(opt, httpService, request);
return engine;
} catch (e) {
diff --git a/api/src/engine/engine.resolver.ts b/api/src/engine/engine.resolver.ts
index 36d51f1790edd8c4dbb2f1ce3acbec2289f4c278..ac8845c7e04e77ddb05f56cebf1b1e02ad316fdd 100644
--- a/api/src/engine/engine.resolver.ts
+++ b/api/src/engine/engine.resolver.ts
@@ -1,5 +1,6 @@
-import { Inject } from '@nestjs/common';
+import { Inject, UseGuards } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
+import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard';
import { Md5 } from 'ts-md5';
import { ENGINE_MODULE_OPTIONS, ENGINE_SERVICE } from './engine.constants';
import { IEngineOptions, IEngineService } from './engine.interfaces';
@@ -14,6 +15,7 @@ import { ExperimentCreateInput } from './models/experiment/input/experiment-crea
import { ExperimentEditInput } from './models/experiment/input/experiment-edit.input';
import { ListExperiments } from './models/experiment/list-experiments.model';
+@UseGuards(JwtAuthGuard)
@Resolver()
export class EngineResolver {
constructor(