@apolitical/server 2.0.0-beta.3 → 2.0.1-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.0.1] - 2022-01-21
9
+ ### Added
10
+ - Correlation when logging from error middleware
11
+ - Dynamically update documentation to set the host
12
+
13
+ ## [2.0.0] - 2022-01-20
14
+ ### Added
15
+ - Authorisation middleware
16
+ - New logging middleware for production (based on Google Winston)
17
+ ### Changed
18
+ - Updated dependencies
19
+ - Upgraded Node.js version
20
+ - Revamped GitLab pipelines
21
+ ### Removed
22
+ - Unused logger helper
23
+
8
24
  ## [1.5.2] - 2021-10-18
9
25
  ### Changed
10
26
  - Allow cors options to be passed in as params on start
package/README.md CHANGED
@@ -75,7 +75,7 @@ For usage examples, see [example.spec.js](tests/../test/integration/example.spec
75
75
 
76
76
  ### JWT authentication
77
77
 
78
- The __Apolitical Server__ has integrated JSON Web Token (JWT) functionality. The JWT authentication layer is intended to be used to secure endpoints without sessions.
78
+ The __Apolitical Server__ has integrated JSON Web Token (JWT) functionality. The JWT authentication layer is intended to be used to secure endpoints from requests without a valid session token.
79
79
 
80
80
  ```js
81
81
  // The JWT strategy session secret
@@ -85,7 +85,7 @@ function appLoader(app) {
85
85
  // Setup the Apolitical JWT strategy
86
86
  jwt.apolitical.setup(SESSION_SECRET);
87
87
  // Use the authentication middleware to reject unauthorised requests
88
- app.use(middlewares.auth());
88
+ app.use(middlewares.authentication());
89
89
  // The example endpoint is now protected
90
90
  app.get('/example', exampleController);
91
91
  }
@@ -102,6 +102,29 @@ The JWT authentication must be defined with two steps:
102
102
 
103
103
  For usage examples, see [jwt.apolitical.spec.js](tests/../test/integration/jwt.apolitical.spec.js) test cases.
104
104
 
105
+ ### JWT authorisation
106
+
107
+ The __Apolitical Server__ has integrated JSON Web Token (JWT) functionality. The JWT authorisation layer is intended to be used to protect endpoints from request with session token without the right permissions.
108
+
109
+ ```js
110
+ // The JWT strategy session secret
111
+ const SESSION_SECRET = 'hello';
112
+
113
+ function appLoader(app) {
114
+ // Setup the Apolitical JWT strategy
115
+ jwt.apolitical.setup(SESSION_SECRET);
116
+ // Use the authentication middleware to reject unauthorised requests
117
+ app.use(middlewares.authentication());
118
+ // The example endpoint can only be accessed by admin users
119
+ app.get('/example', middlewares.authorisation(), exampleController);
120
+ }
121
+
122
+ // Start the server
123
+ start({ appLoader, port: 3000 });
124
+ ```
125
+
126
+ As before, the Apolitical token will be validated by the `authentication` middleware, and then, the `authorisation` middleware will check that the `role` property on the session token to determine the permissions.
127
+
105
128
  ### Error handling
106
129
 
107
130
  The __Apolitical Server__ comes with a default error handler so you don’t need to write your own to get started. It’s important to ensure that your server catches all errors that occur while running your business logic. For more info see [express error handling](https://expressjs.com/en/guide/error-handling.html).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apolitical/server",
3
- "version": "2.0.0-beta.3",
3
+ "version": "2.0.1-beta.3",
4
4
  "description": "Node.js module to encapsulate Apolitical's express server setup",
5
5
  "author": "Apolitical Group Limited <engineering@apolitical.co>",
6
6
  "license": "MIT",
@@ -24,7 +24,7 @@
24
24
  "Node Modules"
25
25
  ],
26
26
  "dependencies": {
27
- "@apolitical/logger": "2.0.0-beta.7",
27
+ "@apolitical/logger": "2.0.0",
28
28
  "@cloudnative/health-connect": "2.1.0",
29
29
  "awilix": "6.0.0",
30
30
  "body-parser": "1.19.1",
@@ -45,13 +45,13 @@
45
45
  "swagger-ui-express": "4.3.0"
46
46
  },
47
47
  "devDependencies": {
48
- "@apolitical/eslint-config": "1.0.0-beta.0",
49
- "@apolitical/testing": "0.0.4",
48
+ "@apolitical/eslint-config": "1.0.1",
49
+ "@apolitical/testing": "1.0.1",
50
50
  "audit-ci": "5.1.2",
51
51
  "husky": "7.0.4",
52
52
  "jest": "27.4.7",
53
53
  "jest-junit": "13.0.0",
54
- "lint-staged": "12.2.0",
54
+ "lint-staged": "12.2.2",
55
55
  "mock-jwks": "1.0.1",
56
56
  "nock": "13.2.2"
57
57
  },
package/src/container.js CHANGED
@@ -37,11 +37,11 @@ const middlewaresLoader = require('./loaders/middlewares.loader');
37
37
  const probesLoader = require('./loaders/probes.loader');
38
38
  const staticLoader = require('./loaders/static.loader');
39
39
  // Middleware
40
- const authMiddleware = require('./middlewares/auth.middleware');
40
+ const authenticationMiddleware = require('./middlewares/authentication.middleware');
41
+ const authorisationMiddleware = require('./middlewares/authorisation.middleware');
41
42
  const jwtApoliticalMiddleware = require('./middlewares/jwt/apolitical.middleware');
42
43
  const jwtAuth0Middleware = require('./middlewares/jwt/auth0.middleware');
43
44
  const errorMiddleware = require('./middlewares/error.middleware');
44
- const permissionsMiddleware = require('./middlewares/permissions.middleware');
45
45
  // Services
46
46
  const jwtService = require('./services/jwt.service');
47
47
  const serverService = require('./services/server.service');
@@ -85,11 +85,11 @@ container.register({
85
85
  probesLoader: asFunction(probesLoader).singleton(),
86
86
  staticLoader: asFunction(staticLoader).singleton(),
87
87
  // Middlewares
88
- authMiddleware: asFunction(authMiddleware).singleton(),
88
+ authenticationMiddleware: asFunction(authenticationMiddleware).singleton(),
89
+ authorisationMiddleware: asFunction(authorisationMiddleware).singleton(),
89
90
  jwtApoliticalMiddleware: asFunction(jwtApoliticalMiddleware).singleton(),
90
91
  jwtAuth0Middleware: asFunction(jwtAuth0Middleware).singleton(),
91
92
  errorMiddleware: asFunction(errorMiddleware).singleton(),
92
- permissionsMiddleware: asFunction(permissionsMiddleware).singleton(),
93
93
  // Services
94
94
  jwtService: asFunction(jwtService).singleton(),
95
95
  serverService: asFunction(serverService).singleton(),
@@ -11,7 +11,7 @@ module.exports = ({ passport, passportJwt, logger, config }) => {
11
11
  if (req && req.cookies && req.cookies[COOKIE_KEY]) {
12
12
  result = req.cookies[COOKIE_KEY];
13
13
  } else {
14
- childLogger.debug('No Apolitical auth cookie');
14
+ childLogger.debug('Cannot find Apolitical token (cookie)');
15
15
  }
16
16
  childLogger.debug('Finished');
17
17
  return result;
@@ -5,19 +5,25 @@ module.exports = ({
5
5
  config,
6
6
  logger,
7
7
  swaggerUi: { serve, setup },
8
- permissionsMiddleware,
8
+ authorisationMiddleware,
9
9
  }) => {
10
10
  const { DOCUMENTATION } = config.ENDPOINTS;
11
11
 
12
12
  return function load(app, { swaggerDocument }) {
13
13
  const childLogger = logger.where(__filename, 'load');
14
14
  childLogger.debug('Started');
15
+ // Internal middleware to dynamically set the host
16
+ function hostMiddleware(req, res, next) {
17
+ swaggerDocument.host = req.get('host');
18
+ req.swaggerDoc = swaggerDocument;
19
+ next();
20
+ }
15
21
  // Load document endpoint
16
22
  if (swaggerDocument) {
17
23
  // Redirection to documentation
18
24
  app.use(`${DOCUMENTATION}index.html`, (req, res) => res.redirect(MOVED_PERMANENTLY, DOCUMENTATION));
19
25
  // Documentation express setup
20
- app.use(DOCUMENTATION, permissionsMiddleware(), serve, setup(swaggerDocument));
26
+ app.use(DOCUMENTATION, authorisationMiddleware(), hostMiddleware, serve, setup());
21
27
  }
22
28
  childLogger.debug('Finished');
23
29
  };
@@ -5,7 +5,7 @@ module.exports = ({ logger, serverError: { Forbidden }, config }) => {
5
5
  // Define external options
6
6
  return ({ myselfSource = null, myselfTarget = null, allowNonAdmin = false } = {}) => {
7
7
  // Return middleware handler
8
- return async function handler(req, res, next) {
8
+ return function handler(req, res, next) {
9
9
  const childLogger = logger.where(__filename, 'handler');
10
10
  childLogger.debug('Started');
11
11
  let isNotMyselfSlug = false;
@@ -38,7 +38,11 @@ module.exports =
38
38
  errors = ['unknown-error'];
39
39
  }
40
40
  }
41
- errorLogger.warn(message, { errors });
41
+ if (req.log) {
42
+ req.log.warn(message, { errors });
43
+ } else {
44
+ errorLogger.warn(message, { errors });
45
+ }
42
46
  if (redirectURL) {
43
47
  res.redirect(TEMPORARY_REDIRECT, `${redirectURL}?errorMessage=${encodeURI(message)}`);
44
48
  } else {
@@ -6,7 +6,8 @@ module.exports = ({
6
6
  logger,
7
7
  documentationLoader,
8
8
  loggerLoader,
9
- authMiddleware,
9
+ authenticationMiddleware,
10
+ authorisationMiddleware,
10
11
  errorMiddleware,
11
12
  middlewaresLoader,
12
13
  probesLoader,
@@ -74,7 +75,8 @@ module.exports = ({
74
75
  jwt: jwtService,
75
76
  errors: serverError,
76
77
  middlewares: {
77
- auth: authMiddleware,
78
+ authentication: authenticationMiddleware,
79
+ authorisation: authorisationMiddleware,
78
80
  },
79
81
  };
80
82
  };