Skip to content

Commit 39e539d

Browse files
Miel Vander SandeRubenVerborgh
authored andcommitted
Created WebID extension
1 parent 1d3268f commit 39e539d

File tree

2 files changed

+126
-1
lines changed

2 files changed

+126
-1
lines changed
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*! @license MIT ©2016 Miel Vander Sande - Ghent University / iMinds */
2+
/* A WebIDControllerExtension extends Triple Pattern Fragments responses with WebID authentication. */
3+
4+
var http = require('http'),
5+
lru = require('lru-cache'),
6+
parseCacheControl = require('parse-cache-control'),
7+
N3 = require('n3'),
8+
N3Util = N3.Util,
9+
Util = require('../Util');
10+
11+
var CERT_NS = 'http://www.w3.org/ns/auth/cert#';
12+
13+
// Creates a new WebIDControllerExtension
14+
function WebIDControllerExtension(settings) {
15+
if (!(this instanceof WebIDControllerExtension))
16+
return new WebIDControllerExtension(settings);
17+
18+
this._cache = lru(50);
19+
this._protocol = settings.protocol || 'http';
20+
}
21+
22+
// Add WebID Link headers
23+
WebIDControllerExtension.prototype._handleRequest = function (request, response, next, settings) {
24+
// Get WebID from certificate
25+
if (this._protocol !== 'https') // This WebID implementation requires HTTPS
26+
return next();
27+
28+
var self = this,
29+
certificate = request.connection.getPeerCertificate();
30+
31+
if (!(certificate.subject && certificate.subject.subjectAltName))
32+
return this._handleNotAcceptable(request, response, next);
33+
34+
var webID = certificate.subject.subjectAltName.replace('uniformResourceIdentifier:', '');
35+
this._verifyWebID(webID, certificate.modulus, parseInt(certificate.exponent, 16),
36+
function (verified) {
37+
console.log("WebID verified: ", verified);
38+
39+
if (!verified)
40+
return self._handleNotAcceptable(request, response, next);
41+
42+
next();
43+
});
44+
};
45+
46+
// Verify webID
47+
WebIDControllerExtension.prototype._verifyWebID = function (webID, modulus, exponent, callback) {
48+
//request & parse
49+
var parser = N3.Parser(),
50+
candidates = {}, verified = false;
51+
52+
parser.parse(processTriple);
53+
54+
function processTriple(error, triple, prefixes) {
55+
if (error)
56+
console.error('Cannot parse WebID: ' + error);
57+
else if (triple) {
58+
switch (triple.predicate) {
59+
case CERT_NS + 'modulus':
60+
var webidModulus = N3Util.getLiteralValue(triple.object);
61+
// Apply parsing method by nodejs
62+
webidModulus = webidModulus.slice(webidModulus.indexOf('00:') === 0 ? 3 : 0).replace(/:/g, '').toUpperCase();
63+
64+
if (modulus === webidModulus) {
65+
console.log('WebID modulus verified');
66+
if (candidates[triple.subject] && candidates[triple.subject] === exponent)
67+
verified = true;
68+
else
69+
candidates[triple.subject] = webidModulus;
70+
} else console.log('WebID modulus mismatch: %s (webid) <> %s (cert)', webidModulus, modulus);
71+
break;
72+
case CERT_NS + 'exponent':
73+
var webidExponent = parseInt(N3Util.getLiteralValue(triple.object));
74+
75+
if (webidExponent === exponent) {
76+
console.log('WebID exponent verified');
77+
if (candidates[triple.subject] && candidates[triple.subject] === modulus)
78+
verified = true;
79+
else
80+
candidates[triple.subject] = webidExponent;
81+
} else console.log('WebID exponent mismatch: %s (webid) <> %s (cert)', webidExponent, exponent);
82+
break;
83+
}
84+
} else callback(verified);
85+
}
86+
87+
// Try to get WebID from cache
88+
var webIDFile = this._cache.get(webID);
89+
90+
if (webIDFile) {
91+
parser.addChunk(webIDFile);
92+
parser.end();
93+
} else {
94+
var req = http.request(webID, function(res) {
95+
res.setEncoding('utf8');
96+
var response = "";
97+
98+
res.on('data', function (data) {
99+
parser.addChunk(data);
100+
response += data;
101+
});
102+
103+
res.on('end', function () {
104+
parser.end();
105+
var cacheControl = parseCacheControl(res.getHeader("Cache-Control"));
106+
this._cache.set(webID, response, cacheControl['max-age']);
107+
});
108+
});
109+
110+
req.on('error', function(e) {
111+
console.log('Problem with request: ' + e.message);
112+
callback(false);
113+
});
114+
115+
req.end();
116+
}
117+
};
118+
119+
WebIDControllerExtension.prototype._handleNotAcceptable = function (request, response, next) {
120+
response.writeHead(401, { 'Content-Type': Util.MIME_PLAINTEXT });
121+
response.end('Access to ' + request.url + ' is not allowed, WebID verification failed.');
122+
};
123+
124+
module.exports = WebIDControllerExtension;

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
},
3737
"optionalDependencies": {
3838
"hdt": "^1.3.0",
39-
"access-log": "^0.3.9"
39+
"access-log": "^0.3.9",
40+
"parse-cache-control": "^1.0.1"
4041
},
4142
"devDependencies": {
4243
"chai": "^3.5.0",

0 commit comments

Comments
 (0)