Skip to content

Commit

Permalink
Merge pull request #196 from bcgov/chore/release
Browse files Browse the repository at this point in the history
Release COMS v0.6
  • Loading branch information
TimCsaky authored Aug 11, 2023
2 parents f027eab + 00915fa commit 5612188
Show file tree
Hide file tree
Showing 11 changed files with 5,961 additions and 6,102 deletions.
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#
# Build the application
#
FROM registry.access.redhat.com/ubi9/nodejs-18:1-48 as builder
FROM registry.access.redhat.com/ubi9/nodejs-18:1-59 as builder

ENV NO_UPDATE_NOTIFIER=true

Expand All @@ -22,7 +22,7 @@ RUN npm ci --omit=dev
#
# Create the final container image
#
FROM registry.access.redhat.com/ubi9/nodejs-18-minimal:1-51
FROM registry.access.redhat.com/ubi9/nodejs-18-minimal:1-63

ENV APP_PORT=3000 \
NO_UPDATE_NOTIFIER=true
Expand Down
4 changes: 2 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ At this time, only the latest version of Common Object Management Service is sup

| Version | Supported |
| ------- | ------------------ |
| 0.5.0 | :white_check_mark: |
| < 0.5.x | :x: |
| 0.6.0 | :white_check_mark: |
| < 0.6.x | :x: |

## Reporting a Bug

Expand Down
8 changes: 5 additions & 3 deletions app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,11 @@ switch (state.authMode) {
break;
}
if (state.authMode === AuthMode.OIDCAUTH || state.authMode === AuthMode.FULLAUTH) {
// Use Keycloak OIDC Middleware
const keycloak = require('./src/components/keycloak');
app.use(keycloak.middleware());
if (!config.has('keycloak.publicKey')) {
log.error('OIDC environment variable KC_PUBLICKEY or keycloak.publicKey must be defined');
process.exitCode = 1;
shutdown();
}
}

// Application privacy Mode mode
Expand Down
11,934 changes: 5,910 additions & 6,024 deletions app/package-lock.json

Large diffs are not rendered by default.

29 changes: 14 additions & 15 deletions app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "common-object-management-service",
"version": "0.5.0",
"version": "0.6.0",
"private": true,
"description": "",
"author": "NR Common Service Showcase <NR.CommonServiceShowcase@gov.bc.ca>",
Expand Down Expand Up @@ -29,9 +29,9 @@
"seed": "knex seed:run"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.341.0",
"@aws-sdk/lib-storage": "^3.341.0",
"@aws-sdk/s3-request-presigner": "^3.341.0",
"@aws-sdk/client-s3": "^3.388.0",
"@aws-sdk/lib-storage": "^3.388.0",
"@aws-sdk/s3-request-presigner": "^3.388.0",
"api-problem": "^9.0.1",
"busboy": "^1.6.0",
"compression": "^1.7.4",
Expand All @@ -44,23 +44,22 @@
"express-validation": "^4.1.0",
"express-winston": "^4.2.0",
"js-yaml": "^4.1.0",
"jsonwebtoken": "^9.0.0",
"keycloak-connect": "^21.0.1",
"knex": "^2.4.2",
"objection": "^3.0.1",
"pg": "^8.11.0",
"winston": "^3.9.0",
"jsonwebtoken": "^9.0.1",
"knex": "^2.5.1",
"objection": "^3.1.1",
"pg": "^8.11.2",
"winston": "^3.10.0",
"winston-transport": "^4.5.0"
},
"devDependencies": {
"aws-sdk-client-mock": "^2.1.1",
"aws-sdk-client-mock-jest": "^2.1.1",
"eslint": "^8.41.0",
"aws-sdk-client-mock": "^3.0.0",
"aws-sdk-client-mock-jest": "^3.0.0",
"eslint": "^8.47.0",
"eslint-config-recommended": "^4.1.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-prettier": "^5.0.0",
"jest": "~29.3.1",
"jest-joi": "^1.1.17",
"nodemon": "^2.0.22",
"nodemon": "^3.0.1",
"supertest": "^6.3.3"
}
}
21 changes: 0 additions & 21 deletions app/src/components/keycloak.js

This file was deleted.

