Skip to content

Commit a7b7df9

Browse files
committed
acl-checker.js rewrite parentAcl
1 parent 1f0277a commit a7b7df9

File tree

4 files changed

+81
-32
lines changed

4 files changed

+81
-32
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,15 @@ $ solid start --root path/to/folder --port 8443 --ssl-key path/to/ssl-key.pem --
6969
# Solid server (solid v0.2.24) running on https://localhost:8443/
7070
```
7171

72+
By default `solid` runs in debug all mode. To stop the debug logs use `-q`, the quiet parameter.
73+
74+
```bash
75+
$ DEBUG="solid:*" solid start -q
76+
# use quiet mode and set debug to all
77+
# DEBUG="solid:ACL" logs only debug.ACL's
78+
79+
```
80+
7281
### Running in development environments
7382

7483
Solid requires SSL certificates to be valid, so you cannot use self-signed certificates. To switch off this security feature in development environments, you can use the `bin/solid-test` executable, which unsets the `NODE_TLS_REJECT_UNAUTHORIZED` flag and sets the `rejectUnauthorized` option.

lib/acl-checker.js

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
'use strict'
22
/* eslint-disable node/no-deprecated-api */
33

4-
const { dirname } = require('path')
4+
// const { dirname } = require('path')
55
const rdf = require('rdflib')
66
const debug = require('./debug').ACL
7-
const debugCache = require('./debug').cache
7+
// const debugCache = require('./debug').cache
88
const HTTPError = require('./http-error')
99
const aclCheck = require('@solid/acl-check')
1010
const { URL } = require('url')
@@ -63,59 +63,62 @@ class ACLChecker {
6363
return this.aclCached[cacheKey]
6464
}
6565
let resource = rdf.sym(this.resource)
66+
let parentResource = resource
67+
if (!this.resource.endsWith('/')) { parentResource = rdf.sym(ACLChecker.getDirectory(this.resource)) }
6668
if (this.resource.endsWith('/' + this.suffix)) {
6769
resource = rdf.sym(ACLChecker.getDirectory(this.resource))
70+
parentResource = resource
6871
}
6972
// If this is an ACL, Control mode must be present for any operations
7073
if (this.isAcl(this.resource)) {
7174
mode = 'Control'
72-
resource = rdf.sym(this.resource.substring(0, this.resource.length - this.suffix.length))
75+
const thisResource = this.resource.substring(0, this.resource.length - this.suffix.length)
76+
resource = rdf.sym(thisResource)
77+
parentResource = resource
78+
if (!thisResource.endsWith('/')) parentResource = rdf.sym(ACLChecker.getDirectory(thisResource))
7379
}
7480
// If the slug is an acl, reject
7581
/* if (this.isAcl(this.slug)) {
7682
this.aclCached[cacheKey] = Promise.resolve(false)
7783
return this.aclCached[cacheKey]
7884
} */
79-
const directory = acl.isContainer ? rdf.sym(ACLChecker.getDirectory(acl.acl)) : null
80-
const aclFile = rdf.sym(acl.acl)
85+
const directory = acl.isContainer ? rdf.sym(ACLChecker.getDirectory(acl.docAcl)) : null
86+
const aclFile = rdf.sym(acl.docAcl)
87+
const aclGraph = acl.docGraph
8188
const agent = user ? rdf.sym(user) : null
8289
const modes = [ACL(mode)]
8390
const agentOrigin = this.agentOrigin
8491
const trustedOrigins = this.trustedOrigins
8592
let originTrustedModes = []
8693
try {
8794
this.fetch(aclFile.doc().value)
88-
originTrustedModes = await aclCheck.getTrustedModesForOrigin(acl.graph, resource, directory, aclFile, agentOrigin, (uriNode) => {
89-
return this.fetch(uriNode.doc().value, acl.graph)
95+
originTrustedModes = await aclCheck.getTrustedModesForOrigin(aclGraph, resource, directory, aclFile, agentOrigin, (uriNode) => {
96+
return this.fetch(uriNode.doc().value, aclGraph)
9097
})
9198
} catch (e) {
9299
// FIXME: https://github.com/solid/acl-check/issues/23
93100
// console.error(e.message)
94101
}
95-
let accessDenied = aclCheck.accessDenied(acl.graph, resource, directory, aclFile, agent, modes, agentOrigin, trustedOrigins, originTrustedModes)
102+
let accessDenied = aclCheck.accessDenied(aclGraph, resource, directory, aclFile, agent, modes, agentOrigin, trustedOrigins, originTrustedModes)
96103

97104
function accessDeniedForAccessTo (mode) {
98-
const accessDeniedAccessTo = aclCheck.accessDenied(acl.graph, directory, null, aclFile, agent, [ACL(mode)], agentOrigin, trustedOrigins, originTrustedModes)
105+
const parentAclDirectory = ACLChecker.getDirectory(acl.parentAcl)
106+
const parentDirectory = parentResource === parentAclDirectory ? null : rdf.sym(parentAclDirectory)
107+
const accessDeniedAccessTo = aclCheck.accessDenied(acl.parentGraph, parentResource, parentDirectory, rdf.sym(acl.parentAcl), agent, [ACL(mode)], agentOrigin, trustedOrigins, originTrustedModes)
99108
const accessResult = !accessDenied && !accessDeniedAccessTo
100109
accessDenied = accessResult ? false : accessDenied || accessDeniedAccessTo
101110
// debugCache('accessDenied result ' + accessDenied)
102111
}
103112
// For create and update HTTP methods
104-
if ((method === 'PUT' || method === 'PATCH' || method === 'COPY') && directory) {
105-
// if resource and acl have same parent container,
106-
// and resource does not exist, then accessTo Append from parent is required
107-
if (directory.value === dirname(aclFile.value) + '/' && !resourceExists) {
108-
accessDeniedForAccessTo('Append')
109-
}
113+
if ((method === 'PUT' || method === 'PATCH' || method === 'COPY')) { // && !aclFile.value.endsWith('/.acl')) {
114+
// accessTo Append from parent is required
115+
accessDeniedForAccessTo('Append')
110116
}
111117

112118
// For delete HTTP method
113-
if ((method === 'DELETE') && directory) {
114-
// if resource and acl have same parent container,
115-
// then accessTo Write from parent is required
116-
if (directory.value === dirname(aclFile.value) + '/') {
117-
accessDeniedForAccessTo('Write')
118-
}
119+
if ((method === 'DELETE')) { // } && !aclFile.value.endsWith('/.acl')) {
120+
// accessTo Write from parent is required
121+
accessDeniedForAccessTo('Write')
119122
}
120123
if (accessDenied && user) {
121124
this.messagesCached[cacheKey].push(HTTPError(403, accessDenied))
@@ -147,7 +150,12 @@ class ACLChecker {
147150
const possibleACLs = this.getPossibleACLs()
148151
const acls = [...possibleACLs]
149152
let returnAcl = null
150-
while (possibleACLs.length > 0 && !returnAcl) {
153+
let returnParentAcl = null
154+
let parentAcl = null
155+
let parentGraph = null
156+
let docAcl = null
157+
let docGraph = null
158+
while (possibleACLs.length > 0 && !returnParentAcl) {
151159
const acl = possibleACLs.shift()
152160
let graph
153161
try {
@@ -161,19 +169,32 @@ class ACLChecker {
161169
debug(err)
162170
throw err
163171
}
164-
const relative = resource.replace(acl.replace(/[^/]+$/, ''), './')
165-
debug(`Using ACL ${acl} for ${relative}`)
166-
returnAcl = { acl, graph, isContainer }
172+
// const relative = resource.replace(acl.replace(/[^/]+$/, ''), './')
173+
// debug(`Using ACL ${acl} for ${relative}`)
174+
if (!docAcl) {
175+
docAcl = acl
176+
docGraph = graph
177+
if ((possibleACLs.length === 0) || docAcl.endsWith('/.acl')) {
178+
parentAcl = acl // alain
179+
parentGraph = graph // alain
180+
returnParentAcl = true
181+
}
182+
} else {
183+
parentAcl = acl
184+
parentGraph = graph
185+
returnParentAcl = true
186+
}
187+
returnAcl = { docAcl, docGraph, isContainer, parentAcl, parentGraph }
167188
}
168-
if (!returnAcl) {
189+
if (!returnParentAcl) {
169190
throw new HTTPError(500, `No ACL found for ${resource}, searched in \n- ${acls.join('\n- ')}`)
170191
}
171-
const groupNodes = returnAcl.graph.statementsMatching(null, ACL('agentGroup'), null)
192+
const groupNodes = returnAcl.docGraph.statementsMatching(null, ACL('agentGroup'), null)
172193
const groupUrls = groupNodes.map(node => node.object.value.split('#')[0])
173194
await Promise.all(groupUrls.map(async groupUrl => {
174195
try {
175-
const graph = await this.fetch(groupUrl, returnAcl.graph)
176-
this.requests[groupUrl] = this.requests[groupUrl] || graph
196+
const docGraph = await this.fetch(groupUrl, returnAcl.docGraph)
197+
this.requests[groupUrl] = this.requests[groupUrl] || docGraph
177198
} catch (e) {} // failed to fetch groupUrl
178199
}))
179200

@@ -264,7 +285,7 @@ function fetchLocalOrRemote (mapper, serverUri) {
264285
// debugCache('Expunging from cache', url)
265286
delete temporaryCache[url]
266287
if (Object.keys(temporaryCache).length === 0) {
267-
debugCache('Cache is empty again')
288+
// debugCache('Cache is empty again')
268289
}
269290
}, EXPIRY_MS),
270291
promise: doFetch(url)

lib/handlers/allow.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module.exports = allow
22

33
// const path = require('path')
44
const ACL = require('../acl-checker')
5-
const debug = require('../debug.js').ACL
5+
// const debug = require('../debug.js').ACL
66
// const error = require('../http-error')
77

88
function allow (mode) {
@@ -77,7 +77,7 @@ function allow (mode) {
7777
if (resourceUrl.endsWith('.acl') && (await ldp.isOwner(userId, req.hostname))) return next()
7878
} catch (err) {}
7979
const error = req.authError || await req.acl.getError(userId, mode)
80-
debug(`${mode} access denied to ${userId || '(none)'}: ${error.status} - ${error.message}`)
80+
// debug(`${mode} access denied to ${userId || '(none)'}: ${error.status} - ${error.message}`)
8181
next(error)
8282
}
8383
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
@prefix acl: <http://www.w3.org/ns/auth/acl#>.
2+
3+
<#authorization1>
4+
a acl:Authorization;
5+
6+
acl:agent
7+
<https://tim.localhost:7777/profile/card#me>;
8+
acl:accessTo <./>;
9+
acl:mode
10+
acl:Read, acl:Write, acl:Control;
11+
12+
acl:default <./>.
13+
14+
<#AppendOnly>
15+
a <http://www.w3.org/ns/auth/acl#Authorization>;
16+
<http://www.w3.org/ns/auth/acl#accessTo> <./>;
17+
acl:default <./>;
18+
<http://www.w3.org/ns/auth/acl#agentClass> <http://xmlns.com/foaf/0.1/Agent>;
19+
<http://www.w3.org/ns/auth/acl#mode> <http://www.w3.org/ns/auth/acl#Read>, <http://www.w3.org/ns/auth/acl#Append> .

0 commit comments

Comments
 (0)