Skip to content

Commit

Permalink
updated docs
Browse files Browse the repository at this point in the history
  • Loading branch information
f-w committed Feb 22, 2021
1 parent d5ea965 commit b97ccbb
Show file tree
Hide file tree
Showing 11 changed files with 207 additions and 32 deletions.
10 changes: 5 additions & 5 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
{
"type": "node",
"request": "launch",
"name": "App",
"name": "Server",
"program": "${workspaceFolder}\\dist\\index.js",
"autoAttachChildProcesses": true,
"console": "internalConsole",
Expand Down Expand Up @@ -63,12 +63,12 @@
],
"compounds": [
{
"name": "App&Docs",
"configurations": ["App", "Docs", "Launch Docs"]
"name": "Server&Docs",
"configurations": ["Server", "Docs", "Launch Docs"]
},
{
"name": "App&Client",
"configurations": ["App", "Client", "Launch Client"]
"name": "Server&Client",
"configurations": ["Server", "Client", "Launch Client"]
}
]
}
1 change: 1 addition & 0 deletions docs/.vuepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ module.exports = {
'config/workerProcessCount',
'config/middleware',
'config/oidc',
'config/certificates',
],
},
{
Expand Down
6 changes: 4 additions & 2 deletions docs/docs/api/administrator.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ permalink: /docs/api-administrator/

# Administrator

The administrator API provides knowledge factor authentication to identify admin request by access token (aka API token in other literature), as opposed to possession factor admin ip list. Because knowledge factor authentication is vulnerable to brute-force attack, administrator API is less favorable than admin ip list. Administrator API is advised to be used only when obtaining client's ip or ip range is infeasible.
The administrator API provides knowledge factor authentication to identify admin request by access token (aka API token in other literatures) associated with a registered administrator maintained in _NotifyBC_ database. Because knowledge factor authentication is vulnerable to brute-force attack, administrator API based access token authentication is less favorable than admin ip list, client certificate, or OIDC authentication.

::: tip Example Use Case
::: warning Avoid Administrator API
Administrator API was created to circumvent an OpenShift limitation - the source ip of a request initiated from an OpenShift pod cannot be exclusively allocated to the pod's project, rather it has to be shared by all OpenShift projects. Therefore it's difficult to impose granular access control based on source ip.

With the introduction client certificate in v2.4.0, most use cases, if not all, that need Administrator API including the OpenShift use case mentioned above can be addressed by client certificate. Therefore only use Administrator API sparingly as last resort.
:::

To enable access token authentication,
Expand Down
99 changes: 99 additions & 0 deletions docs/docs/config/certificates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
permalink: /docs/config-certificates/
---

# TLS Certificates

_NotifyBC_ supports HTTPS TLS to achieve end-to-end encryption. In addition, both server and client can be authenticated using certificates.

To enable HTTPS for server authentication only, you need to create two files

- _server/certs/key.pem_ - a PEM encoded private key
- _server/certs/cert.pem_ - a PEM encoded X.509 certificate chain

::: tip Use ConfigMaps on OpenShift
Create _key.pem_ and _cert.pem_ as items in ConfigMap _notify-bc_, then mount the items under _/opt/app-root/src/server/certs_ similar to how _config.local.js_ and _middleware.local.js_ are implemented.
:::

For self-signed certificate, run

```sh
openssl req -x509 -newkey rsa:4096 -keyout server/certs/key.pem -out server/certs/cert.pem -nodes -days 365 -subj "/CN=NotifyBC"
```

to generate both files in one shot.

To create a CSR from the private key generated above, run

```sh
openssl req -new -key server/certs/key.pem -out server/certs/csr.pem
```

Then bring your CSR to your CA to sign. Replace _server/certs/cert.pem_ with the cert signed by CA. If your CA also supplied intermediate certificate in PEM encoded format, say in a file called _intermediate.pem_, append all of the content of _intermediate.pem_ to file _server/certs/cert.pem_.

::: warning Make a copy of self-signed server/certs/cert.pem
If you want to enable [client certificate authentication](#client-certificate-authentication) documented below, make sure to copy self-signed _server/certs/cert.pem_ to _server/certs/ca.pem_ before replacing the file with the cert signed by CA.
You need the self-signed _server/certs/cert.pem_ to sign client CSR.
:::

In case you created _server/certs/key.pem_ and _server/certs/cert.pem_ but don't want to enable HTTPS, create following config in _src/config.local.js_

```js
module.exports = {
tls: {
enabled: false,
},
};
```

::: warning Update URL configs after enabling HTTPS
Make sure to update the protocol of following URL configs after enabling HTTPS

- [httpHost](../config/httpHost.md)
- [internalHttpHost](../config/internalHttpHost.md)

When _NotifyBC_ is hosted on OpenShift, also update on all deployed environments

- notify-bc-app [livenessProbe httpGet scheme](https://github.com/bcgov/NotifyBC/blob/d389d260ce29beb9631dd73867870fa842fb6181/.openshift-templates/notify-bc.yml#L81)
- notify-bc-app [readinessProbe httpGet scheme](https://github.com/bcgov/NotifyBC/blob/d389d260ce29beb9631dd73867870fa842fb6181/.openshift-templates/notify-bc.yml#L96)
- notify-bc-cron [livenessProbe httpGet scheme](https://github.com/bcgov/NotifyBC/blob/d389d260ce29beb9631dd73867870fa842fb6181/.openshift-templates/notify-bc.yml#L169)
- notify-bc-cron [readinessProbe httpGet scheme](https://github.com/bcgov/NotifyBC/blob/d389d260ce29beb9631dd73867870fa842fb6181/.openshift-templates/notify-bc.yml#L182)
:::

## Client certificate authentication

After enabling HTTPS, you can further configure such that a client request can be authenticated using client certificate. To do so, copy self-signed _server/certs/cert.pem_ to _server/certs/ca.pem_. You will use your server key to sign client certificate CSR, and advertise _server/certs/ca.pem_ as acceptable CAs during TLS handshake.

Assuming a client's CSR file is named _myClientApp_csr.pem_, to sign the CSR

```sh
openssl x509 -req -in myClientApp_csr.pem -CA server/certs/ca.pem -CAkey server/certs/key.pem -out myClientApp_cert.pem -set_serial 01 -days 365
```

Then give _myClientApp_cert.pem_ to the client. How a client app supplies the client certificate when making a request to _NotifyBC_ varies by client type. Usually the client first needs to bundle the signed client cert and client key into PKCS#12 format

```sh
openssl pkcs12 -export -clcerts -in myClientApp_cert.pem -inkey myClientApp_key.pem -out myClientApp.p12
```

To use _myClientApp.p12_, for cURL,

```sh
curl --insecure --cert myClientApp.p12 --cert-type p12 https://localhost:3000/api/administrators/whoami
```

For browsers, check browser's instruction how to import _myClientApp.p12_. When browser accessing _NotifyBC_ API endpoints such as _https://localhost:3000/api/administrators/whoami_, the browser will prompt to choose from a list certificates that are signed by the server certificate.

In case you created _server/certs/ca.pem_ but don't want to enable client certificate authentication, create following config in _src/config.local.js_

```js
module.exports = {
tls: {
clientCertificateEnabled: false,
},
};
```

::: warning TLS termination has to be passthrough
For client certification authentication to work, TLS termination of all reverse proxies has to be set to passthrough rather than offload and reload. This means, for example, when _NotifyBC_ is hosted on OpenShift, router [tls termination](https://github.com/bcgov/NotifyBC/blob/d389d260ce29beb9631dd73867870fa842fb6181/.openshift-templates/notify-bc.yml#L319) has to be changed from _edge_ to _passthrough_.
:::
2 changes: 1 addition & 1 deletion docs/docs/config/internalHttpHost.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ then the HTTP request will be sent to the configured host. An internal request c
All internal requests are supposed to be admin requests. The purpose of _internalHttpHost_ is to facilitate identifying the internal server ip as admin ip.

::: tip OpenShift Use Case
The OpenShift deployment script has set <i>internalHttpHost</i> to service url <i>http://notify-bc:3000</i> in file <a href="https://github.com/bcgov/NotifyBC/blob/main/.s2i/configs/config.production.json">config.production.json</a> so you shouldn't re-define it in <i>/src/config.local.js</i>. The source ip in such case would be in a private OpenShift ip range. You should add this private ip range to <a href="#admin-ip-list">admin ip list</a>. The private ip range varies from OpenShift installation. In BCGov's cluster, it starts with octet 172.
The OpenShift deployment script sets <i>internalHttpHost</i> to service url <i>http://notify-bc:3000</i> in config map. The source ip in such case would be in a private OpenShift ip range. You should add this private ip range to <a href="#admin-ip-list">admin ip list</a>. The private ip range varies from OpenShift installation. In BCGov's OCP4 cluster, it starts with octet 10.
:::
71 changes: 56 additions & 15 deletions docs/docs/getting-started/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,19 @@ _NotifyBC_, designed to be a microservice, doesn't use full-blown ACL to secure

Each type has two subtypes based on following criteria

- super-admin, if the source ip of the request is in the admin ip list and the request doesn't contain any of following case insensitive HTTP headers, with the first three being SiteMinder headers
- super-admin, if the request meets both of the following two requirements

- sm_universalid
- sm_user
- smgov_userdisplayname
- is_anonymous
1. The request carries one of the following two attributes

- the source ip is in the admin ip list
- has a client certificate that is signed using _NotifyBC_ server certificate. See [Client certificate authentication](../config/certificates.md#client-certificate-authentication) on how to sign.

2. The request doesn't contain any of following case insensitive HTTP headers, with the first three being SiteMinder headers

- sm_universalid
- sm_user
- smgov_userdisplayname
- is_anonymous

- admin, if the request is not super-admin and meets one of the following criteria

Expand Down Expand Up @@ -120,9 +127,10 @@ The way _NotifyBC_ interacts with other components is diagrammed below.
API requests to _NotifyBC_ can be either anonymous or authenticated. As alluded in [Request Types](#request-types) above, _NotifyBC_ supports following authentication strategies

1. ip whitelisting
2. Access token associated with an builtin admin user
3. OpenID Connect (OIDC)
4. CA SiteMinder
2. client certificate
3. access token associated with an builtin admin user
4. OpenID Connect (OIDC)
5. CA SiteMinder

Authentication is performed in above order. Once a request passed an authentication strategy, the rest strategies are skipped. A request that failed all authentication strategies is anonymous.

Expand Down Expand Up @@ -153,36 +161,69 @@ The mapping between authentication strategy and request type is
<td class="tg-btxf">anonymous</td>
</tr>
<tr>
<td class="tg-c3ow">ip whitelisting</td>
<td class="tg-0pky">ip whitelisting</td>
<td class="tg-c3ow">✔</td>
<td class="tg-c3ow"></td>
<td class="tg-c3ow"></td>
<td class="tg-c3ow"></td>
</tr>
<tr>
<td class="tg-btxf">access token</td>
<td class="tg-abip"></td>
<td class="tg-btxf">client certifcate</td>
<td class="tg-abip">✔</td>
<td class="tg-abip"></td>
<td class="tg-abip"></td>
<td class="tg-abip"></td>
</tr>
<tr>
<td class="tg-0pky">OIDC</td>
<td class="tg-0pky">access token</td>
<td class="tg-c3ow"></td>
<td class="tg-c3ow">✔</td>
<td class="tg-c3ow"></td>
<td class="tg-c3ow"></td>
<td class="tg-c3ow"></td>
</tr>
<tr>
<td class="tg-btxf">SiteMinder</td>
<td class="tg-abip"></td>
<td class="tg-btxf">OIDC</td>
<td class="tg-abip"></td>
<td class="tg-abip">✔</td>
<td class="tg-abip">✔</td>
<td class="tg-abip"></td>
</tr>
<tr>
<td class="tg-0pky">SiteMinder</td>
<td class="tg-c3ow"></td>
<td class="tg-c3ow"></td>
<td class="tg-c3ow">✔</td>
<td class="tg-c3ow"></td>
</tr>
</tbody>
</table>

::: tip Which authentication strategy to use?

Because ip whitelist doesn't expire and client certificates usually has a relatively long expiration period (say one year), they are suitable for long-running unattended server processes such as server-side code of web apps, cron jobs, IOT sensors etc. The server processes have to be trusted because once authenticated, they have full privilege to _NotifyBC_. Usually the server processes and _NotifyBC_ instance are in the same administration domain, i.e. managed by the same admin group of an organization.

By contrast, OIDC and SiteMinder use short-lived tokens or session cookies. Therefore they are only suitable for interactive user sessions.

Access token associated with an builtin admin user should be avoided whenever possible.

Here are some common scenarios and recommendations

- For server-side code of web apps

- use OIDC if the web app is OIDC enabled and user requests can be proxied to _NotifyBC_ by web app; otherwise
- use ip whitelisting if obtaining ip is feasible; otherwise
- use client certificate (requires a little more config than ip whitelisting)

- For front-end browser-based web apps such as SPAs
- use OIDC
- For server apps that send requests spontaneously such as IOT sensors, cron jobs
- use ip whitelisting if obtaining ip is feasible; otherwise
- client certificate
- If _NotifyBC_ is ued by a _SiteMinder_ protected web apps and _NotifyBC_ is also protected by _SiteMinder_
- use SiteMinder

:::

## Application Framework

_NotifyBC_ is created on Node.js [LoopBack](https://loopback.io/). Contributors to source code of _NotifyBC_ should be familiar with LoopBack. [LoopBack Docs](https://loopback.io/doc/en/lb4) serves a good complement to this documentation.
10 changes: 7 additions & 3 deletions docs/docs/getting-started/web-console.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,22 @@ What you see in web console and what you get from API calls depend on how your r

## Ip whitelisting authentication

The API calls you made with API explorer as well as API calls made by web console from localhost are by default authenticated as [super-admin requests](../overview/#architecture) because localhost is in [admin ip list](../config-adminIpList/) by default. Super-admin authentication status is indicated by the <span class="material-icons">verified_user</span>
The API calls you made with API explorer as well as API calls made by web console from localhost are by default authenticated as [super-admin requests](../overview/#architecture) because localhost is in [admin ip list](../config-adminIpList/) by default. Ip whitelisting authentication status is indicated by the <span class="material-icons">verified_user</span>
icon on top right corner of web console.

To see the result of non super-admin requests, you can choose one of the following methods

- customize admin ip list to omit localhost (127.0.0.1)
- access web console from another ip not in the admin ip list

## Client certificate authentication

If your ip is not in the admin ip list but you have setup a client certificate issued by _NotifyBC_ server in browser, the API calls you made with API explorer as well as API calls made by web console are also authenticated as [super-admin requests](../overview/#architecture). Client certificate authentication status is indicated by the <span class="material-icons">verified</span>
icon on top right corner of web console.

## Anonymous

If you access web console from a client that is not in the admin ip list, you are by default anonymous user.
Anonymous authentication status is indicated by the LOGIN<span class="material-icons">login</span> button on top right corner of web console. Click the button to login.
If you access web console from a client that is not in the admin ip list, you are by default anonymous user. Anonymous authentication status is indicated by the LOGIN<span class="material-icons">login</span> button on top right corner of web console. Click the button to login.

## Access token authentication

Expand Down
9 changes: 9 additions & 0 deletions docs/docs/getting-started/what's-new.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,29 @@ permalink: /docs/what's-new/
_NotifyBC_ has been built on Node.js [LoopBack](https://loopback.io/) framework since 2017. LoopBack v4, which was released in 2019, is backward incompatible. To keep software stack up-to-date, unless rewriting from scratch, it is necessary to port _NotifyBC_ to LoopBack v4. Great care has been taken to minimize migration effort.
:::

## v2.4.0

- Issue [#16](https://github.com/bcgov/NotifyBC/issues/16): Support client certificate authentication
- misc web console adjustments
- docs updates

## v2.3.0

- Issue [#15](https://github.com/bcgov/NotifyBC/issues/15): Support OIDC authentication for both admin and non-admin user
- misc web console adjustments
- docs updates

## v2.2.0

- Issue [#14](https://github.com/bcgov/NotifyBC/issues/14): Support Administrator login, changing password, obtain access token in web console
- misc web console adjustments
- docs updates

## v2.1.0

- Issue [#13](https://github.com/bcgov/NotifyBC/issues/13): Upgraded Vuetify from v0.16.9 to v2.4.3
- misc web console adjustments
- docs updates

## v2.0.0

Expand Down
16 changes: 16 additions & 0 deletions docs/docs/miscellaneous/developer-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ permalink: /docs/developer-notes/

# Developer Notes

## Setup development environment

Install Visual Studio Code and following extensions:

- Prettier
- ESLint
- Vetur
- Code Spell Checker
- Debugger for Chrome

Multiple run configs have been created to facilitate debugging server, client, test and docs.

::: warning Client certificate authentication doesn't work in client debugger
Because Vue cli webpack dev server cannot proxy passthrough HTTPS connections, client certificate authentication doesn't work in client debugger. If testing client certificate authentication in web console is needed, run `yarn build` to generate prod client distribution and launch server debugger on https://localhost:3000
:::

## Automated Testing

Test framework is created by LoopBack lb4 CLI, using LoopBack provided tool set and following LoopBack [best practices](https://loopback.io/doc/en/lb4/Testing-your-application.html). To launch test, run `yarn test`. A _Test_ launch config is provided to debug in VS Code.
Expand Down
13 changes: 8 additions & 5 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ features:
details: >
<ul>
<li>Anonymous or authenticated subscriptions</li>
<li>Multiple authentication strategies</li>
<li>Push and in-app pull notifications</li>
<li>Email and SMS push notification channels</li>
<li>Unicast and broadcast message types</li>
Expand All @@ -24,11 +23,15 @@ features:
<li>Loose coupling - interacts with user browser or other server components through RESTful API.
</li>
</ul>
- title: Microservice
- title: Secure
details: >
Containerized deployment to PAAS such as OpenShift.
No need for complex enterprise-wide shared service. Better
meet privacy mandates.
<ul>
<li>Support end-to-end encryption
</li>
<li>Multiple authentication strategies including client certificate for server-server and OIDC for user-server</li>
<li>Containerized deployment as a microservice. No need for complex enterprise-wide shared service. Better meet privacy mandates.
</li>
</ul>
footer: >
The contents of this website are <br />&copy;&nbsp;2016-present under the terms of the <a href="https://github.com/bcgov/NotifyBC/blob/main/LICENSE">Apache&nbsp;License, Version 2.0</a>.
---
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "notify-bc",
"version": "2.3.0",
"version": "2.4.0",
"dbSchemaVersion": "0.8.0",
"description": "A versatile notification API server",
"keywords": [
Expand Down

0 comments on commit b97ccbb

Please sign in to comment.