Skip to content

Commit 9467292

Browse files
author
Robin Gottfried
committed
docker support for external key manager and verbosity configuration
1 parent 32bedeb commit 9467292

File tree

7 files changed

+77
-20
lines changed

7 files changed

+77
-20
lines changed

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ FROM node:13-alpine
33
ENV ADDRESS 0.0.0.0
44
ENV PORT 8090
55
ENV KEY_SERVER_URL ''
6+
ENV KEY_SERVER_IGNORE_FOR_HOSTNAMES ''
7+
ENV VERBOSITY 3
68

79
# Create app directory
810
WORKDIR /usr/src/app

config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ let CONFIG = {
1414
// empty value means no authenticator (allow any key to connect)
1515
// http(s)://... - a url for key-master APIs
1616
keyServerUrl: val('KEY_SERVER_URL', undefined),
17+
keyServerIgoreForHostnames: val('KEY_SERVER_IGNORE_FOR_HOSTNAMES', undefined),
1718
},
1819
client: {
1920
key: val('KEY', 'client-1'),

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "karmen_ws",
3-
"version": "1.0.1",
3+
"version": "1.0.2",
44
"description": "",
55
"main": "client",
66
"scripts": {

server/api-authenticator.js

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
'use strict';
22
// vim: ft=javascript tabstop=2 softtabstop=2 expandtab shiftwidth=2
33
const http = require('http'),
4-
path = require('path');
4+
path = require('path'),
5+
{ debug, info } = require('../lib/logger');
56

67
class InvalidKey extends Error { }
78
exports.InvalidKey = InvalidKey;
@@ -30,11 +31,35 @@ function fetchJson(url, options) {
3031
}
3132

3233

33-
exports.getAuthenticator = function getAuthenticator(authenticatorUri) {
34+
exports.getAuthenticator = function getAuthenticator(authenticatorUri, privateHostnamesToPass) {
3435
if (!authenticatorUri) throw new Error(`authenticatorUri is a required parameter`);
35-
return (key) => {
36-
return fetchJson(
37-
path.join(authenticatorUri, '/key', key)
38-
);
36+
if (privateHostnamesToPass) {
37+
if (typeof privateHostnamesToPass == 'string') privateHostnamesToPass = privateHostnamesToPass.split(',');
38+
if (!(privateHostnamesToPass instanceof Set)) privateHostnamesToPass = new Set(privateHostnamesToPass);
39+
debug(`Set hosts to skip auth: ${[...privateHostnamesToPass].join(', ')}.`);
40+
} else {
41+
privateHostnamesToPass = null;
42+
}
43+
return (key, request) => {
44+
let result;
45+
if (privateHostnamesToPass && privateHostnamesToPass.has(request.headers.host)) {
46+
debug(`Passing user with key ${key}, hostname '${request.headers.host}' matches one of ${[...privateHostnamesToPass].join(',')}.`);
47+
result = Promise.resolve({authenticated: false});
48+
} else {
49+
debug(`Authenticating ${key} from ${request.headers.host} to ${authenticatorUri}.`);
50+
result = fetchJson(
51+
path.join(authenticatorUri, '/key', key)
52+
)
53+
.then((response) => {
54+
debug(`Key ${key} authenticated.`);
55+
return {authenticated: true, token: response}
56+
})
57+
.catch((err) => {
58+
debug(`Key ${key} authentication failed: ${err}.`);
59+
throw err;
60+
});
61+
62+
}
63+
return result;
3964
}
4065
}

server/index.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ const { getAuthenticator } = require('./api-authenticator');
2121
`*
2222
*/
2323

24-
function Server(keyServerUrl) {
24+
function Server({keyServerUrl=null, keyServerIgoreForHostnames=null}={}) {
2525

2626
let authenticate;
2727
if (keyServerUrl) {
28-
authenticate = getAuthenticator(keyServerUrl);
28+
authenticate = getAuthenticator(keyServerUrl, keyServerIgoreForHostnames);
2929
}
3030

3131
this.clientsManager = new ClientsManager({
@@ -86,7 +86,9 @@ if (require.main == module) {
8686
debug(`
8787
config: ${server_host}:${server_port}
8888
`);
89-
90-
new Server(config.server.keyServerUrl).listen(server_port, server_host);
89+
new Server({
90+
keyServerUrl: config.server.keyServerUrl,
91+
keyServerIgoreForHostnames: config.server.keyServerIgoreForHostnames}
92+
).listen(server_port, server_host);
9193

9294
}

tests/authenticator.test.js

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,59 @@
11
// vim: ft=javascript tabstop=2 softtabstop=2 expandtab shiftwidth=2
22
const test = require('ava'),
33
nock = require('nock'),
4-
authenticator = require('../server/api-authenticator');
4+
authenticator = require('../server/api-authenticator'),
5+
fakeRequest = {headers: {host: 'http://example.com'}};
56

67
test('valid key passes', t => {
78
const key = 'some-secret-key',
89
authServerUri = 'http://example.com',
910
response = {sub: 'userinfo', iss: 'iss'};
10-
nock(`${authServerUri}`).get(`/key/${key}`).reply(200, response);
11+
nock(authServerUri).get(`/key/${key}`).reply(200, response);
1112
const authenticate = authenticator.getAuthenticator(authServerUri);
12-
return authenticate(key).then(clientInfo => {
13-
t.deepEqual(clientInfo, response);
13+
return authenticate(key, fakeRequest).then(clientInfo => {
14+
t.deepEqual(clientInfo, {authenticated: true, token: response});
1415
});
1516
});
1617

18+
test('auth is skipped for selected hostnames even when the key is invalid', t => {
19+
const key = 'some-secret-key',
20+
authServerUri = 'http://example.com',
21+
authenticate = authenticator.getAuthenticator(authServerUri, 'a.example.com,b.example.com'),
22+
request = {headers: {host: 'b.example.com'}},
23+
promises = [];
24+
25+
promises.push(
26+
authenticate(key, request).then(clientInfo => {
27+
t.is(clientInfo.authenticated, false);
28+
})
29+
);
30+
// nock(authServerUri).get(`/key/${key}`).reply(422);
31+
// promises.push(
32+
// authenticate(key, fakeRequest).catch((err) => {
33+
// t.assert(err instanceof authenticator.InvalidKey)
34+
// })
35+
// );
36+
return Promise.all(promises);
37+
});
38+
1739
test('fail on invalid key', t => {
1840
const key = 'some-secret-key',
1941
authServerUri = 'http://example.com';
2042
nock(`${authServerUri}`).get(`/key/${key}`).reply(422);
21-
const authenticate = authenticator.getAuthenticator(authServerUri);
22-
return authenticate(key).catch((err) => {
43+
const authenticate = authenticator.getAuthenticator(authServerUri, 'a.example.com,b.example.com');
44+
return authenticate(key, fakeRequest).catch((err) => {
2345
t.assert(err instanceof authenticator.InvalidKey)
2446
});
2547
});
2648

2749

50+
2851
test('authentication rejected on server error', t => {
2952
const key = 'some-secret-key',
3053
authServerUri = 'http://example.com';
3154
nock(`${authServerUri}`).get(`/key/${key}`).reply(500);
3255
const authenticate = authenticator.getAuthenticator(authServerUri);
33-
return authenticate(key).catch((err) => {
56+
return authenticate(key, fakeRequest).catch((err) => {
3457
t.assert(!(err instanceof authenticator.InvalidKey))
3558
});
3659
});

tests/server-api-authentication.test.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ test('connection is closed with wrong key', t => {
1414
return client.connect(`ws+unix://${socketFilePath}:`, clientConfig)
1515
.catch((err) => {
1616
t.is(err.code, 'ECONNRESET');
17-
});
17+
})
1818
});
1919

2020
test('connection accepted with a valid key', t => {
@@ -34,8 +34,12 @@ test.before(t => {
3434
invalidKey = 'some-invalid-key',
3535
validKeyResponse = {sub: 'userinfo', iss: 'iss'},
3636
authServerUri = 'http://authserveruri.example.com',
37+
keyServerIgoreForHostnames = 'a.example.com,b.example.com',
3738
Server = require('../server'),
38-
server = new Server(authServerUri);
39+
server = new Server({
40+
keyServerUrl: authServerUri,
41+
keyServerIgoreForHostnames: keyServerIgoreForHostnames,
42+
});
3943

4044
nock(`${authServerUri}`).persist().get(`/key/${validKey}`).reply(200, validKeyResponse);
4145
nock(`${authServerUri}`).persist().get(`/key/${invalidKey}`).reply(422);

0 commit comments

Comments
 (0)