4 changes: 2 additions & 2 deletions app/src/db/models/mixins/encrypt.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ const Encrypt = opts => {
await super.$afterUpdate(queryOptions, context);
return this.decryptFields();
}
async $afterGet(context) {
await super.$afterGet(context);
async $afterFind(context) {
await super.$afterFind(context);
return this.decryptFields();
}

Expand Down
3 changes: 1 addition & 2 deletions app/src/middleware/authentication.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ const currentUser = async (req, res, next) => {
issuer: `${config.get('keycloak.serverUrl')}/realms/${config.get('keycloak.realm')}`
});
} else {
const keycloak = require('../components/keycloak');
isValid = await keycloak.grantManager.validateAccessToken(bearerToken);
throw new Error('OIDC environment variable KC_PUBLICKEY or keycloak.publicKey must be defined');
}

if (isValid) {
Expand Down
50 changes: 22 additions & 28 deletions app/tests/unit/middleware/authentication.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const jwt = require('jsonwebtoken');

const mw = require('../../../src/middleware/authentication');
const { AuthType } = require('../../../src/components/constants');
const keycloak = require('../../../src/components/keycloak');
const { userService } = require('../../../src/services');

// Mock config library - @see {@link https://stackoverflow.com/a/64819698}
Expand All @@ -17,8 +16,6 @@ jest.mock('express-basic-auth', () => {
buildMiddleware.safeCompare = jest.requireActual('express-basic-auth').safeCompare;
return buildMiddleware;
});
// Mock out keycloak library and use a spy to observe behavior
jest.mock('../../../src/components/keycloak');

beforeEach(() => {
jest.resetAllMocks();
Expand Down Expand Up @@ -90,7 +87,6 @@ describe('currentUser', () => {
const jwtVerifySpy = jest.spyOn(jwt, 'verify');
const loginSpy = jest.spyOn(userService, 'login');
const problemSendSpy = jest.spyOn(Problem.prototype, 'send');
const validateAccessTokenSpy = jest.spyOn(keycloak.grantManager, 'validateAccessToken');

let req, res, next;

Expand Down Expand Up @@ -159,7 +155,7 @@ describe('currentUser', () => {
it.each([
['SPKI', spki],
['PEM', publicKey]
])('sets authType to BEARER with keycloak.publicKey %s', async (_desc, pkey) => {
])('sets authType to BEARER with keycloak.publicKey %s and valid auth token', async (_desc, pkey) => {
jwtVerifySpy.mockReturnValue({ sub: 'sub' }); // return truthy value
loginSpy.mockImplementation(() => { });
config.has
Expand Down Expand Up @@ -187,7 +183,6 @@ describe('currentUser', () => {
expect(config.get).toHaveBeenNthCalledWith(1, 'keycloak.publicKey');
expect(config.get).toHaveBeenNthCalledWith(2, 'keycloak.serverUrl');
expect(config.get).toHaveBeenNthCalledWith(3, 'keycloak.realm');
expect(validateAccessTokenSpy).toHaveBeenCalledTimes(0);
expect(checkBasicAuthSpy).toHaveBeenCalledTimes(0);
expect(jwtVerifySpy).toHaveBeenCalledTimes(1);
expect(jwtVerifySpy).toHaveBeenCalledWith(expect.any(String), publicKey, expect.objectContaining({
Expand All @@ -200,42 +195,43 @@ describe('currentUser', () => {
expect(problemSendSpy).toHaveBeenCalledTimes(0);
});

it('sets authType to BEARER without keycloak.publicKey and valid token', async () => {
jwtVerifySpy.mockReturnValue({ sub: 'sub' });
loginSpy.mockImplementation(() => { });
validateAccessTokenSpy.mockResolvedValue('tokenstring');
it('short circuits with invalid auth token', async () => {
const authorization = 'bearer ';

problemSendSpy.mockImplementation(() => { });
config.has
.mockReturnValueOnce(false) // basicAuth.enabled
.mockReturnValueOnce(true) // keycloak.enabled
.mockReturnValueOnce(false); // keycloak.publicKey
.mockReturnValueOnce(true); // keycloak.publicKey
config.get
.mockReturnValueOnce(spki) // keycloak.publicKey
.mockReturnValueOnce(serverUrl) // keycloak.serverUrl
.mockReturnValueOnce(realm); // keycloak.realm
req.get.mockReturnValueOnce(authorization);

await mw.currentUser(req, res, next);

expect(req.currentUser).toBeTruthy();
expect(req.currentUser).toHaveProperty('authType', AuthType.BEARER);
expect(req.currentUser).toHaveProperty('tokenPayload');
expect(req.currentUser).toBeFalsy();
expect(req.get).toHaveBeenCalledTimes(1);
expect(req.get).toHaveBeenCalledWith('Authorization');
expect(config.has).toHaveBeenCalledTimes(3);
expect(config.has).toHaveBeenNthCalledWith(1, 'basicAuth.enabled');
expect(config.has).toHaveBeenNthCalledWith(2, 'keycloak.enabled');
expect(config.has).toHaveBeenNthCalledWith(3, 'keycloak.publicKey');
expect(validateAccessTokenSpy).toHaveBeenCalledTimes(1);
expect(validateAccessTokenSpy).toHaveBeenCalledWith(expect.any(String));
expect(checkBasicAuthSpy).toHaveBeenCalledTimes(0);
expect(jwtVerifySpy).toHaveBeenCalledTimes(0);
expect(loginSpy).toHaveBeenCalledTimes(1);
expect(next).toHaveBeenCalledTimes(1);
expect(next).toHaveBeenCalledWith();
expect(problemSendSpy).toHaveBeenCalledTimes(0);
expect(jwtVerifySpy).toHaveBeenCalledTimes(1);
expect(jwtVerifySpy).toHaveBeenCalledWith(expect.any(String), publicKey, expect.objectContaining({
issuer: `${serverUrl}/realms/${realm}`
}));
expect(loginSpy).toHaveBeenCalledTimes(0);
expect(next).toHaveBeenCalledTimes(0);
expect(problemSendSpy).toHaveBeenCalledTimes(1);
expect(problemSendSpy).toHaveBeenCalledWith(res);
});

it('short circuits without keycloak.publicKey and invalid token', async () => {
const authorization = 'bearer ';

problemSendSpy.mockImplementation(() => { });
validateAccessTokenSpy.mockResolvedValue(false);
it('short circuits without keycloak.publicKey', async () => {
jwtVerifySpy.mockReturnValue({ sub: 'sub' });
loginSpy.mockImplementation(() => { });
config.has
.mockReturnValueOnce(false) // basicAuth.enabled
.mockReturnValueOnce(true) // keycloak.enabled
Expand All @@ -251,8 +247,6 @@ describe('currentUser', () => {
expect(config.has).toHaveBeenNthCalledWith(1, 'basicAuth.enabled');
expect(config.has).toHaveBeenNthCalledWith(2, 'keycloak.enabled');
expect(config.has).toHaveBeenNthCalledWith(3, 'keycloak.publicKey');
expect(validateAccessTokenSpy).toHaveBeenCalledTimes(1);
expect(validateAccessTokenSpy).toHaveBeenCalledWith(expect.any(String));
expect(checkBasicAuthSpy).toHaveBeenCalledTimes(0);
expect(jwtVerifySpy).toHaveBeenCalledTimes(0);
expect(loginSpy).toHaveBeenCalledTimes(0);
Expand Down
4 changes: 2 additions & 2 deletions charts/coms/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: common-object-management-service
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.0.16
version: 0.0.17
kubeVersion: ">= 1.13.0"
description: A microservice for managing access control to S3 Objects
# A chart can be either an 'application' or a 'library' chart.
Expand Down Expand Up @@ -43,6 +43,6 @@ maintainers:
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "0.5.0"
appVersion: "0.6.0"
deprecated: false
annotations: {}
2 changes: 1 addition & 1 deletion charts/coms/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# common-object-management-service

![Version: 0.0.16](https://img.shields.io/badge/Version-0.0.16-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.5.0](https://img.shields.io/badge/AppVersion-0.5.0-informational?style=flat-square)
![Version: 0.0.17](https://img.shields.io/badge/Version-0.0.17-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.6.0](https://img.shields.io/badge/AppVersion-0.6.0-informational?style=flat-square)

A microservice for managing access control to S3 Objects

Expand Down

0 comments on commit 5612188

Please sign in to comment.