-
Notifications
You must be signed in to change notification settings - Fork 0
/
authenticationServer.js
142 lines (122 loc) · 3.63 KB
/
authenticationServer.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
const express = require('express');
const bodyParser = require('body-parser');
const mqttWildcard = require('mqtt-wildcard');
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
const port = 8080;
const users = [
{
login: 'testUser',
password: 'testPassword',
acls: [
{
topic: 'users/testUser/#',
permissions: [ 'read', 'write', 'subscribe' ] // Can be "read", "write" or "subscribe"
},
{
topic: 'global',
permissions: [ 'write', 'read', 'subscribe' ]
}
]
},
{
login: 'testUser2',
password: 'testPassword2',
acls: [
{
topic: 'users/testUser2/#',
permissions: [ 'read', 'write', 'subscribe' ] // Can be "read", "write" or "subscribe"
},
{
topic: 'global',
permissions: [ 'write', 'read', 'subscribe' ]
}
]
}
];
// Define POST route "/user"
// This route will be used to check the user login and password
app.post(
'/user',
(req, res) => {
// Log the route call
console.log(new Date(), req.originalUrl, req.body);
// Mosquitto sends us the username, password and clientid.
const { username, password, clientid } = req.body;
// We try to find the user
const userFound = users.find(user => user.login === username && user.password === password);
// We send a 200 if the authentication succeed or 401 else
if (userFound) {
return res.status(200).send();
}
else {
console.warn(`⛔️ User ${username} doesn't exist or password is incorrect`);
return res.status(401).send();
}
}
);
// Define POST route "/acls"
// This route will be used to check the topic ACL
app.post(
'/acls',
(req, res) => {
// Log the route call
console.log(new Date(), req.originalUrl, req.body);
const { username, clientid, topic, acc } = req.body;
// "acc" represents the type of access required by the client to this topic
// - 1: read
// - 2: write
// - 3: read and write
// - 4: subscribe
const accToPermissions = {
1: [ 'read' ],
2: [ 'write' ],
3: [ 'read', 'write' ],
4: [ 'subscribe' ]
};
const allowed = users.find(user => {
if (user.login !== username) {
return false;
}
const aclValidated = user.acls.find(
acl => mqttWildcard(topic, acl.topic) !== null
&& accToPermissions[acc].every(v => acl.permissions.includes(v))
);
return aclValidated;
});
if (allowed) {
return res.status(200).send();
}
else {
console.warn(`⛔️ Error when checking ACL for user ${username} on topic ${topic} with permission "${acc}"`);
return res.status(401).send();
}
}
);
// Start Express server
const server = app.listen(port);
// You'll see this log directly on your Stackhero's console
console.log('🎉 The app has just start!');
// Handle termination signal
// When you'll push your code to Stackhero, we'll send a termination signal (SIGTERM).
// The goal is to let you close cleanly connections from Express, connections to databases etc...
process.on('SIGTERM', () => {
// You'll see this log directly on your Stackhero's console
console.info('😯 SIGTERM signal received.');
// Close the server and all connections
server.close(
err => {
if (err) {
// You'll see this log directly on your Stackhero's console
console.error(err);
process.exit(1);
}
else {
// You'll see this log directly on your Stackhero's console
console.log('👋 Exit the app with status code 0');
process.exit(0);
}
}
);
});