diff --git a/README.md b/README.md
index 2f14c04..763fd54 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ curl 'https://test:test@nodered.example.net/basic-auth-demo'
There are three types of configuration:
-1. *Simple*: each node has it’s own credentials. (one credential)
+1. *Simple*: each node has its own credentials. (one credential)
2. *Multiple credentials*: credentials shared with multiple nodes. (multiple credentials)
3. *File with multiple credentials*: the user credentials are stored in a file. (multiple credentials)
@@ -57,6 +57,35 @@ user1:test
user2:$2y$10$5TSZDldoJ7MxDZdtK/SG2O3cwORqLDhHabYlKX9OsM.W/Z/oLwKW6
```
+## Outputs
+
+The first node output is used when the authentication succeeded, and it contains the username:
+
+```json
+"msg": {
+ "realm": "node-red",
+ "username": "alice",
+ "req": "...",
+ "res": "...",
+ "...": "..."
+}
+```
+
+The second node output is used when the authentication failed, and it contains error information:
+
+```json
+"msg": {
+ "realm": "node-red",
+ "username": "",
+ "authError": "Unknown user 'test'",
+ "req": "...",
+ "res": "...",
+ "...": "..."
+}
+```
+
+Both outputs contain the `req` object, which can be inspected for detailed information about HTTP request headers, IP address, URL, etc.
+
## Hints
Here are examples to create hashed passwords:
diff --git a/examples/flow.json b/examples/flow.json
index 033ba30..ad0a2bb 100644
--- a/examples/flow.json
+++ b/examples/flow.json
@@ -5,15 +5,18 @@
"z": "d9a661f4.ef966",
"name": "",
"file": "",
- "cred": "",
+ "multiple": "",
"realm": "node-red",
"username": "test",
"password": "$2y$10$5TSZDldoJ7MxDZdtK/SG2O3cwORqLDhHabYlKX9OsM.W/Z/oLwKW6",
- "x": 1040,
+ "x": 1030,
"y": 100,
"wires": [
[
"6ef8ccf5965075f1"
+ ],
+ [
+ "a230b772edd4ea9c"
]
]
},
@@ -26,7 +29,7 @@
"method": "get",
"upload": false,
"swaggerDoc": "",
- "x": 810,
+ "x": 790,
"y": 100,
"wires": [
[
@@ -42,7 +45,7 @@
"statusCode": "",
"headers": {},
"x": 1370,
- "y": 100,
+ "y": 80,
"wires": []
},
{
@@ -56,12 +59,29 @@
"syntax": "plain",
"template": "
\nHello world!\n
\n",
"output": "str",
- "x": 1220,
- "y": 100,
+ "x": 1240,
+ "y": 80,
"wires": [
[
"57b04097f0b0647d"
]
]
+ },
+ {
+ "id": "a230b772edd4ea9c",
+ "type": "debug",
+ "z": "d9a661f4.ef966",
+ "name": "Log error",
+ "active": true,
+ "tosidebar": true,
+ "console": false,
+ "tostatus": false,
+ "complete": "true",
+ "targetType": "full",
+ "statusVal": "",
+ "statusType": "auto",
+ "x": 1240,
+ "y": 120,
+ "wires": []
}
]
diff --git a/images/flow.png b/images/flow.png
index efd9452..88baf23 100644
Binary files a/images/flow.png and b/images/flow.png differ
diff --git a/nodes/http-auth.html b/nodes/http-auth.html
index cfa545b..8becc6a 100644
--- a/nodes/http-auth.html
+++ b/nodes/http-auth.html
@@ -3,7 +3,7 @@
RED.nodes.registerType('http-basic-auth', {
category: 'function',
inputs: 1,
- outputs: 1,
+ outputs: 2,
defaults: {
name: { value: '' },
file: { value: '', type: 'http-basic-auth-file', required: false },
@@ -77,7 +77,7 @@
Config
There are three types of configuration:
- - Simple: each node has it’s own credentials. (one credential)
+ - Simple: each node has its own credentials. (one credential)
- Multiple credentials: credentials shared with multiple nodes. (multiple credentials)
- File with multiple credentials: the user credentials are stored in a file. (multiple credentials)
diff --git a/nodes/http-auth.js b/nodes/http-auth.js
index e820737..8c59c8e 100644
--- a/nodes/http-auth.js
+++ b/nodes/http-auth.js
@@ -25,20 +25,36 @@ function basicAuth(authStr, node, msg) {
const values = Buffer.from(authStr, 'base64').toString().split(':');
const username = values[0];
const password = values[1];
+
+ if (username == '' || username == '') {
+ msg.authError = 'Invalid format for credentials!';
+ unAuth(node, msg);
+ return;
+ }
+
const user = node.httpauthconf.getUser(username);
- if (user !== null && passwordCompare(password, user.password)) {
- node.send(msg);
- } else {
+ if (user === null) {
+ msg.authError = `Unknown user '${username}'!`;
unAuth(node, msg);
+ return;
}
+
+ if (!passwordCompare(password, user.password)) {
+ msg.authError = `Invalid credentials for user '${username}'!`;
+ unAuth(node, msg);
+ return;
+ }
+
+ msg.username = user.username;
+ node.send([msg, null]);
}
-function unAuth(node, msg, stale) {
+function unAuth(node, msg) {
const res = msg.res._res || msg.res; // Resolves deprecates warning messages.
res.set('WWW-Authenticate', 'Basic realm="' + node.httpauthconf.realm + '"');
- res.type('text/plain');
- res.status(401).send('401 Unauthorized');
+ res.sendStatus(401);
+ node.send([null, msg]);
}
module.exports = function (RED) {
@@ -76,10 +92,14 @@ module.exports = function (RED) {
this.httpauthconf = {};
this.httpauthconf.src = src;
this.httpauthconf.getUser = getUser;
+ this.httpauthconf.realm = config.realm;
const node = this;
this.on('input', function (msg) {
+ msg.realm = node.httpauthconf.realm;
+ msg.username = '';
+
const header = msg.req.get('Authorization');
const authType = header ? header.match(/^\w+\b/)[0] : null;
@@ -87,6 +107,7 @@ module.exports = function (RED) {
const authStr = header.substring(authType.length).trim();
basicAuth(authStr, node, msg);
} else {
+ msg.authError = 'Missing Basic Auth headers!';
unAuth(node, msg);
}
});
diff --git a/package-lock.json b/package-lock.json
index 6c434bd..ba0b657 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,9 +16,9 @@
"eslint-config-standard": "^17.1.0",
"eslint-plugin-html": "^7.1.0",
"eslint-plugin-import": "^2.28.1",
- "eslint-plugin-n": "^16.1.0",
+ "eslint-plugin-n": "^16.2.0",
"eslint-plugin-promise": "^6.1.1",
- "node-red-contrib-mock-cli": "^1.4.0"
+ "node-red-contrib-mock-cli": "^1.4.1"
},
"engines": {
"node": ">=12"
@@ -578,9 +578,9 @@
"dev": true
},
"node_modules/define-data-property": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.0.tgz",
- "integrity": "sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz",
+ "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==",
"dev": true,
"dependencies": {
"get-intrinsic": "^1.2.1",
@@ -2100,9 +2100,9 @@
}
},
"node_modules/node-red-contrib-mock-cli": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/node-red-contrib-mock-cli/-/node-red-contrib-mock-cli-1.4.0.tgz",
- "integrity": "sha512-z5HE5hTZiZ1lcariugJWhhF2YJpTSnIYWjB6PK/WO1fgtx8iumRw8LHrW2wLoD0QB0CA/laaAymSwZVLjRxBmQ==",
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/node-red-contrib-mock-cli/-/node-red-contrib-mock-cli-1.4.1.tgz",
+ "integrity": "sha512-O6eP5Iz1YRr6CC8ul/6hIS9Heo0RFNSHrmpWIOUn8CHnHX4NMStmdG8Iz8Sn4KlKIvWqynHhfiOl+GEzcTzmtg==",
"dev": true,
"engines": {
"node": ">=8"
diff --git a/package.json b/package.json
index 9efcbb4..df4b9f8 100644
--- a/package.json
+++ b/package.json
@@ -53,9 +53,9 @@
"eslint-config-standard": "^17.1.0",
"eslint-plugin-html": "^7.1.0",
"eslint-plugin-import": "^2.28.1",
- "eslint-plugin-n": "^16.1.0",
+ "eslint-plugin-n": "^16.2.0",
"eslint-plugin-promise": "^6.1.1",
- "node-red-contrib-mock-cli": "^1.4.0"
+ "node-red-contrib-mock-cli": "^1.4.1"
},
"scripts": {
"start": "node ./index.js",