@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 +16 -0
- package/README.md +25 -2
- package/package.json +5 -5
- package/src/container.js +4 -4
- package/src/helpers/jwt/passport.helper.js +1 -1
- package/src/loaders/documentation.loader.js +8 -2
- package/src/middlewares/{auth.middleware.js → authentication.middleware.js} +0 -0
- package/src/middlewares/{permissions.middleware.js → authorisation.middleware.js} +1 -1
- package/src/middlewares/error.middleware.js +5 -1
- package/src/services/server.service.js +4 -2
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
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
49
|
-
"@apolitical/testing": "
|
|
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.
|
|
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
|
|
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
|
-
|
|
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('
|
|
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
|
-
|
|
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,
|
|
26
|
+
app.use(DOCUMENTATION, authorisationMiddleware(), hostMiddleware, serve, setup());
|
|
21
27
|
}
|
|
22
28
|
childLogger.debug('Finished');
|
|
23
29
|
};
|
|
File without changes
|
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
78
|
+
authentication: authenticationMiddleware,
|
|
79
|
+
authorisation: authorisationMiddleware,
|
|
78
80
|
},
|
|
79
81
|
};
|
|
80
82
|
};
|