Commit 4d6664af authored by Sébastien DA ROCHA's avatar Sébastien DA ROCHA
Browse files

OIDC passer par apis.grandlyon.fr + utilise le access_token dand un header

parent f9ca2065
Pipeline #13723 passed with stage
in 4 seconds
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
plugins: [
'@typescript-eslint',
],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
],
};
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
[packages]
[requires]
python_version = "3.7"
{
"_meta": {
"hash": {
"sha256": "7e7ef69da7248742e869378f8421880cf8f0017f96d94d086813baa518a65489"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.7"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {},
"develop": {}
}
......@@ -9,6 +9,7 @@ export class ConfigService {
constructor() {
dotenv.config();
this._config.legacyAuthServiceUrl = process.env.LEGACY_AUTH_SERVICE_URL;
this._config.legacyAuthOidcUrl = process.env.LEGACY_AUTH_OIDC_URL;
this._config.adminPassword = process.env.ADMIN_PASSWORD;
this._config.adminUsername = process.env.ADMIN_USERNAME;
this._config.serviceEmailUrl = process.env.SERVICE_EMAIL_URL;
......@@ -68,4 +69,4 @@ export class ConfigService {
throw new InternalServerErrorException('Failed to initialize Public/Private keys');
}
}
}
\ No newline at end of file
}
export const Config = {
legacyAuthServiceUrl: '',
legacyAuthOidcUrl: '',
adminUsername: '',
adminPassword: '',
serviceEmailUrl: '',
......@@ -21,4 +22,4 @@ export const Config = {
imageHost: '',
apiKey: '',
accessTokenCookieKey: '',
};
\ No newline at end of file
};
......@@ -96,7 +96,7 @@ export class LegacyController {
@HttpCode(201)
async createOidcAccount(@Req() req) {
try {
return await this.legacyServiceOidc.createAccount(req.headers.token);
return await this.legacyServiceOidc.createAccount(req.headers['apis_access_token']);
} catch (error) {
if (error instanceof HttpException) {
throw error;
......@@ -266,9 +266,9 @@ export class LegacyController {
try {
let userServices;
if (token.authzKey == null) { // is OIDC token
userServices = await this.legacyServiceOidc.getUserResources(token.email);
userServices = await this.legacyServiceOidc.getUserResources(token, req.headers['apis_access_token']);
} else {
userServices = await this.legacyService.getUserResources(token.username, token.authzKey);
userServices = await this.legacyService.getUserResources(token);
}
return userServices;
} catch (error) {
......
......@@ -105,16 +105,6 @@ export class UserInfo {
}
}
export class OIDCCreateForm {
@ApiModelProperty()
@IsString()
username: string;
@ApiModelProperty()
@IsString()
email?: string;
}
export class UserInfoWithEcryptedPassword {
@ApiModelProperty()
@IsString()
......
import {
Injectable, Logger, HttpException, BadRequestException, HttpStatus,
Injectable, HttpException, BadRequestException, HttpStatus,
InternalServerErrorException, UnauthorizedException,
} from '@nestjs/common';
import {
LoginForm, UserInfoWithEcryptedPassword, UserCreationForm, Service, JWTToken, Resource, RestrictedAccessDataset,
AccessRequest, UpdatePasswordForm, UserUpdateForm, UserInfo, LegacyUserUpdateForm, LegacyUserCreationForm,
AccessDeletionResponse, AccessRequestResponse, AccessRenewalResponse, PasswordResetForm, PasswordForgottenForm, Email,
OIDCCreateForm,
} from './legacy.model';
import * as request from 'request-promise-native';
import { ConfigService } from '../configuration/config.service';
......@@ -30,25 +29,33 @@ export class LegacyServiceOIDC extends LegacyService {
try {
const userInfo = {username: token.id, email: token.email} as OIDCCreateForm;
if(token) {
let options = {
method: 'POST',
headers:{
'Authorization': 'Bearer ' + token,
},
url: `${this.conf.legacyAuthOidcUrl}/add_user/`,
};
if (userInfo) {
Logger.log(`User account validation for : ${userInfo.email}`, `${LegacyServiceOIDC.name} - ${this.createAccount.name}`);
let token_data = jwt.decode(token);
// Get the list of the accessible services by the user
this.logger.log(`OIDC user account validation for : ${token_data['http://wso2.org/claims/emailaddress']}`, `${LegacyServiceOIDC.name} - ${this.createAccount.name}`);
let res = await request.post(`${this.conf.legacyAuthServiceUrl}/add_user_oidc/`).form(userInfo).catch((error) => {
let res = await request.post(options).catch((error) => {
const inres = JSON.parse(error.error);
// Normal use case
if (inres.message === 'Account already exists') {
return;
}
this.logger.error('Couldn\'t create user.', `${error}`, `${LegacyServiceOIDC.name} - ${this.createAccount.name}`);
this.logger.error(`Couldn\'t create user (socle answer): ${error}`, `${LegacyServiceOIDC.name} - ${this.createAccount.name}`);
throw new InternalServerErrorException({ error, message: 'Couldn\'t create user.' });
});
res = JSON.parse(res);
if (res.server_response && res.server_response === 'Success') {
Logger.log(`User account created.`, `${LegacyServiceOIDC.name} - ${this.createAccount.name}`);
this.logger.log(`User account created.`, `${LegacyServiceOIDC.name} - ${this.createAccount.name}`);
return;
} else {
// Normal use case
......@@ -56,7 +63,7 @@ export class LegacyServiceOIDC extends LegacyService {
return;
}
this.logger.error('Couldn\'t create user.', `${res}`, `${LegacyServiceOIDC.name} - ${this.createAccount.name}`);
this.logger.error(`Couldn\'t create user : ${res}`, `${LegacyServiceOIDC.name} - ${this.createAccount.name}`);
if (res.message === 'Error during account creation') {
throw new InternalServerErrorException(res.message);
}
......@@ -75,15 +82,24 @@ export class LegacyServiceOIDC extends LegacyService {
}
}
async getUserResources(username: string): Promise<Resource[]> {
async getUserResources(token: JWTToken, access_token: string=""): Promise<Resource[]> {
const username = token.username;
this.logger.log('Entering function', `${LegacyServiceOIDC.name} - ${this.getUserResources.name}`);
try {
let options = {
//method: 'POST',
headers:{
'Authorization': 'Bearer ' + access_token,
},
url: `${this.conf.legacyAuthOidcUrl}/get_user_service/`,
};
// Get the list of the accessible services by the user
let res = await request.post(`${this.conf.legacyAuthServiceUrl}/get_user_service_oidc/`).form({ username}).catch((error) => {
this.logger.error('Couldn\'t get the user`\'s services list.', `${error}`, `${LegacyServiceOIDC.name} - ${this.getUserResources.name}`);
throw new InternalServerErrorException({ error, message: 'Couldn\'t get the user`\'s services list.' });
});
let res = await request(options)
.catch((error) => {
this.logger.error('Couldn\'t get the user`\'s services list.', `${error}`, `${LegacyServiceOIDC.name} - ${this.getUserResources.name}`);
throw new InternalServerErrorException({ error, message: 'Couldn\'t get the user`\'s services list.' });
});
res = JSON.parse(res);
......@@ -105,43 +121,7 @@ export class LegacyServiceOIDC extends LegacyService {
if (err instanceof HttpException) {
throw new HttpException(err.message, err.getStatus());
} else {
throw new InternalServerErrorException('Something went wrong.');
}
}
}
async getRestrictedAccessDatasets(): Promise<RestrictedAccessDataset[]> {
this.logger.log('Entering function', `${LegacyServiceOIDC.name} - ${this.getRestrictedAccessDatasets.name}`);
try {
let rawRestrictedService = await request.get(`${this.conf.legacyAuthServiceUrl}/get_services/`).catch((error) => {
this.logger.error('Couldn\'t get the services list.', `${error}`, `${LegacyServiceOIDC.name} - ${this.getRestrictedAccessDatasets.name}`);
throw new InternalServerErrorException({ error, message: 'Couldn\'t get the services list.' });
});
rawRestrictedService = JSON.parse(rawRestrictedService);
const restrictedServices = [];
if (rawRestrictedService.services) {
rawRestrictedService = rawRestrictedService.services.filter(service => service.visible === 'RESTRICTED');
rawRestrictedService.forEach((service) => {
restrictedServices.push(new RestrictedAccessDataset(service));
});
return restrictedServices;
} else {
this.logger.error(
'Couldn\'t get the different restricted services.',
`${rawRestrictedService}`,
`${LegacyServiceOIDC.name} - ${this.getRestrictedAccessDatasets.name}`,
);
throw new InternalServerErrorException('Couldn\'t get the different restricted services.');
}
} catch (err) {
if (err instanceof HttpException) {
throw new HttpException(err.message, err.getStatus());
} else {
throw new InternalServerErrorException('Something went wrong.');
throw new InternalServerErrorException('Something went wrong.' + err);
}
}
}
......@@ -161,14 +141,15 @@ export class LegacyServiceOIDC extends LegacyService {
for (const accessRequest of accessRequests) {
// Request access the the specified service and the specified modes
let res = await request.post(`${this.conf.legacyAuthServiceUrl}/add_user_service_oidc/`).form(
this.logger.log('got data', `${LegacyServiceOIDC.name} - ${this.renewUserResource.name}`);
let res = await request.post(`${this.conf.legacyAuthOidcUrl}/add_user_service/`).form(
{
username: token.email,
service_id: accessRequest.id,
modes: accessRequest.servicesId.toString(),
},
).catch((error) => {
this.logger.error('Couldn\'t request access to the resource.', `${error}`, `${LegacyServiceOIDC.name} - ${this.addUserResource.name}`);
this.logger.error(`Couldn\'t request access to the resource :${error}`, `${LegacyServiceOIDC.name} - ${this.addUserResource.name}`);
throw new InternalServerErrorException({ error, message: 'Couldn\'t request access to the resource.' });
});
......@@ -245,7 +226,7 @@ export class LegacyServiceOIDC extends LegacyService {
this.logger.log('Entering function', `${LegacyServiceOIDC.name} - ${this.renewUserResource.name}`);
try {
// Get the list of user access
const userAccess = await this.getUserResources(token.email);
const userAccess = await this.getUserResources(token);
// Get the list of datasets
const datasets = await this.getRestrictedAccessDatasets();
// Get the list of services
......@@ -351,7 +332,7 @@ export class LegacyServiceOIDC extends LegacyService {
for (const accessRequest of accessRequests) {
// Delete access to the specified service and the specified modes
let res = await request.post(`${this.conf.legacyAuthServiceUrl}/del_user_service_oidc/`).form(
let res = await request.post(`${this.conf.legacyAuthOidcUrl}/del_user_service_oidc/`).form(
{
username: token.email,
service_id: accessRequest.id,
......@@ -383,7 +364,7 @@ export class LegacyServiceOIDC extends LegacyService {
datasetsSuccessfullyDeleted.push(`${dataset.datasetName} (${servicesName.toString()})`);
}
} else {
Logger.error(` [x] Error: ${res.message}`);
this.logger.error(` [x] Error: ${res.message}`);
datasetsUnsuccessfullyDeleted.push(`${dataset.datasetName} (${servicesName.toString()})`);
}
}
......
......@@ -385,7 +385,9 @@ export class LegacyService {
}
}
async getUserResources(username: string, password: string): Promise<Resource[]> {
async getUserResources(token: JWTToken): Promise<Resource[]> {
const username = token.username;
let password = token.authzKey;
this.logger.log('Entering function', `${LegacyService.name} - ${this.getUserResources.name}`);
try {
// Decrypt the password
......@@ -428,9 +430,11 @@ export class LegacyService {
async getRestrictedAccessDatasets(): Promise<RestrictedAccessDataset[]> {
this.logger.log('Entering function', `${LegacyService.name} - ${this.getRestrictedAccessDatasets.name}`);
const legacyUrl = `${this.conf.legacyAuthServiceUrl}/get_services/`;
try {
let rawRestrictedService = await request.get(`${this.conf.legacyAuthServiceUrl}/get_services/`).catch((error) => {
this.logger.error('Couldn\'t get the services list.', `${error}`, `${LegacyService.name} - ${this.getRestrictedAccessDatasets.name}`);
this.logger.log('Requesting URL ' + legacyUrl, `${LegacyService.name} - ${this.getRestrictedAccessDatasets.name}`);
let rawRestrictedService = await request.get(legacyUrl).catch((error) => {
this.logger.error(`Couldn\'t get the services list : ${error}`, `${LegacyService.name} - ${this.getRestrictedAccessDatasets.name}`);
throw new InternalServerErrorException({ error, message: 'Couldn\'t get the services list.' });
});
......@@ -576,7 +580,7 @@ export class LegacyService {
}
// Get the list of user access
const userAccess = await this.getUserResources(token.username, token.authzKey);
const userAccess = await this.getUserResources(token);
// Get the list of datasets
const datasets = await this.getRestrictedAccessDatasets();
// Get the list of services
......
TAG=<version/tag of the docker image to be deployed>
MIDDLEWARE_LEGACY_SERVICE_BIND_PORT=<port on which the service will be running>
LEGACY_AUTH_SERVICE_URL=<root url of the legacy auth service>
LEGACY_AUTH_OIDC_URL=<root url of the legacy auth service through GL API Manager>
ADMIN_PASSWORD=<legacy auth service admin password>
ADMIN_USERNAME=<legacy auth service admin username>
SERVICE_EMAIL_URL=<the email service URL>
......@@ -18,4 +19,4 @@ REDIS_GROUP_NAME=<name of the group of the different sentinels>
ALLOW_EMPTY_PASSWORD=<whether empty password is accepted or not for a redis instance ex: 'yes'>
REDIS_MASTER_PORT=<port of the redis master>
REDIS_MASTER_HOST=<host of the redis master>
REDIS_SLAVE_PORT=<port of the redis slave>
\ No newline at end of file
REDIS_SLAVE_PORT=<port of the redis slave>
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
[packages]
pytest = "*"
requests = "*"
config = "*"
python-decouple = "*"
pyjwt = "*"
[requires]
python_version = "3.7"
{
"_meta": {
"hash": {
"sha256": "7558fd0f4c1afd71486dbc6f357b245b60c51edb176dc75d4f5013aae57ba783"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.7"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"attrs": {
"hashes": [
"sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6",
"sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==20.3.0"
},
"certifi": {
"hashes": [
"sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c",
"sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"
],
"version": "==2020.12.5"
},
"chardet": {
"hashes": [
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==4.0.0"
},
"config": {
"hashes": [
"sha256:73ea4a8064facc61fcba736be71996aaa7f38a564166a284628b8e8c53444f2e",
"sha256:c7e48f9820758a4ddc23ae3bf10b118959f6fd06018be9eb0e1d9d5a3b227de1"
],
"index": "pypi",
"version": "==0.5.0.post0"
},
"idna": {
"hashes": [
"sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
"sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.10"
},
"importlib-metadata": {
"hashes": [
"sha256:8c501196e49fb9df5df43833bdb1e4328f64847763ec8a50703148b73784d581",
"sha256:d7eb1dea6d6a6086f8be21784cc9e3bcfa55872b52309bc5fad53a8ea444465d"
],
"markers": "python_version < '3.8'",
"version": "==4.0.1"
},
"iniconfig": {
"hashes": [
"sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3",
"sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"
],
"version": "==1.1.1"
},
"packaging": {
"hashes": [
"sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5",
"sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==20.9"
},
"pluggy": {
"hashes": [
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.13.1"
},
"py": {
"hashes": [
"sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3",
"sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.10.0"
},
"pyjwt": {
"hashes": [
"sha256:a5c70a06e1f33d81ef25eecd50d50bd30e34de1ca8b2b9fa3fe0daaabcf69bf7",
"sha256:b70b15f89dc69b993d8a8d32c299032d5355c82f9b5b7e851d1a6d706dffe847"
],
"index": "pypi",
"version": "==2.0.1"
},
"pyparsing": {
"hashes": [
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.4.7"
},
"pytest": {
"hashes": [
"sha256:671238a46e4df0f3498d1c3270e5deb9b32d25134c99b7d75370a68cfbe9b634",
"sha256:6ad9c7bdf517a808242b998ac20063c41532a570d088d77eec1ee12b0b5574bc"
],
"index": "pypi",
"version": "==6.2.3"
},
"python-decouple": {
"hashes": [
"sha256:2e5adb0263a4f963b58d7407c4760a2465d464ee212d733e2a2c179e54c08d8f",
"sha256:a8268466e6389a639a20deab9d880faee186eb1eb6a05e54375bdf158d691981"
],
"index": "pypi",
"version": "==3.4"
},
"requests": {
"hashes": [
"sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
"sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
],
"index": "pypi",
"version": "==2.25.1"
},
"toml": {
"hashes": [
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.10.2"
},
"typing-extensions": {
"hashes": [
"sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918",
"sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c",
"sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"
],
"markers": "python_version < '3.8'",
"version": "==3.7.4.3"
},
"urllib3": {
"hashes": [
"sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df",
"sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
"version": "==1.26.4"
},
"zipp": {
"hashes": [
"sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76",
"sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"
],
"markers": "python_version >= '3.6'",
"version": "==3.4.1"
}
},
"develop": {}
}
import requests
from decouple import config
import jwt
TOKEN = ""
PORT = config("PORT", 3000)
ACCESS_TOKEN_COOKIE_KEY = config("ACCESS_TOKEN_COOKIE_KEY")
BASE_URL = f"http://localhost:{PORT}"
def test_user_createOidcAccount():
endpoint = "user/createOidcAccount"
encoded_jwt = jwt.encode(
{
"some": "payload",
"xsrfToken": "x-xsrf-token_secret",
},
"secret",
algorithm="HS256",
)
cookies = {ACCESS_TOKEN_COOKIE_KEY: encoded_jwt}
headers = {
"x-anonymous-consumer": "false",
"x-xsrf-token": "x-xsrf-token_secret",
"apis_access_token": TOKEN,
}
resp = requests.post(
f"{BASE_URL}/{endpoint}",
#json=data_input,
#data = form,
cookies=cookies,
headers=headers,
#files=files
)
resp.raise_for_status()
resp_json = resp.json()
def test_user_resources():
endpoint = "user/resources"
encoded_jwt = jwt.encode(
{
"some": "payload",
"xsrfToken": "x-xsrf-token_secret",
},
"secret",
algorithm="HS256",
)