Skip to content

Commit

Permalink
Release Proxy (#233)
Browse files Browse the repository at this point in the history
* build(deps): bump node-fetch from 2.6.2 to 2.6.7 (#219)

Bumps [node-fetch](https://github.com/node-fetch/node-fetch) from 2.6.2 to 2.6.7.
- [Release notes](https://github.com/node-fetch/node-fetch/releases)
- [Commits](node-fetch/node-fetch@v2.6.2...v2.6.7)

---
updated-dependencies:
- dependency-name: node-fetch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump follow-redirects from 1.14.7 to 1.14.8 (#220)

* fix(oidc): Use latest version of ssr-pages (#221)

* fix(oidc): Fixes post-logout redirect for single tenant config (#224)

* fix(oidc): Fixes post-logout redirect for single tenant config

* revert package lock

* build(deps): bump ansi-regex from 3.0.0 to 3.0.1 (#226)

Bumps [ansi-regex](https://github.com/chalk/ansi-regex) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/chalk/ansi-regex/releases)
- [Commits](chalk/ansi-regex@v3.0.0...v3.0.1)

---
updated-dependencies:
- dependency-name: ansi-regex
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Fix missing axios dependency (#229)

* Update package.json

closes #228

* Update CHANGELOG.md

* fix package-lock

* feat(proxy): ⚡ Adds an option to opt out from token fowrarding (#231)

* feat(proxy): ⚡ Adds an option to opt out from token fowrarding (per service)

* unit test coverage

* [Proxy] cookies forwarding (#232)

* feat(proxy): ⚡ Adds an option to opt out from token fowrarding (per service)

* unit test coverage

* feat(proxy): ✨ List cookies you want to proxy in the `allowedCookies` option

* docs(proxy): ✏️ Fix typo

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • Loading branch information
bcldvd and dependabot[bot] authored May 19, 2022
1 parent 4e37196 commit f27df7a
Show file tree
Hide file tree
Showing 11 changed files with 8,006 additions and 9,337 deletions.
6 changes: 3 additions & 3 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"recommendations": [
"alanwalk.markdown-toc",
"vivaxy.vscode-conventional-commits",
"orta.vscode-jest",
"cssho.vscode-svgviewer",
"gruntfuggly.todo-tree"
"gruntfuggly.todo-tree",
"huntertran.auto-markdown-toc"
]
}
}
62 changes: 44 additions & 18 deletions libs/proxy/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,57 @@

**Table of Contents**

<!-- TOC depthFrom:2 depthTo:3 -->
<!-- TOC depthfrom:2 depthto:3 -->

- [0.5.3 (2021-10-20)](#053-2021-10-20)
- [2022-05-18](#2022-05-18)
- [Features](#features)
- [2021-11-4](#2021-11-4)
- [Features](#features)
- [2021-10-20](#2021-10-20)
- [Bugfixes](#bugfixes)
- [2021-10-20](#2021-10-20)
- [Bugfixes](#bugfixes)
- [0.5.2 (2021-10-20)](#052-2021-10-20)
- [Bugfixes](#bugfixes-1)
- [0.5.1 (2021-10-19)](#051-2021-10-19)
- [Bugfixes](#bugfixes-2)
- [0.5.0 (2021-09-27)](#050-2021-09-27)
- [2021-10-19](#2021-10-19)
- [Bugfixes](#bugfixes)
- [2021-09-27](#2021-09-27)
- [Features](#features)
- [2020-09-16](#2020-09-16)
- [Features](#features)
- [2020-07-23](#2020-07-23)
- [Bugfixes](#bugfixes)
- [2020-07-23](#2020-07-23)
- [Features](#features)
- [2020-06-25](#2020-06-25)
- [Bug fixes](#bug-fixes)
- [2020-05-19](#2020-05-19)
- [Features](#features)
- [0.4.0 (2020-09-16)](#040-2020-09-16)
- [Features](#features-1)
- [0.3.1 (2020-07-23)](#031-2020-07-23)
- [Bugfixes](#bugfixes-3)
- [0.3.0 (2020-07-23)](#030-2020-07-23)
- [Features](#features-2)
- [0.2.1 (2020-06-25)](#021-2020-06-25)
- [2020-04-30](#2020-04-30)
- [Bug fixes](#bug-fixes)
- [0.2.0 (2020-05-19)](#020-2020-05-19)
- [Features](#features-3)
- [0.1.1 (2020-04-30)](#011-2020-04-30)
- [Bug fixes](#bug-fixes-1)

<!-- /TOC -->

## 0.7.0 (2022-05-18)

### Features

- Adds an option to opt out from token forwarding (per service).

```typescript
services: [
{
id: 'THIRD_PARTY_SERVICE',
url: 'https://some-service.com/some-endpoint',
forwardToken: false,
},
];
```

- Cookies are not proxied anymore by default. You can opt in by listing the cookie names in the `allowedCookies` option.

```typescript
allowedCookies: ['cookie1', 'cookie2'],
```

## 0.6.0 (2021-11-4)

### Features
Expand Down
25 changes: 25 additions & 0 deletions libs/proxy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,31 @@ Whether synchronously or asynchronously, the module takes two parameters (both o

> A service can also take an optional `config`, which is the same signature as the parent one, allowing you to override configuration for that particular service !
### Token forwarding

By default, OAuth token are forwarded to the service call being proxied. You can disable this by setting the `forwardToken` property to `false` in the service configuration.

```typescript
services: [
{
id: 'THIRD_PARTY_SERVICE',
url: 'https://some-service.com/some-endpoint',
forwardToken: false,
},
];
```

> &#x26A0; Be careful to only forward tokens to internal services. Don't forward the token to third party services.
### Cookies forwarding

Cookies are not proxied by default. You can opt in by listing the cookie names in the `allowedCookies` option:

```typescript
allowedCookies: ['cookie1', 'cookie2'],
```


### Default module configuration

If you do not provide any, the default proxy configuration for this module can be found in [proxy.constants.ts](./src/proxy.constants.ts), under `defaultProxyOptions`
Expand Down
2 changes: 1 addition & 1 deletion libs/proxy/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@finastra/nestjs-proxy",
"version": "0.6.0",
"version": "0.7.0",
"contributors": [
"David Boclé <david.bocle@finastra.com>"
],
Expand Down
2 changes: 2 additions & 0 deletions libs/proxy/src/interfaces/proxy.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ export interface Service {
id: string;
url: string;
config?: server.ServerOptions;
forwardToken?: boolean;
}

export interface ProxyModuleOptions {
config?: server.ServerOptions;
services?: Service[];
allowedCookies?: string[];
}

export interface ProxyModuleOptionsFactory {
Expand Down
55 changes: 55 additions & 0 deletions libs/proxy/src/proxy.module.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Test, TestingModule } from '@nestjs/testing';
import * as server from 'http-proxy';
import { createRequest } from 'node-mocks-http';
import { ProxyModuleOptions } from './interfaces';
import { HTTP_PROXY } from './proxy.constants';
import { ProxyModule } from './proxy.module';

Expand All @@ -26,6 +27,7 @@ describe('ProxyModule', () => {
const proxyReq = createRequest();
const req = createRequest();
proxyReq.getHeader = header => header;
proxyReq.setHeader = jest.fn();
proxyReq.write = jest.fn();
proxyReq.protocol = 'http:';
proxyReq.host = 'localhost';
Expand All @@ -40,6 +42,7 @@ describe('ProxyModule', () => {
const body = { prop: 'test' };
req.body = body;
proxyReq.getHeader = header => header;
proxyReq.setHeader = jest.fn();
proxyReq.write = jest.fn();
proxyReq.protocol = 'http:';
proxyReq.host = 'localhost';
Expand All @@ -51,6 +54,7 @@ describe('ProxyModule', () => {
it('should stringify body if content type is json', () => {
const proxyReq = createRequest();
proxyReq.getHeader = header => 'application/json';
proxyReq.setHeader = jest.fn();
proxyReq.write = jest.fn();
proxyReq.setHeader = jest.fn();
proxyReq.protocol = 'http:';
Expand Down Expand Up @@ -81,6 +85,20 @@ describe('ProxyModule', () => {
proxy.emit('proxyReq', proxyReq, req);
expect(spy).toHaveBeenCalledWith('prop=test');
});

it('should strip all cookies since no allowedCookies defined', () => {
const proxyReq = createRequest();
const req = createRequest();
proxyReq._headers = { cookie: 'ga=test' };
proxyReq.getHeader = header => proxyReq._headers[header];
proxyReq.setHeader = (header, value) => (proxyReq._headers[header] = value);
proxyReq.write = jest.fn();
proxyReq.protocol = 'http:';
proxyReq.host = 'localhost';

proxy.emit('proxyReq', proxyReq, req);
expect(proxyReq.getHeader('cookie')).toBe('');
});
});
});
});
Expand Down Expand Up @@ -126,4 +144,41 @@ describe('ProxyModule', () => {
expect(module).toBeDefined();
});
});

describe('register sync', () => {
let module: TestingModule;
let proxy;
const mockProxyModuleOptions: ProxyModuleOptions = {
allowedCookies: ['_ga'],
};

beforeEach(async () => {
module = await Test.createTestingModule({
imports: [ProxyModule.forRoot(mockProxyModuleOptions)],
}).compile();
proxy = module.get<server>(HTTP_PROXY);
});

it('should be defined', () => {
expect(module).toBeDefined();
});

describe('proxyFactory', () => {
describe('on ProxyReq', () => {
it('should strip all cookies since no allowedCookies defined', () => {
const proxyReq = createRequest();
const req = createRequest();
proxyReq._headers = { cookie: '_ga=test; privateCookie=secret;' };
proxyReq.getHeader = header => proxyReq._headers[header];
proxyReq.setHeader = (header, value) => (proxyReq._headers[header] = value);
proxyReq.write = jest.fn();
proxyReq.protocol = 'http:';
proxyReq.host = 'localhost';

proxy.emit('proxyReq', proxyReq, req);
expect(proxyReq.getHeader('cookie')).toBe('_ga=test');
});
});
});
});
});
11 changes: 10 additions & 1 deletion libs/proxy/src/proxy.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,19 @@ const proxyFactory = {
...options.config,
});

proxy.on('proxyReq', function (proxyReq, req, res, options) {
proxy.on('proxyReq', function (proxyReq, req, res, opts) {
const url = concatPath(`${proxyReq.protocol}//${proxyReq.host}`, req.url);
logger.log(`Sending ${req.method} ${url}`);

let cookies = (proxyReq.getHeader('cookie') || '') as string;
const allowedCookies = options.allowedCookies || [];
cookies = cookies
.split(';')
.filter(cookie => allowedCookies.indexOf(cookie.split('=')[0].trim()) !== -1)
.join(';');

proxyReq.setHeader('cookie', cookies);

if (!req['body'] || !Object.keys(req['body']).length) {
return;
}
Expand Down
22 changes: 22 additions & 0 deletions libs/proxy/src/services/proxy.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ const services = [
id: 'test',
url: 'https://test.io/subpath',
},
{
id: 'THIRD_PARTY_SERVICE',
url: 'https://some-service.com/some-endpoint',
forwardToken: false,
},
];
const mockProxyModuleOptions = {
services,
Expand Down Expand Up @@ -119,6 +124,23 @@ describe('ProxyService', () => {
expect((spy.mock.calls[0][2] as any).headers).toHaveProperty('authorization');
});

it('should not call proxy with token', () => {
const req = createMock<Request>();
const res = createMock<Response>();
req.query = {
serviceId: services[1].id,
};
req.user = {
authTokens: {
accessToken: 'test',
},
};

const spy = jest.spyOn(proxy, 'web');
service.proxyRequest(req, res);
expect((spy.mock.calls[0][2] as any).headers).not.toHaveProperty('authorization');
});

it('should send a 500 if error comes from proxy', done => {
const req = createMock<Request>();
const res = createMock<Response>();
Expand Down
8 changes: 7 additions & 1 deletion libs/proxy/src/services/proxy.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,13 @@ export class ProxyService {
if (services.has(serviceId)) {
const service = services.get(serviceId);
const baseUrl = service.url;
return this.doProxy(req, res, target ? concatPath(baseUrl, prefix, target) : baseUrl, token, service.config);
return this.doProxy(
req,
res,
target ? concatPath(baseUrl, prefix, target) : baseUrl,
service.forwardToken === false ? null : token,
service.config,
);
} else {
const error = `Could not find serviceId ${serviceId}`;
this.logger.warn(error);
Expand Down
Loading

0 comments on commit f27df7a

Please sign in to comment.