Skip to content

Commit

Permalink
Merge pull request bcgov#1258 from usingtechnology/forms-960-idp-refa…
Browse files Browse the repository at this point in the history
…ctor

Keycloak Custom to Standard, Identity Provider refactoring
  • Loading branch information
usingtechnology authored Apr 21, 2024
2 parents 0f51715 + fc3ebb7 commit e913ec9
Show file tree
Hide file tree
Showing 112 changed files with 3,156 additions and 1,039 deletions.
33 changes: 33 additions & 0 deletions .devcontainer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ The `.devcontainer` folder contains the `devcontainer.json` file which defines t

In order to run CHEFS you require Keycloak (configured), Postgresql (seeded) and the CHEFS backend/API and frontend/UX. Previously, this was a series of downloads and configuration updates and numerous commands to run. See `.devcontainer/chefs_local` files.

**NODE_CONFIG_DIR** to simplify loading a default configuration to the CHEFS infrastructure (Keycloak, Postgresql, etc), we set an environment variable [`NODE_CONFIG_DIR`](https://github.com/node-config/node-config/wiki/Environment-Variables#node_config_dir). This supercedes the files found under `app/config`. Running node apps and commands (ex. knex, launch configurations) will use this environment variable and load configuration from `.devcontainer/chefs_local`.

Also included are convenient launch tasks to run and debug CHEFS.

## Open CHEFS in the devcontainer
Expand Down Expand Up @@ -72,6 +74,37 @@ _Notes_

If you are developing the formio components, you should build and redeploy them before running your local debug instances of CHEFS. Use tasks `Components build` and `Components Deploy`.

## KNEX - Database tools
[knex](https://knexjs.org) is installed globally and should be run from the `/app` directory where the knex configuration is located. Use knex to stub out migrations or to rollback migrations as you are developing.

### create a migration file
This will create a stub file with a timestamp. You will populate the up and down methods to add/update/delete database objects.

```
cd app
knex migrate:make my_new_migration_script
> Created Migration: /workspaces/common-hosted-form-service/app/src/db/migrations/20240119172630_my_new_migration_script.js
```

### rollback previous migration
When developing your migrations, you may find it useful to run the migration and roll it back if it isn't exactly what you expect to happen.

#### run the migration(s)
```
cd app
knex migrate:latest
> Batch 2 run: 1 migrations
```

#### rollback the migration(s)
```
cd app
knex migrate:rollback
> Batch 2 rolled back: 1 migrations
```

Please review the [knex](https://knexjs.org) for more detail and how to leverage the tool.

## Troubleshooting

All development machines are unique and here we will document problems that have been encountered and how to fix them.
Expand Down
21 changes: 12 additions & 9 deletions .devcontainer/chefs_local/local.json.sample
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,24 @@
"frontend": {
"apiPath": "api/v1",
"basePath" : "/app",
"keycloak": {
"clientId": "chefs-frontend-local",
"realm": "chefs",
"serverUrl": "http://localhost:8082"
"oidc": {
"clientId": "chefs-frontend-localhost-5300",
"realm": "standard",
"serverUrl": "https://dev.loginproxy.gov.bc.ca/auth",
"logoutUrl": "https://logon7.gov.bc.ca/clp-cgi/logoff.cgi?retnow=1&returl=https%3A%2F%2Fdev.loginproxy.gov.bc.ca%2Fauth%2Frealms%2Fstandard%2Fprotocol%2Fopenid-connect%2Flogout"
}
},
"server": {
"apiPath": "/api/v1",
"basePath" : "/app",
"bodyLimit": "30mb",
"keycloak": {
"clientId": "chefs",
"realm": "chefs",
"serverUrl": "http://localhost:8082",
"clientSecret": "XXXXXXXXXXXX"
"oidc": {
"realm": "standard",
"serverUrl": "https://dev.loginproxy.gov.bc.ca/auth",
"jwksUri": "https://dev.loginproxy.gov.bc.ca/auth/realms/standard/protocol/openid-connect/certs",
"issuer": "https://dev.loginproxy.gov.bc.ca/auth/realms/standard",
"audience": "chefs-frontend-localhost-5300",
"maxTokenAge": "300"
},
"logLevel": "http",
"port": "8080",
Expand Down
92 changes: 92 additions & 0 deletions .devcontainer/chefs_local/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{
"db": {
"database": "chefs",
"host": "localhost",
"port": "5432",
"username": "app",
"password": "admin"
},
"files": {
"uploads": {
"enabled": "true",
"fileCount": "1",
"fileKey": "files",
"fileMaxSize": "25MB",
"fileMinSize": "0KB",
"path": "files"
},
"permanent": "localStorage",
"localStorage": {
"path": "myfiles"
},
"objectStorage": {
"accessKeyId": "bcgov-citz-ccft",
"bucket": "chefs",
"endpoint": "https://commonservices.objectstore.gov.bc.ca",
"key": "chefs/dev/",
"secretAccessKey": "anything"
}
},
"frontend": {
"apiPath": "api/v1",
"basePath": "/app",
"oidc": {
"clientId": "chefs-frontend-localhost-5300",
"realm": "standard",
"serverUrl": "https://dev.loginproxy.gov.bc.ca/auth",
"logoutUrl": "https://logon7.gov.bc.ca/clp-cgi/logoff.cgi?retnow=1&returl=https%3A%2F%2Fdev.loginproxy.gov.bc.ca%2Fauth%2Frealms%2Fstandard%2Fprotocol%2Fopenid-connect%2Flogout"
}
},
"server": {
"apiPath": "/api/v1",
"basePath": "/app",
"bodyLimit": "30mb",
"oidc": {
"realm": "standard",
"serverUrl": "https://dev.loginproxy.gov.bc.ca/auth",
"jwksUri": "https://dev.loginproxy.gov.bc.ca/auth/realms/standard/protocol/openid-connect/certs",
"issuer": "https://dev.loginproxy.gov.bc.ca/auth/realms/standard",
"audience": "chefs-frontend-localhost-5300",
"maxTokenAge": "300"
},
"logLevel": "http",
"port": "8080",
"rateLimit": {
"public": {
"windowMs": "900000",
"max": "100"
}
}
},
"serviceClient": {
"commonServices": {
"ches": {
"endpoint": "https://ches-dev.api.gov.bc.ca/api",
"tokenEndpoint": "https://dev.loginproxy.gov.bc.ca/auth/realms/comsvcauth/protocol/openid-connect/token",
"clientId": "CHES_CLIENT_ID",
"clientSecret": "CHES_CLIENT_SECRET"
},
"cdogs": {
"endpoint": "https://cdogs-dev.api.gov.bc.ca/api",
"tokenEndpoint": "https://dev.loginproxy.gov.bc.ca/auth/realms/comsvcauth/protocol/openid-connect/token",
"clientId": "CDOGS_CLIENT_ID",
"clientSecret": "CDOGS_CLIENT_SECRET"
}
}
},
"customBcAddressFormioComponent": {
"apikey": "xxxxxxxxxxxxxxx",
"bcAddressURL": "https://geocoder.api.gov.bc.ca/addresses.json",
"queryParameters": {
"echo": false,
"brief": true,
"minScore": 55,
"onlyCivic": true,
"maxResults": 15,
"autocomplete": true,
"matchAccuracy": 100,
"matchPrecision": "occupant, unit, site, civic_number, intersection, block, street, locality, province",
"precisionPoints": 100
}
}
}
8 changes: 6 additions & 2 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,12 @@
"editor.formatOnSave": true
}
}
}
},

// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
//"remoteUser": "root"
//"remoteUser": "root",

"containerEnv": {
"NODE_CONFIG_DIR": "${containerWorkspaceFolder}/.devcontainer/chefs_local"
}
}
3 changes: 3 additions & 0 deletions .devcontainer/post-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ set -ex
WORKSPACE_DIR=$(pwd)
CHEFS_LOCAL_DIR=${WORKSPACE_DIR}/.devcontainer/chefs_local

npm install knex -g
npm install jest -g

# install app libraries, prepare for app development and debugging...
cd app
npm install
Expand Down
23 changes: 20 additions & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"runtimeExecutable": "npm",
"type": "node",
"env": {
"NODE_CONFIG_DIR": "${workspaceFolder}/.devcontainer/chefs_local",
"NODE_CONFIG_DIR": "${workspaceFolder}/.devcontainer/chefs_local"
}
},
{
Expand All @@ -32,7 +32,7 @@
"request": "launch",
"runtimeArgs": ["run", "dev"],
"runtimeExecutable": "npm",
"type": "node",
"type": "node"
},
{
"name": "CHEFS Frontend - chrome",
Expand All @@ -41,7 +41,24 @@
"url": "http://localhost:5173/app",
"enableContentValidation": false,
"webRoot": "${workspaceFolder}/app/frontend/src",
"pathMapping": {"url": "//src/", "path": "${webRoot}/"}
"pathMapping": { "url": "//src/", "path": "${webRoot}/" }
},
{
"type": "node",
"request": "launch",
"name": "Jest: current file",
//"env": { "NODE_ENV": "test" },
"program": "${workspaceFolder}/app/node_modules/.bin/jest",
"args": [
"${fileBasenameNoExtension}",
"--config",
"${workspaceFolder}/app/jest.config.js",
"--coverage=false"
],
"console": "integratedTerminal",
"windows": {
"program": "${workspaceFolder}/app/node_modules/jest/bin/jest"
}
}
],
"version": "0.2.0"
Expand Down
6 changes: 4 additions & 2 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,16 @@
{
"label": "chefs_local up",
"type": "shell",
"command": "docker-compose -f ${workspaceFolder}/.devcontainer/chefs_local/docker-compose.yml up -d",
"command": "docker-compose",
"args": ["-f", "${workspaceFolder}/.devcontainer/chefs_local/docker-compose.yml", "up", "-d"],
"isBackground": true,
"problemMatcher": [],
},
{
"label": "chefs_local down",
"type": "shell",
"command": "docker-compose -f ${workspaceFolder}/.devcontainer/chefs_local/docker-compose.yml down",
"command": "docker-compose",
"args": ["-f", "${workspaceFolder}/.devcontainer/chefs_local/docker-compose.yml", "down"],
"isBackground": true,
"problemMatcher": [],
},
Expand Down
22 changes: 14 additions & 8 deletions app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ const path = require('path');
const Problem = require('api-problem');
const querystring = require('querystring');

