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

Improvement/vltclt 37 remove arsenal dep #431

Merged
merged 5 commits into from
Jan 24, 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
7 changes: 5 additions & 2 deletions lib/IAMClient.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/// <reference types="arsenal/node_modules/werelogs" />
export = VaultClient;
declare class VaultClient {
/**
Expand Down Expand Up @@ -32,6 +31,9 @@ declare class VaultClient {
log: any;
_path: string;
useAuthenticatedAdminRoutes: boolean;
setCustomEndpointForSignature(host: any, path: any): void;
_host: any;
__path: any;
enableIAMOnAdminRoutes(): VaultClient;
/**
* Set the configuration for the werelogs logger
Expand Down Expand Up @@ -313,7 +315,7 @@ declare class VaultClient {
/**
* Get policy evaluation (without authentication first)
* @param {Object} requestContextParams - parameters needed to construct
* requestContext in Vault, can be an array of request contexts
* requestContext in Vault
* @param {Object} requestContextParams.constantParams -
* params that have the
* same value for each requestContext to be constructed in Vault
Expand Down Expand Up @@ -348,6 +350,7 @@ declare class VaultClient {
logger?: werelogs.RequestLogger;
}, callback: Function): undefined;
healthcheck(reqUid: any, callback: any): void;
_signRequest(iamAuthenticate: any, req: any, options: any, path: any): Promise<void>;
/**
* @param {string} method - CRUD method chosen for the request
* @param {string} path - RESTful URL for the request
Expand Down
2 changes: 1 addition & 1 deletion lib/IAMClient.d.ts.map

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

96 changes: 69 additions & 27 deletions lib/IAMClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
/* eslint-disable no-underscore-dangle */
'use strict'; // eslint-disable-line

const { auth, errors, constants } = require('arsenal');
const { SignatureV4 } = require('@smithy/signature-v4');
const { Sha256 } = require('@aws-crypto/sha256-universal');
const assert = require('assert');
const werelogs = require('werelogs');
const http = require('http');
const https = require('https');
const { parseString } = require('xml2js');
const queryString = require('querystring');
const { http: HttpAgent, https: HttpsAgent } = require('httpagent');
const { httpClientFreeSocketTimeout, InternalError } = require('./constants');

const regexAccountId = /^[0-9]{12}$/;
const regexCanonicalId = /^[A-Za-z0-9]{64}$/;
Expand Down Expand Up @@ -59,12 +61,12 @@ class VaultClient {
keepAlive: true,
requestCert: true,
rejectUnauthorized: !(ignoreCa === true),
freeSocketTimeout: constants.httpClientFreeSocketTimeout,
freeSocketTimeout: httpClientFreeSocketTimeout,
});
} else {
this._agent = new HttpAgent.Agent({
keepAlive: true,
freeSocketTimeout: constants.httpClientFreeSocketTimeout,
freeSocketTimeout: httpClientFreeSocketTimeout,
});
}
this.accessKey = accessKey;
Expand All @@ -76,6 +78,11 @@ class VaultClient {
this.useAuthenticatedAdminRoutes = false;
}

setCustomEndpointForSignature(host, path) {
this._host = host;
this.__path = path;
}

