Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 27 additions & 9 deletions lib/acl-checker.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,40 @@ class ACLChecker {
const aclFile = rdf.sym(acl.acl)
const agent = user ? rdf.sym(user) : null
const modes = [ACL(mode)]
const agentOrigin = this.agentOrigin ? rdf.sym(this.agentOrigin) : null
const trustedOrigins = this.trustedOrigins ? this.trustedOrigins.map(trustedOrigin => rdf.sym(trustedOrigin)) : null
const accessDenied = aclCheck.accessDenied(acl.graph, resource, directory, aclFile, agent, modes, agentOrigin, trustedOrigins)
if (accessDenied && this.agentOrigin && this.resourceUrl.origin !== this.agentOrigin) {
this.messagesCached[cacheKey].push(HTTPError(403, accessDenied))
} else if (accessDenied && user) {
const agentOrigin = this.strictOrigin && this.agentOrigin ? rdf.sym(this.agentOrigin) : null
const trustedOrigins = this.strictOrigin && this.trustedOrigins ? this.trustedOrigins.map(trustedOrigin => rdf.sym(trustedOrigin)) : null
const originTrustedModes = agent && agentOrigin ? await this.getOriginTrustedModes(agent, agentOrigin) : []
const accessDenied = aclCheck.accessDenied(acl.graph, resource, directory, aclFile, agent, modes, agentOrigin, trustedOrigins, originTrustedModes)

if (accessDenied && user) {
this.messagesCached[cacheKey].push(HTTPError(403, accessDenied))
} else if (accessDenied && !user) {
this.messagesCached[cacheKey].push(HTTPError(401, 'Unauthenticated'))
} else if (accessDenied) {
this.messagesCached[cacheKey].push(HTTPError(401, accessDenied))
this.messagesCached[cacheKey].push(HTTPError(401, 'Unauthenticated'))
}
this.aclCached[cacheKey] = Promise.resolve(!accessDenied)
return this.aclCached[cacheKey]
}

async getOriginTrustedModes (agent, agentOrigin) {
let agentStore
try {
this.requests[agent.uri] = this.requests[agent.uri] || this.fetch(agent.uri)
agentStore = await this.requests[agent.uri]
} catch (err) {
if (err && (err.code === 'ENOENT' || err.status === 404)) {
// If we're unable to resolve the agent, we conclude that origin has no trusted modes
this.requests[agent.uri] = Promise.resolve(null)
return Promise.resolve([])
}
debug(err)
throw err
}
if (agentStore) {
return aclCheck.getTrustedModesForOrigin(agentStore, agent, agentOrigin)
}
return Promise.resolve([])
}

async getError (user, mode) {
const cacheKey = `${mode}-${user}`
this.aclCached[cacheKey] = this.aclCached[cacheKey] || this.can(user, mode)
Expand Down
17 changes: 15 additions & 2 deletions lib/create-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,14 +206,27 @@ function initWebId (argv, app, ldp) {
// without permission by including the credentials set by the Solid server.
app.use((req, res, next) => {
const origin = req.get('origin')
const trustedOrigins = argv.trustedOrigins
const trustedOrigins = ldp.getTrustedOrigins(req)
const userId = req.session.userId
// Exception: allow logout requests from all third-party apps
// such that OIDC client can log out via cookie auth
// TODO: remove this exception when OIDC clients
// use Bearer token to authenticate instead of cookie
// (https://github.com/solid/node-solid-server/pull/835#issuecomment-426429003)
if (!argv.host.allowsSessionFor(userId, origin, trustedOrigins) && !isLogoutRequest(req)) {
//
// Authentication cookies are an optimization:
// instead of going through the process of
// fully validating authentication on every request,
// we go through this process once,
// and store its successful result in a cookie
// that will be reused upon the next request.
// However, that cookie can then be sent by any server,
// even servers that have not gone through the proper authentication mechanism.
// However, if trusted origins are enabled,
// then any origin is allowed to take the shortcut route,
// since malicious origins will be banned at the ACL checking phase.
// https://github.com/solid/node-solid-server/issues/1117
if (!argv.strictOrigin && !argv.host.allowsSessionFor(userId, origin, trustedOrigins) && !isLogoutRequest(req)) {
debug.authentication(`Rejecting session for ${userId} from ${origin}`)
// Destroy session data
delete req.session.userId
Expand Down
6 changes: 1 addition & 5 deletions lib/models/solid-host.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,7 @@ class SolidHost {
const serverHost = getHostName(this.serverUri)
if (originHost === serverHost) return true
if (originHost.endsWith('.' + serverHost)) return true
// Allow the user's own domain
const userHost = getHostName(userId)
if (originHost === userHost) return true
if (trustedOrigins.includes(origin)) return true
return false
return !!trustedOrigins.includes(origin)
}

/**
Expand Down
16 changes: 9 additions & 7 deletions test/integration/acl-oidc-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,11 @@ describe('ACL with WebID+OIDC over HTTP', function () {
})

describe('Origin', function () {
before(function () {
let _error, _response

before(function (done) {
rm('/accounts-acl/tim.localhost/origin/test-folder/.acl')
})

it('should PUT new ACL file', function (done) {
var options = createOptions('/origin/test-folder/.acl', 'user1', 'text/turtle')
options.body = '<#Owner> a <http://www.w3.org/ns/auth/acl#Authorization>;\n' +
' <http://www.w3.org/ns/auth/acl#accessTo> <https://localhost:3456/origin/test-folder/.acl>;\n' +
Expand All @@ -274,13 +274,15 @@ describe('ACL with WebID+OIDC over HTTP', function () {
' <http://www.w3.org/ns/auth/acl#origin> <' + origin1 + '>;\n' +
' <http://www.w3.org/ns/auth/acl#mode> <http://www.w3.org/ns/auth/acl#Write> .\n'
request.put(options, function (error, response, body) {
assert.equal(error, null)
assert.equal(response.statusCode, 201)
_error = error
_response = response
done()
// TODO triple header
// TODO user header
})
})

it('should be no error', () => assert.equal(_error, null))
it('should return 200', () => assert.equal(_response.statusCode, 201))

it('user1 should be able to access test directory', function (done) {
var options = createOptions('/origin/test-folder/', 'user1')
options.headers.origin = origin1
Expand Down
46 changes: 22 additions & 24 deletions test/integration/acl-tls-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ describe('ACL with WebID+TLS', function () {
done()
})
})
it("should create test file's acl file", function (done) {
it('should create test file\'s acl file', function (done) {
var options = createOptions('/acl-tls/write-acl/test-file.acl', 'user1')
options.headers = {
'content-type': 'text/turtle'
Expand All @@ -243,7 +243,7 @@ describe('ACL with WebID+TLS', function () {
done()
})
})
it("should not access test file's acl file", function (done) {
it('should not access test file\'s acl file', function (done) {
var options = createOptions('/acl-tls/write-acl/test-file.acl', 'user1')
options.headers = {
accept: 'text/turtle'
Expand All @@ -267,12 +267,10 @@ describe('ACL with WebID+TLS', function () {
})

describe('Origin', function () {
before(function () {
before(function (done) {
rm('acl-tls/origin/test-folder/.acl')
})

it('should PUT new ACL file', function (done) {
var options = createOptions('/acl-tls/origin/test-folder/.acl', 'user1', 'text/turtle')
const options = createOptions('/acl-tls/origin/test-folder/.acl', 'user1', 'text/turtle')
options.headers = {
'content-type': 'text/turtle'
}
Expand All @@ -294,6 +292,7 @@ describe('ACL with WebID+TLS', function () {
// TODO user header
})
})

it('user1 should be able to access test directory', function (done) {
var options = createOptions('/acl-tls/origin/test-folder/', 'user1')
options.headers.origin = origin1
Expand Down Expand Up @@ -332,7 +331,7 @@ describe('ACL with WebID+TLS', function () {

request.head(options, function (error, response, body) {
assert.equal(error, null)
assert.equal(response.statusCode, 403)
assert.equal(response.statusCode, 401)
done()
})
})
Expand All @@ -354,7 +353,7 @@ describe('ACL with WebID+TLS', function () {

request.head(options, function (error, response, body) {
assert.equal(error, null)
assert.equal(response.statusCode, 403)
assert.equal(response.statusCode, 401)
done()
})
})
Expand All @@ -365,11 +364,9 @@ describe('ACL with WebID+TLS', function () {
})

describe('Mixed statement Origin', function () {
before(function () {
before(function (done) {
rm('acl-tls/origin/test-folder/.acl')
})

it('should PUT new ACL file', function (done) {
var options = createOptions('/acl-tls/origin/test-folder/.acl', 'user1', 'text/turtle')
options.headers = {
'content-type': 'text/turtle'
Expand All @@ -379,9 +376,9 @@ describe('ACL with WebID+TLS', function () {
' <http://www.w3.org/ns/auth/acl#agent> <' + user1 + '>;\n' +
' <http://www.w3.org/ns/auth/acl#mode> <http://www.w3.org/ns/auth/acl#Read>, <http://www.w3.org/ns/auth/acl#Write>, <http://www.w3.org/ns/auth/acl#Control> .\n' +
'<#Owner2> a <http://www.w3.org/ns/auth/acl#Authorization>;\n' +
' <http://www.w3.org/ns/auth/acl#accessTo> <https://localhost:3456/test/acl-tls/origin/test-folder/>;\n' +
' <http://www.w3.org/ns/auth/acl#origin> <' + origin1 + '>;\n' +
' <http://www.w3.org/ns/auth/acl#mode> <http://www.w3.org/ns/auth/acl#Read>, <http://www.w3.org/ns/auth/acl#Write>, <http://www.w3.org/ns/auth/acl#Control> .\n' +
' <http://www.w3.org/ns/auth/acl#accessTo> <https://localhost:3456/test/acl-tls/origin/test-folder/>;\n' +
' <http://www.w3.org/ns/auth/acl#origin> <' + origin1 + '>;\n' +
' <http://www.w3.org/ns/auth/acl#mode> <http://www.w3.org/ns/auth/acl#Read>, <http://www.w3.org/ns/auth/acl#Write>, <http://www.w3.org/ns/auth/acl#Control> .\n' +
'<#Public> a <http://www.w3.org/ns/auth/acl#Authorization>;\n' +
' <http://www.w3.org/ns/auth/acl#accessTo> <./>;\n' +
' <http://www.w3.org/ns/auth/acl#agentClass> <http://www.w3.org/ns/auth/acl#AuthenticatedAgent>;\n' +
Expand All @@ -395,6 +392,7 @@ describe('ACL with WebID+TLS', function () {
// TODO user header
})
})

it('user1 should be able to access test directory', function (done) {
var options = createOptions('/acl-tls/origin/test-folder/', 'user1')
options.headers.origin = origin1
Expand Down Expand Up @@ -433,7 +431,7 @@ describe('ACL with WebID+TLS', function () {

request.head(options, function (error, response, body) {
assert.equal(error, null)
assert.equal(response.statusCode, 403)
assert.equal(response.statusCode, 401)
done()
})
})
Expand All @@ -455,7 +453,7 @@ describe('ACL with WebID+TLS', function () {

request.head(options, function (error, response, body) {
assert.equal(error, null)
assert.equal(response.statusCode, 403)
assert.equal(response.statusCode, 401)
done()
})
})
Expand Down Expand Up @@ -582,7 +580,7 @@ describe('ACL with WebID+TLS', function () {

describe('Append-only', function () {
// var body = fs.readFileSync(__dirname + '/resources/acl-tls/append-acl/abc.ttl.acl')
it("user1 should be able to access test file's ACL file", function (done) {
it('user1 should be able to access test file\'s ACL file', function (done) {
var options = createOptions('/acl-tls/append-acl/abc.ttl.acl', 'user1')
request.head(options, function (error, response) {
assert.equal(error, null)
Expand Down Expand Up @@ -623,7 +621,7 @@ describe('ACL with WebID+TLS', function () {
done()
})
})
it("user2 should not be able to access test file's ACL file", function (done) {
it('user2 should not be able to access test file\'s ACL file', function (done) {
var options = createOptions('/acl-tls/append-acl/abc.ttl.acl', 'user2')
request.head(options, function (error, response, body) {
assert.equal(error, null)
Expand Down Expand Up @@ -685,7 +683,7 @@ describe('ACL with WebID+TLS', function () {
' <http://www.w3.org/ns/auth/acl#accessTo> <./abc2.ttl>;\n' +
' <http://www.w3.org/ns/auth/acl#agent> <' + user2 + '>;\n' +
' <http://www.w3.org/ns/auth/acl#mode> <http://www.w3.org/ns/auth/acl#Read>, <http://www.w3.org/ns/auth/acl#Write>.\n'
it("user1 should be able to modify test file's ACL file", function (done) {
it('user1 should be able to modify test file\'s ACL file', function (done) {
var options = createOptions('/acl-tls/append-acl/abc2.ttl.acl', 'user1')
options.headers = {
'content-type': 'text/turtle'
Expand All @@ -697,7 +695,7 @@ describe('ACL with WebID+TLS', function () {
done()
})
})
it("user1 should be able to access test file's ACL file", function (done) {
it('user1 should be able to access test file\'s ACL file', function (done) {
var options = createOptions('/acl-tls/append-acl/abc2.ttl.acl', 'user1')
request.head(options, function (error, response, body) {
assert.equal(error, null)
Expand Down Expand Up @@ -733,7 +731,7 @@ describe('ACL with WebID+TLS', function () {
done()
})
})
it("user2 should not be able to access test file's ACL file", function (done) {
it('user2 should not be able to access test file\'s ACL file', function (done) {
var options = createOptions('/acl-tls/append-acl/abc2.ttl.acl', 'user2')
request.head(options, function (error, response, body) {
assert.equal(error, null)
Expand Down Expand Up @@ -791,7 +789,7 @@ describe('ACL with WebID+TLS', function () {
' <http://www.w3.org/ns/auth/acl#default> <./>;\n' +
' <http://www.w3.org/ns/auth/acl#agentClass> <http://xmlns.com/foaf/0.1/Agent>;\n' +
' <http://www.w3.org/ns/auth/acl#mode> <http://www.w3.org/ns/auth/acl#Read> .\n'
it("user1 should be able to modify test directory's ACL file", function (done) {
it('user1 should be able to modify test directory\'s ACL file', function (done) {
var options = createOptions('/acl-tls/write-acl/default-for-new/.acl', 'user1')
options.headers = {
'content-type': 'text/turtle'
Expand All @@ -803,7 +801,7 @@ describe('ACL with WebID+TLS', function () {
done()
})
})
it("user1 should be able to access test direcotory's ACL file", function (done) {
it('user1 should be able to access test direcotory\'s ACL file', function (done) {
var options = createOptions('/acl-tls/write-acl/default-for-new/.acl', 'user1')
request.head(options, function (error, response, body) {
assert.equal(error, null)
Expand Down Expand Up @@ -831,7 +829,7 @@ describe('ACL with WebID+TLS', function () {
done()
})
})
it("user2 should not be able to access test direcotory's ACL file", function (done) {
it('user2 should not be able to access test direcotory\'s ACL file', function (done) {
var options = createOptions('/acl-tls/write-acl/default-for-new/.acl', 'user2')
request.head(options, function (error, response, body) {
assert.equal(error, null)
Expand Down
Loading