Skip to content

Commit

Permalink
feat: supports https proxy for Okta http client
Browse files Browse the repository at this point in the history
OKTA-419414
<<<Jenkins Check-In of Tested SHA: 170db51 for eng_productivity_ci_bot_okta@okta.com>>>
Artifact: okta-sdk-nodejs
Files changed count: 9
PR Link: "#307"
  • Loading branch information
denys.oblohin authored and eng-prod-CI-bot-okta committed Feb 28, 2022
1 parent 8715eb1 commit 96a735d
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 2 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Okta Node SDK Changelog

## 6.4.0

### Features

- [#307](https://github.com/okta/okta-sdk-nodejs/pull/307) Supports HTTPS proxy for Okta http client

## 6.3.1

### Bug Fixes
Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,23 @@ const client = new okta.Client({
})
```

## Proxy

If you need to use a proxy, you can configure it with `httpsProxy` property.
```javascript
const okta = require('@okta/okta-sdk-nodejs');

const client = new okta.Client({
orgUrl: 'https://dev-1234.oktapreview.com/',
token: 'xYzabc', // Obtained from Developer Dashboard
httpsProxy: 'http://proxy.example.net:8080/'
});
```

When the proxy configuration is not overridden as shown above, Okta client relies on the proxy configuration defined by standard environment variable `https_proxy` or its uppercase variant `HTTPS_PROXY`.

To use HTTP Basic Auth with your proxy, use the `http://user:password@host/` syntax.

## TypeScript usage

### 4.5.x
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"dependencies": {
"deep-copy": "^1.4.2",
"form-data": "^4.0.0",
"https-proxy-agent": "^5.0.0",
"isomorphic-fetch": "^3.0.0",
"js-yaml": "^4.1.0",
"lodash": "^4.17.20",
Expand All @@ -42,6 +43,7 @@
"safe-flat": "^2.0.2"
},
"devDependencies": {
"@faker-js/faker": "^5.5.3",
"@okta/openapi": "^2.10.0",
"@types/chai": "^4.2.22",
"@types/mocha": "^9.0.0",
Expand All @@ -53,7 +55,6 @@
"eslint": "^8.2.0",
"eslint-plugin-jest": "^25.2.4",
"fake-fs": "^0.5.0",
"@faker-js/faker": "^5.5.3",
"globby": "^11.0.4",
"ink-docstrap": "^1.3.2",
"jest": "^27.3.1",
Expand Down Expand Up @@ -86,4 +87,4 @@
"tsd": {
"directory": "test/type"
}
}
}
1 change: 1 addition & 0 deletions src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class Client extends GeneratedApiClient {
}

