From e975e7de9773ea3b3276a2aac1293903fedef687 Mon Sep 17 00:00:00 2001 From: Saad Jutt Date: Fri, 1 Oct 2021 12:03:44 +0500 Subject: [PATCH] test(RequestClient): specs for communicating with self-signed server --- package.json | 4 + src/request/RequestClient.ts | 7 +- src/test/RequestClient.spec.ts | 163 +++++++++++++++++++++++++++++++++ src/test/SAS_server_app.ts | 38 ++++++++ 4 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 src/test/RequestClient.spec.ts create mode 100644 src/test/SAS_server_app.ts diff --git a/package.json b/package.json index fcf32f6..4f1f120 100644 --- a/package.json +++ b/package.json @@ -41,17 +41,21 @@ "license": "ISC", "devDependencies": { "@types/axios": "^0.14.0", + "@types/express": "^4.17.13", "@types/form-data": "^2.5.0", "@types/jest": "^27.0.1", "@types/mime": "^2.0.3", + "@types/pem": "^1.9.6", "@types/tough-cookie": "^4.0.1", "copyfiles": "^2.4.1", "cp": "^0.2.0", "dotenv": "^10.0.0", + "express": "^4.17.1", "jest": "^27.2.0", "jest-extended": "^0.11.5", "node-polyfill-webpack-plugin": "^1.1.4", "path": "^0.12.7", + "pem": "^1.14.4", "process": "^0.11.10", "rimraf": "^3.0.2", "semantic-release": "^17.4.7", diff --git a/src/request/RequestClient.ts b/src/request/RequestClient.ts index f4a0f29..ba2d3ce 100644 --- a/src/request/RequestClient.ts +++ b/src/request/RequestClient.ts @@ -527,9 +527,12 @@ export class RequestClient implements HttpClient { ? { rejectUnauthorized: !allowInsecure } : undefined - if (httpsAgentConfig) { + if (httpsAgentConfig && https.Agent) { const httpsAgent = new https.Agent(httpsAgentConfig) - this.httpClient = axios.create({ httpsAgent }) + this.httpClient = axios.create({ + baseURL: baseUrl, + httpsAgent + }) } else { this.httpClient = axios.create({ baseURL: baseUrl diff --git a/src/test/RequestClient.spec.ts b/src/test/RequestClient.spec.ts new file mode 100644 index 0000000..b40c578 --- /dev/null +++ b/src/test/RequestClient.spec.ts @@ -0,0 +1,163 @@ +import * as pem from 'pem' +import * as http from 'http' +import * as https from 'https' +import { app, mockedAuthResponse } from './SAS_server_app' +import { ServerType } from '@sasjs/utils' +import SASjs from '../SASjs' + +const PORT = 8000 +const SERVER_URL = `https://localhost:${PORT}/` + +describe('RequestClient', () => { + let server: http.Server + + const adapter = new SASjs({ + serverUrl: `http://localhost:${PORT}/`, + serverType: ServerType.SasViya + }) + + beforeAll(async () => { + await new Promise((resolve: any, reject: any) => { + server = app + .listen(PORT, () => resolve()) + .on('error', (err: any) => reject(err)) + }) + }) + + afterAll(() => { + server.close() + }) + + it('should response the POST method', async () => { + const authResponse = await adapter.getAccessToken( + 'clientId', + 'clientSecret', + 'authCode' + ) + + expect(authResponse.access_token).toBe(mockedAuthResponse.access_token) + }) + + it('should response the POST method with Unauthorized', async () => { + await expect( + adapter.getAccessToken('clientId', 'clientSecret', 'incorrect') + ).rejects.toEqual( + new Error( + 'Error while getting access tokenRequest failed with status code 401' + ) + ) + }) +}) + +describe('RequestClient - Self Signed Server', () => { + let adapter: SASjs + + let httpsServer: https.Server + let sslConfig: pem.CertificateCreationResult + + beforeAll(async () => { + ;({ httpsServer, keys: sslConfig } = await setupSelfSignedServer()) + await new Promise((resolve: any, reject: any) => { + httpsServer + .listen(PORT, () => resolve()) + .on('error', (err: any) => reject(err)) + }) + + adapter = new SASjs({ + serverUrl: SERVER_URL, + serverType: ServerType.SasViya, + httpsAgentConfiguration: { + selfSigned: { ca: [sslConfig.certificate] } + } + }) + }) + + afterAll(() => { + httpsServer.close() + }) + + it('should throw error for not providing certificate', async () => { + const adapterWithoutCertificate = new SASjs({ + serverUrl: SERVER_URL, + serverType: ServerType.SasViya + }) + + await expect( + adapterWithoutCertificate.getAccessToken( + 'clientId', + 'clientSecret', + 'authCode' + ) + ).rejects.toEqual( + expect.objectContaining({ + message: 'Error while getting access tokenself signed certificate' + }) + ) + }) + + it('should response the POST method using insecure flag', async () => { + const adapterAllowInsecure = new SASjs({ + serverUrl: SERVER_URL, + serverType: ServerType.SasViya, + httpsAgentConfiguration: { + allowInsecure: true + } + }) + + const authResponse = await adapterAllowInsecure.getAccessToken( + 'clientId', + 'clientSecret', + 'authCode' + ) + + expect(authResponse.access_token).toBe(mockedAuthResponse.access_token) + }) + + it('should response the POST method', async () => { + const authResponse = await adapter.getAccessToken( + 'clientId', + 'clientSecret', + 'authCode' + ) + + expect(authResponse.access_token).toBe(mockedAuthResponse.access_token) + }) + + it('should response the POST method with Unauthorized', async () => { + await expect( + adapter.getAccessToken('clientId', 'clientSecret', 'incorrect') + ).rejects.toEqual( + new Error( + 'Error while getting access tokenRequest failed with status code 401' + ) + ) + }) +}) + +const setupSelfSignedServer = async (): Promise<{ + httpsServer: https.Server + keys: pem.CertificateCreationResult +}> => { + return await new Promise(async (resolve) => { + const keys = await createCertificate() + + const httpsServer = https.createServer( + { key: keys.clientKey, cert: keys.certificate }, + app + ) + + resolve({ httpsServer, keys }) + }) +} + +const createCertificate = async (): Promise => { + return await new Promise((resolve, reject) => { + pem.createCertificate( + { days: 1, selfSigned: true }, + (error: any, keys: pem.CertificateCreationResult) => { + if (error) reject(false) + resolve(keys) + } + ) + }) +} diff --git a/src/test/SAS_server_app.ts b/src/test/SAS_server_app.ts new file mode 100644 index 0000000..e4cff7a --- /dev/null +++ b/src/test/SAS_server_app.ts @@ -0,0 +1,38 @@ +import express = require('express') + +export const app = express() + +export const mockedAuthResponse = { + access_token: 'access_token', + token_type: 'bearer', + id_token: 'id_token', + refresh_token: 'refresh_token', + expires_in: 43199, + scope: 'openid', + jti: 'jti' +} + +app.get('/', function (req: any, res: any) { + res.send('Hello World') +}) + +app.post('/SASLogon/oauth/token', function (req: any, res: any) { + let valid = true + // capture the encoded form data + req.on('data', (data: any) => { + const resData = data.toString() + + if (resData.includes('incorrect')) valid = false + }) + + // send a response when finished reading + // the encoded form data + req.on('end', () => { + if (valid) res.status(200).send(mockedAuthResponse) + else + res.status(401).send({ + error: 'unauthorized', + error_description: 'Bad credentials' + }) + }) +})