const keycloak = require('./src/components/keycloak');
const log = require('./src/components/log')(module.filename);
const httpLogger = require('./src/components/log').httpLogger;
const middleware = require('./src/forms/common/middleware');
Expand Down Expand Up @@ -40,9 +39,6 @@ if (process.env.NODE_ENV !== 'test') {
app.use(httpLogger);
}

// Use Keycloak OIDC Middleware
app.use(keycloak.middleware());

// Block requests until service is ready
app.use((_req, res, next) => {
if (state.shutdown) {
Expand Down Expand Up @@ -178,11 +174,16 @@ function initializeConnections() {
.then((results) => {
state.connections.data = results[0];

if (state.connections.data) log.info('DataConnection Reachable', { function: 'initializeConnections' });
if (state.connections.data)
log.info('DataConnection Reachable', {
function: 'initializeConnections',
});
})
.catch((error) => {
log.error(`Initialization failed: Database OK = ${state.connections.data}`, { function: 'initializeConnections' });
log.error('Connection initialization failure', error.message, { function: 'initializeConnections' });
log.error('Connection initialization failure', error.message, {
function: 'initializeConnections',
});
if (!state.ready) {
process.exitCode = 1;
shutdown();
Expand All @@ -191,7 +192,9 @@ function initializeConnections() {
.finally(() => {
state.ready = Object.values(state.connections).every((x) => x);
if (state.ready) {
log.info('Service ready to accept traffic', { function: 'initializeConnections' });
log.info('Service ready to accept traffic', {
function: 'initializeConnections',
});
// Start periodic 10 second connection probe check
probeId = setInterval(checkConnections, 10000);
}
Expand All @@ -211,7 +214,10 @@ function checkConnections() {
Promise.all(tasks).then((results) => {
state.connections.data = results[0];
state.ready = Object.values(state.connections).every((x) => x);
if (!wasReady && state.ready) log.info('Service ready to accept traffic', { function: 'checkConnections' });
if (!wasReady && state.ready)
log.info('Service ready to accept traffic', {
function: 'checkConnections',
});
log.verbose(state);
if (!state.ready) {
process.exitCode = 1;
Expand Down
22 changes: 12 additions & 10 deletions app/config/custom-environment-variables.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,24 @@
"adminDashboardUrl": "VITE_ADMIN_DASHBOARD_URL",
"apiPath": "FRONTEND_APIPATH",
"basePath": "VITE_FRONTEND_BASEPATH",
"keycloak": {
"clientId": "FRONTEND_KC_CLIENTID",
"realm": "FRONTEND_KC_REALM",
"serverUrl": "FRONTEND_KC_SERVERURL"
"oidc": {
"clientId": "OIDC_CLIENTID",
"realm": "OIDC_REALM",
"serverUrl": "OIDC_SERVERURL",
"logoutUrl": "OIDC_LOGOUTURL"
}
},
"server": {
"apiPath": "SERVER_APIPATH",
"basePath": "SERVER_BASEPATH",
"bodyLimit": "SERVER_BODYLIMIT",
"keycloak": {
"clientId": "SERVER_KC_CLIENTID",
"clientSecret": "SERVER_KC_CLIENTSECRET",
"publicKey": "SERVER_KC_PUBLICKEY",
"realm": "SERVER_KC_REALM",
"serverUrl": "SERVER_KC_SERVERURL"
"oidc": {
"realm": "OIDC_REALM",
"serverUrl": "OIDC_SERVERURL",
"jwksUri": "OIDC_JWKSURI",
"issuer": "OIDC_ISSUER",
"audience": "OIDC_CLIENTID",
"maxTokenAge": "OIDC_MAXTOKENAGE"
},
"logFile": "SERVER_LOGFILE",
"logLevel": "SERVER_LOGLEVEL",
Expand Down
22 changes: 13 additions & 9 deletions app/config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,25 @@
"adminDashboardUrl": "",
"apiPath": "api/v1",
"basePath": "/app",
"keycloak": {
"clientId": "chefs-frontend",
"realm": "chefs",
"serverUrl": "https://dev.loginproxy.gov.bc.ca/auth"
"oidc": {
"clientId": "chefs-frontend-localhost-5300",
"realm": "standard",
"serverUrl": "https://dev.loginproxy.gov.bc.ca/auth",
"logoutUrl": "https://logon7.gov.bc.ca/clp-cgi/logoff.cgi?retnow=1&returl=https%3A%2F%2Fdev.loginproxy.gov.bc.ca%2Fauth%2Frealms%2Fstandard%2Fprotocol%2Fopenid-connect%2Flogout"
}
},
"server": {
"apiPath": "/api/v1",
"basePath": "/app",
"bodyLimit": "30mb",
"keycloak": {
"clientId": "chefs",
"realm": "chefs",
"serverUrl": "https://dev.loginproxy.gov.bc.ca/auth"
},
"oidc": {
"realm": "standard",
"serverUrl": "https://dev.loginproxy.gov.bc.ca/auth",
"jwksUri": "https://dev.loginproxy.gov.bc.ca/auth/realms/standard/protocol/openid-connect/certs",
"issuer": "https://dev.loginproxy.gov.bc.ca/auth/realms/standard",
"audience": "chefs-frontend-localhost-5300",
"maxTokenAge": "300"
},
"logLevel": "http",
"port": "8080",
"rateLimit": {
Expand Down
Loading

0 comments on commit e913ec9

Please sign in to comment.