Skip to content

Commit

Permalink
add tests for new service classes.
Browse files Browse the repository at this point in the history
fix middleware calls.
fix issues raised in PR.

Signed-off-by: Jason Sherman <[email protected]>
  • Loading branch information
usingtechnology committed Mar 10, 2024
1 parent 9e579a8 commit cafc838
Show file tree
Hide file tree
Showing 12 changed files with 767 additions and 43 deletions.
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: 5 additions & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
"runtimeArgs": ["run", "serve"],
"runtimeExecutable": "npm",
"type": "node",
"env": {}
"env": {
"NODE_CONFIG_DIR": "${workspaceFolder}/.devcontainer/chefs_local"
}
},
{
"cwd": "${workspaceFolder}/app/frontend",
Expand All @@ -30,7 +32,7 @@
"request": "launch",
"runtimeArgs": ["run", "dev"],
"runtimeExecutable": "npm",
"type": "node",
"type": "node"
},
{
"name": "CHEFS Frontend - chrome",
Expand All @@ -39,7 +41,7 @@
"url": "http://localhost:5173/app",
"enableContentValidation": false,
"webRoot": "${workspaceFolder}/app/frontend/src",
"pathMapping": {"url": "//src/", "path": "${webRoot}/"}
"pathMapping": { "url": "//src/", "path": "${webRoot}/" }
}
],
"version": "0.2.0"
Expand Down
2 changes: 1 addition & 1 deletion app/frontend/src/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export const AppPermissions = Object.freeze({
VIEWS_FORM_MANAGE: 'views_form_manage',
VIEWS_FORM_PREVIEW: 'views_form_preview',
VIEWS_FORM_SUBMISSIONS: 'views_form_submissions',
VIEWS_FORM_TEAMS: 'views_form_teamS',
VIEWS_FORM_TEAMS: 'views_form_teams',
VIEWS_FORM_VIEW: 'views_form_view',
VIEWS_USER_SUBMISSIONS: 'views_user_submissions',
});
Expand Down
2 changes: 1 addition & 1 deletion app/frontend/tests/unit/utils/constants.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ describe('Constants', () => {
VIEWS_FORM_MANAGE: 'views_form_manage',
VIEWS_FORM_PREVIEW: 'views_form_preview',
VIEWS_FORM_SUBMISSIONS: 'views_form_submissions',
VIEWS_FORM_TEAMS: 'views_form_teamS',
VIEWS_FORM_TEAMS: 'views_form_teams',
VIEWS_FORM_VIEW: 'views_form_view',
VIEWS_USER_SUBMISSIONS: 'views_user_submissions',
});
Expand Down
2 changes: 1 addition & 1 deletion app/src/components/idpService.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function stringToGUID(s) {
}

function isEmpty(s) {
return s === null || (s && s.trim() === '');
return s === undefined || s === null || (s && s.trim() === '');
}

function isNotEmpty(s) {
Expand Down
37 changes: 21 additions & 16 deletions app/src/components/jwtService.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const jose = require('jose');
const config = require('config');
const Problem = require('api-problem');

const errorToProblem = require('./errorToProblem');

const SERVICE = 'JwtService';
Expand Down Expand Up @@ -63,26 +65,29 @@ class JwtService {
protect(spec) {
// actual middleware
return async (req, res, next) => {
let authorized = false;
try {
// get token, check if valid
const token = this.getBearerToken(req);
if (token) {
const payload = await this._verify(token);
if (spec) {
authorized = payload.client_roles?.includes(spec);
} else {
authorized = true;
let authorized = false;
try {
// get token, check if valid
const token = this.getBearerToken(req);
if (token) {
const payload = await this._verify(token);
if (spec) {
authorized = payload.client_roles?.includes(spec);
} else {
authorized = true;
}
}
} catch (error) {
authorized = false;
}
if (!authorized) {
throw new Problem(401, { detail: 'Access denied' });
} else {
return next();
}
} catch (error) {
authorized = false;
}
if (!authorized) {
res.status(403);
res.end('Access denied');
} else {
return next();
next(error);
}
};
}
Expand Down
44 changes: 26 additions & 18 deletions app/src/forms/auth/middleware/userAccess.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,31 +56,39 @@ const _getForm = async (currentUser, formId, includeDeleted) => {
return form;
};

const setUser = async (req, _res, next) => {
/**
* Express middleware that adds the user information as the res.currentUser
* attribute so that all downstream middleware and business logic can use it.
*
* This will fall through if everything is OK. If the Bearer auth is not valid,
* this will produce a 403 error.
*
* @param {*} req the Express object representing the HTTP request.
* @param {*} _res the Express object representing the HTTP response - unused.
* @param {*} next the Express chaining function.
*/
const currentUser = async (req, _res, next) => {
try {
const token = await jwtService.getTokenPayload(req);
req.currentUser = await service.login(token);
// Validate bearer tokens before anything else - failure means no access.
const bearerToken = jwtService.getBearerToken(req);
if (bearerToken) {
const ok = await jwtService.validateAccessToken(bearerToken);
if (!ok) {
throw new Problem(403, { detail: 'Authorization token is invalid.' });
}
}

// Add the request element that contains the current user's parsed info. It
// is ok if the access token isn't defined: then we'll have a public user.
const accessToken = await jwtService.getTokenPayload(req);
req.currentUser = await service.login(accessToken);

next();
} catch (error) {
next(error);
}
};

const currentUser = async (req, res, next) => {
// Check if authorization header is a bearer token
const token = jwtService.getBearerToken(req);
if (token) {
const ok = await jwtService.validateAccessToken(token);
if (!ok) {
return new Problem(403, {
detail: 'Authorization token is invalid.',
}).send(res);
}
}

return setUser(req, res, next);
};

/**
* Express middleware to check that a user has all the given permissions for a
* form. This will fall through if everything is OK, otherwise it will call
Expand Down
2 changes: 1 addition & 1 deletion app/src/forms/common/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ module.exports = Object.freeze({
VIEWS_FORM_MANAGE: 'views_form_manage',
VIEWS_FORM_PREVIEW: 'views_form_preview',
VIEWS_FORM_SUBMISSIONS: 'views_form_submissions',
VIEWS_FORM_TEAMS: 'views_form_teamS',
VIEWS_FORM_TEAMS: 'views_form_teams',
VIEWS_FORM_VIEW: 'views_form_view',
VIEWS_USER_SUBMISSIONS: 'views_user_submissions',
},
Expand Down
Loading

0 comments on commit cafc838

Please sign in to comment.