this.http = new Http({
httpsProxy: clientConfig.httpsProxy,
cacheStore: clientConfig.cacheStore,
cacheMiddleware: clientConfig.cacheMiddleware,
defaultCacheMiddlewareResponseBufferSize: clientConfig.defaultCacheMiddlewareResponseBufferSize,
Expand Down
8 changes: 8 additions & 0 deletions src/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const OktaApiError = require('./api-error');
const HttpError = require('./http-error');
const MemoryStore = require('./memory-store');
const defaultCacheMiddleware = require('./default-cache-middleware');
const HttpsProxyAgent = require('https-proxy-agent');

/**
* It's like fetch :) plus some extra convenience methods.
Expand Down Expand Up @@ -55,6 +56,10 @@ class Http {
this.defaultCacheMiddlewareResponseBufferSize = httpConfig.defaultCacheMiddlewareResponseBufferSize;
}
this.oauth = httpConfig.oauth;
const proxy = httpConfig.httpsProxy || process.env.https_proxy || process.env.HTTPS_PROXY;
if (proxy) {
this.agent = new HttpsProxyAgent(proxy);
}
}

prepareRequest(request) {
Expand All @@ -74,6 +79,9 @@ class Http {
request.url = uri;
request.headers = Object.assign({}, this.defaultHeaders, request.headers);
request.method = request.method || 'get';
if (this.agent) {
request.agent = this.agent;
}

let retriedOnAuthError = false;
const execute = () => {
Expand Down
1 change: 1 addition & 0 deletions src/types/client.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export declare class Client extends ParameterizedOperationsClient {
cacheStore?: CacheStorage,
cacheMiddleware?: typeof defaultCacheMiddleware | unknown
defaultCacheMiddlewareResponseBufferSize?: number,
httpsProxy?: string | unknown, // https://github.com/TooTallNate/node-agent-base/issues/56
});

requestExecutor: RequestExecutor;
Expand Down
2 changes: 2 additions & 0 deletions src/types/http.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ export declare class Http {
oauth: OAuth,
cacheStore?: CacheStorage,
cacheMiddleware?: typeof defaultCacheMiddleware | unknown,
httpsProxy?: string | unknown, // https://github.com/TooTallNate/node-agent-base/issues/56
});
defaultHeaders: Record<string, unknown>;
requestExecutor: RequestExecutor;
cacheStore: CacheStorage;
cacheMiddleware: typeof defaultCacheMiddleware | unknown;
agent: any; // https://github.com/TooTallNate/node-agent-base/issues/56
oauth: OAuth;
prepareRequest(request: RequestOptions): Promise<RequestOptions>;
http(uri: string, request?: RequestOptions, context?: {
Expand Down
1 change: 1 addition & 0 deletions src/types/request-options.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ import { RequestInit } from 'node-fetch';
export interface RequestOptions extends RequestInit {
startTime?: Date,
url?: string,
agent?: any, // https://github.com/TooTallNate/node-agent-base/issues/56
}
53 changes: 53 additions & 0 deletions test/jest/http.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,19 @@ const MemoryStore = require('../../src/memory-store');
const defaultCacheMiddleware = require('../../src/default-cache-middleware');
const OktaApiError = require('../../src/api-error');
const HttpError = require('../../src/http-error');
const HttpsProxyAgent = require('https-proxy-agent');

describe('Http class', () => {
describe('constructor', () => {
const OLD_ENV = process.env;
beforeEach(() => {
jest.resetModules();
process.env = { ...OLD_ENV };
});
afterAll(() => {
process.env = OLD_ENV;
});

it('creates empty defaultHeaders object', () => {
const http = new Http({});
expect(http.defaultHeaders).toEqual({});
Expand Down Expand Up @@ -39,6 +49,30 @@ describe('Http class', () => {
const http = new Http({ oauth });
expect(http.oauth).toBe(oauth);
});
it('accepts a "httpsProxy"', () => {
const http = new Http({ httpsProxy: 'http://proxy.example.net:8080/' });
expect(http.agent).toBeInstanceOf(HttpsProxyAgent);
expect(http.agent.proxy.host).toBe('proxy.example.net');
});
it('uses a "https_proxy" env var', () => {
process.env.https_proxy = 'http://proxy.example.net:8080/';
const http = new Http({ });
expect(http.agent).toBeInstanceOf(HttpsProxyAgent);
expect(http.agent.proxy.host).toBe('proxy.example.net');
});
it('uses a "HTTPS_PROXY" env var', () => {
process.env.HTTPS_PROXY = 'http://proxy.example.net:8080/';
const http = new Http({ });
expect(http.agent).toBeInstanceOf(HttpsProxyAgent);
expect(http.agent.proxy.host).toBe('proxy.example.net');
});
it('uses a "httpsProxy" over "https_proxy"/"HTTPS_PROXY" env vars', () => {
process.env.https_proxy = 'http://proxy1.example.net:8080/';
process.env.HTTPS_PROXY = 'http://proxy2.example.net:8080/';
const http = new Http({ httpsProxy: 'http://proxy.example.net:8080/' });
expect(http.agent).toBeInstanceOf(HttpsProxyAgent);
expect(http.agent.proxy.host).toBe('proxy.example.net');
});
});
describe('errorFilter', () => {
it('should resolve promise for status in 200 - 300 range', () => {
Expand Down Expand Up @@ -476,5 +510,24 @@ describe('Http class', () => {
});
});
});

describe('proxy', () => {
it('should use proxy agent in fetch method', () => {
const http = new Http({ requestExecutor, httpsProxy: 'http://proxy.example.net:8080/' });
return http.http('http://fakey.local')
.then(() => {
expect(requestExecutor.fetch).toHaveBeenCalledWith({
headers: {},
method: 'get',
url: 'http://fakey.local',
agent: expect.objectContaining({
proxy: expect.objectContaining({
host: 'proxy.example.net'
})
}),
});
});
});
});
});
});

0 comments on commit 96a735d

Please sign in to comment.