enableIAMOnAdminRoutes() {
this.useAuthenticatedAdminRoutes = true;
return this;
Expand Down Expand Up @@ -920,7 +927,7 @@ class VaultClient {
/**
* Get policy evaluation (without authentication first)
* @param {Object} requestContextParams - parameters needed to construct
* requestContext in Vault, can be an array of request contexts
* requestContext in Vault
* @param {Object} requestContextParams.constantParams -
* params that have the
* same value for each requestContext to be constructed in Vault
Expand Down Expand Up @@ -1002,6 +1009,42 @@ class VaultClient {
reqUid, null);
}

/* eslint-disable no-param-reassign */
async _signRequest(iamAuthenticate, req, options, path) {
if (iamAuthenticate) {
options.headers = {
Host: this._host || options.host,
};
if (this._host && this.__path) {
options.path = this.__path;
options.host = this._host;
}
const signer = new SignatureV4({
credentials: {
accessKeyId: this.accessKey,
secretAccessKey: this.secretKeyValue,
sessionToken: this.sessionToken,
},
region: 'us-east-1',
service: 'iam',
sha256: Sha256,
host: this._host ? this._host : options.host,
});
const signedReq = await signer.sign(options);
Object.keys(signedReq.headers).forEach(key => {
req.setHeader(key, signedReq.headers[key]);
});
if (this._host && this.__path) {
req._headers.host = {
name: 'host',
value: options.host,
};
options.path = this._path || path;
}
}
}
/* eslint-enable no-param-reassign */

/**
* @param {string} method - CRUD method chosen for the request
* @param {string} path - RESTful URL for the request
Expand Down Expand Up @@ -1045,37 +1088,22 @@ class VaultClient {
}
const req = this.useHttps
? https.request(options) : http.request(options);
if (iamAuthenticate) {
auth.client.generateV4Headers(req, data,
this.accessKey, this.secretKeyValue, 'iam', path,
this.sessionToken);
}
if (method === 'POST') {
if (contentType === 'application/json') {
req.setHeader('Content-Type', contentType);
req.write(JSON.stringify(data));
} else {
req.write(queryString.stringify(data));
}
}

// request events
req.on('response', res => {
// response events
res.on('data', receivedData => {
ret += receivedData.toString();
})

.on('error', err => {
log.debug('error receiving data', {
component: 'vaultclient',
method: 'VaultClient:request()',
error: err.message,
errorStack: err.stack,
});
return callback(errors.InternalError);
return callback(InternalError);
})

.on('end', () => {
this.handleResponse(res, ret, log, callback);
});
Expand All @@ -1087,9 +1115,22 @@ class VaultClient {
error: err.message,
errorStack: err.stack,
});
return callback(errors.InternalError);
return callback(InternalError);
});
req.end();

this._signRequest(iamAuthenticate, req, options, path)
.catch(() => callback(InternalError))
.then(() => {
if (method === 'POST') {
if (contentType === 'application/json') {
req.setHeader('Content-Type', contentType);
req.write(JSON.stringify(data));
} else {
req.write(queryString.stringify(data));
}
}
req.end();
});
}

/**
Expand Down Expand Up @@ -1163,21 +1204,22 @@ class VaultClient {
error: obj,
method: 'VaultClient.handleResponse',
});
return cb(
errors[obj.ErrorResponse.Error.Code],
return cb({
code: obj.ErrorResponse.Error.Code,
description: obj.ErrorResponse.Error.Message,
},
null,
res.statusCode
);
}
if (obj && obj.InternalError) {
return cb(errors.InternalError, null, res.statusCode);
return cb(InternalError, null, res.statusCode);
}
log.error('unable to translate error from vault', {
error: obj,
method: 'VaultClient.handleResponse',
});
return cb(errors.InternalError
.customizeDescription('unable to translate error from vault'));
return cb(InternalError);
});
}
}
Expand Down
6 changes: 6 additions & 0 deletions lib/constants.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const httpClientFreeSocketTimeout: 55000;
export namespace InternalError {
const code: number;
const description: string;
}
//# sourceMappingURL=constants.d.ts.map
1 change: 1 addition & 0 deletions lib/constants.d.ts.map

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

11 changes: 11 additions & 0 deletions lib/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const httpClientFreeSocketTimeout = 55000;

const InternalError = {
code: 500,
description: 'We encountered an internal error. Please try again.',
};

module.exports = {
httpClientFreeSocketTimeout,
InternalError,
};
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"engines": {
"node": ">=16"
},
"version": "8.3.17",
"version": "8.3.18",
"description": "Client library and binary for Vault, the user directory and key management service",
"main": "index.js",
"repository": "scality/vaultclient",
Expand All @@ -14,13 +14,15 @@
},
"homepage": "https://github.com/scality/vaultclient#readme",
"dependencies": {
"arsenal": "git+https://github.com/scality/Arsenal#8.1.91",
"@aws-crypto/sha256-universal": "^2.0.1",
"@smithy/signature-v4": "^2.1.1",
"commander": "2.20.0",
"httpagent": "git+https://github.com/scality/httpagent#1.0.6",
"werelogs": "scality/werelogs#8.1.3",
"xml2js": "0.4.19"
},
"devDependencies": {
"arsenal": "git+https://github.com/scality/Arsenal#8.1.91",
"babel-eslint": "10.0.2",
"eslint": "6.8.0",
"eslint-config-airbnb": "17.1.0",
Expand All @@ -35,6 +37,6 @@
"lint_yml": "yamllint $(git ls-files '*.yml')",
"lint_md": "mdlint $(git ls-files '*.md')",
"test": "mocha --exit tests/unit",
"gen-types": "rm -f lib/IAMClient.d.ts && tsc --declaration --emitDeclarationOnly"
"gen-types": "rm -f lib/IAMClient.d.ts && rm -f lib/constants.d.ts && tsc --declaration --emitDeclarationOnly"
}
}
5 changes: 2 additions & 3 deletions tests/unit/handleResponse.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
'use strict'; // eslint-disable-line
// const http = require('http');
const assert = require('assert');
const { errors } = require('arsenal');
const IAMClient = require('../../lib/IAMClient');
const { InternalError } = require('arsenal/build/lib/errors/arsenalErrors');

const log = { error() {} };
const res = { statusCode: 400 };
const ret = '<Response><Code>foo</Code></Response>';
const expErr = errors.InternalError
.customizeDescription('unable to translate error from vault');
const expErr = InternalError;

describe('handling unrecognized error syntax', () => {
let client;
Expand Down
15 changes: 11 additions & 4 deletions tests/unit/httpsTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ const httpPort = 8500;
const httpsPort = 8600;
const httpsPortTwoWay = 8601;

const defaultAccessKey = 'D4IT2AWSB588GO5J9T00';
const defaultSecretKey = 'UEEu8tYlsOGGrgf4DAiSZD6apVNPUWqRiPG0nTB6';

const accountName = 'account_name';
const accountOptions = { email: '[email protected]', password: 'pwd' };

Expand All @@ -39,14 +42,18 @@ const testNames = [
];

const testClients = [
new IAMClient('localhost', httpPort),
new IAMClient('localhost', httpPort, false),
new IAMClient('localhost', httpPort, undefined, undefined, undefined, undefined, undefined,
defaultAccessKey, defaultSecretKey),
new IAMClient('localhost', httpPort, false, undefined, undefined, undefined, undefined,
defaultAccessKey, defaultSecretKey),
new IAMClient('vault.testing.local', httpsPort, true, undefined, undefined,
fs.readFileSync('tests/utils/ca.crt', 'ascii')),
fs.readFileSync('tests/utils/ca.crt', 'ascii'), undefined,
defaultAccessKey, defaultSecretKey),
new IAMClient('vault.testing.local', httpsPortTwoWay, true,
fs.readFileSync('tests/utils/test.key', 'ascii'),
fs.readFileSync('tests/utils/test.crt', 'ascii'),
fs.readFileSync('tests/utils/ca.crt', 'ascii')),
fs.readFileSync('tests/utils/ca.crt', 'ascii'),
undefined, defaultAccessKey, defaultSecretKey),
];

function extractPost(req, cb) {
Expand Down
3 changes: 2 additions & 1 deletion tests/unit/v2authTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ describe('v2 auth tests with mockup server', () => {
accessKeys[testIndex],
{ algo: hashAlgorithms[testIndex] },
(err, response) => {
assert.deepStrictEqual(err, expectedErrors[testIndex]);
assert.deepStrictEqual(err ? err.code : undefined,
expectedErrors[testIndex] ? expectedErrors[testIndex].type : undefined);
assert.deepStrictEqual(response
? response.message.body : response,
expectedResponseBodies[testIndex]);
Expand Down
Loading
Loading