Skip to content
Merged
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
2 changes: 1 addition & 1 deletion lib/handlers/allow.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ var debug = require('../debug.js').ACL

function allow (mode) {
return function allowHandler (req, res, next) {
var ldp = req.app.locals.ldp
var ldp = req.app.locals.ldp || {}
if (!ldp.webid) {
return next()
}
Expand Down
20 changes: 18 additions & 2 deletions lib/handlers/auth-proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@
// that sends a logged-in Solid user's details to a backend
module.exports = addAuthProxyHandlers

const proxy = require('http-proxy-middleware')
const createProxy = require('http-proxy-middleware')
const debug = require('../debug')
const allow = require('./allow')

const PROXY_SETTINGS = {
logLevel: 'silent',
changeOrigin: true
}
const REQUIRED_PERMISSIONS = {
get: ['Read'],
options: ['Read'],
use: ['Read', 'Write']
}

// Registers Auth Proxy handlers for each target
function addAuthProxyHandlers (app, targets) {
Expand All @@ -32,7 +38,11 @@ function addAuthProxyHandler (app, sourcePath, target) {
}, PROXY_SETTINGS)

// Activate the proxy
app.use(`${sourcePath}*`, proxy(settings))
const proxy = createProxy(settings)
for (let action in REQUIRED_PERMISSIONS) {
const permissions = REQUIRED_PERMISSIONS[action]
app[action](`${sourcePath}*`, setOriginalUrl, ...permissions.map(allow), proxy)
}
}

// Adds a headers with authentication information
Expand All @@ -45,3 +55,9 @@ function addAuthHeaders (proxyReq, req) {
proxyReq.setHeader('Forwarded', `host=${headers.host}`)
}
}

// Sets the original URL on the request (for the ACL handler)
function setOriginalUrl (req, res, next) {
res.locals.path = req.originalUrl
next()
}
99 changes: 91 additions & 8 deletions test/integration/auth-proxy-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ const request = require('supertest')
const { expect } = require('chai')
const rm = require('../utils').rm

const HOST = 'solid.org'
const USER = 'https://ruben.verborgh.org/profile/#me'

describe('Auth Proxy', () => {
Expand All @@ -15,10 +14,12 @@ describe('Auth Proxy', () => {
// Set up test back-end server
nock('http://server-a.org').persist()
.get(/./).reply(200, function () { return this.req.headers })
.options(/./).reply(200)
.post(/./).reply(200)

// Set up Solid server
server = ldnode({
root: path.join(__dirname, '../resources'),
root: path.join(__dirname, '../resources/auth-proxy'),
authProxy: {
'/server/a': 'http://server-a.org'
},
Expand All @@ -36,18 +37,100 @@ describe('Auth Proxy', () => {

describe('responding to /server/a', () => {
let response
before(() => {
return request(server).get('/server/a')
.set('Host', HOST)
before(() =>
request(server).get('/server/a/')
.then(res => { response = res })
})
)

it('sets the User header on the proxy request', () => {
expect(response.body).to.have.property('user', USER)
})
})

describe('responding to GET', () => {
describe('for a path with read permissions', () => {
let response
before(() =>
request(server).get('/server/a/r')
.then(res => { response = res })
)
it('returns status code 200', () => {
expect(response.statusCode).to.equal(200)
})
})

describe('for a path without read permissions', () => {
let response
before(() =>
request(server).get('/server/a/wc')
.then(res => { response = res })
)

it('returns status code 403', () => {
expect(response.statusCode).to.equal(403)
})
})
})

describe('responding to OPTIONS', () => {
describe('for a path with read permissions', () => {
let response
before(() =>
request(server).options('/server/a/r')
.then(res => { response = res })
)
it('returns status code 200', () => {
expect(response.statusCode).to.equal(200)
})
})

describe('for a path without read permissions', () => {
let response
before(() =>
request(server).options('/server/a/wc')
.then(res => { response = res })
)

it('returns status code 403', () => {
expect(response.statusCode).to.equal(403)
})
})
})

describe('responding to POST', () => {
describe('for a path with read and write permissions', () => {
let response
before(() =>
request(server).post('/server/a/rw')
.then(res => { response = res })
)
it('returns status code 200', () => {
expect(response.statusCode).to.equal(200)
})
})

describe('for a path without read permissions', () => {
let response
before(() =>
request(server).post('/server/a/w')
.then(res => { response = res })
)

it('returns status code 403', () => {
expect(response.statusCode).to.equal(403)
})
})

describe('for a path without write permissions', () => {
let response
before(() =>
request(server).post('/server/a/r')
.then(res => { response = res })
)

it('returns status code 200', () => {
expect(response).to.have.property('statusCode', 200)
it('returns status code 403', () => {
expect(response.statusCode).to.equal(403)
})
})
})
})
Expand Down
42 changes: 42 additions & 0 deletions test/resources/auth-proxy/.acl
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
@prefix acl: <http://www.w3.org/ns/auth/acl#>.
@prefix foaf: <http://xmlns.com/foaf/0.1/>.

# All permissions on /server/a
[
a acl:Authorization;
acl:accessTo </server/a/>;
acl:agent <https://ruben.verborgh.org/profile/#me>;
acl:mode acl:Read, acl:Write, acl:Control
].

# Only Read permissions on /server/a/r
[
a acl:Authorization;
acl:accessTo </server/a/r>;
acl:agent <https://ruben.verborgh.org/profile/#me>;
acl:mode acl:Read
].

# No Read permissions on /server/a/wc
[
a acl:Authorization;
acl:accessTo </server/a/wc>;
acl:agent <https://ruben.verborgh.org/profile/#me>;
acl:mode acl:Write, acl:Control
].

# Only Write permissions on /server/a/w
[
a acl:Authorization;
acl:accessTo </server/a/w>;
acl:agent <https://ruben.verborgh.org/profile/#me>;
acl:mode acl:Write
].

# Read-Write permissions on /server/a/rw
[
a acl:Authorization;
acl:accessTo </server/a/rw>;
acl:agent <https://ruben.verborgh.org/profile/#me>;
acl:mode acl:Read, acl:Write
].
Empty file.
Empty file.
10 changes: 5 additions & 5 deletions test/unit/auth-proxy-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ describe('Auth Proxy', () => {
})

it('returns status code 200', () => {
expect(response).to.have.property('statusCode', 200)
expect(response.statusCode).to.equal(200)
})
})

Expand Down Expand Up @@ -102,7 +102,7 @@ describe('Auth Proxy', () => {
})

it('returns status code 200', () => {
expect(response).to.have.property('statusCode', 200)
expect(response.statusCode).to.equal(200)
})
})

Expand Down Expand Up @@ -136,7 +136,7 @@ describe('Auth Proxy', () => {
})

it('returns status code 200', () => {
expect(response).to.have.property('statusCode', 200)
expect(response.statusCode).to.equal(200)
})
})

Expand Down Expand Up @@ -170,7 +170,7 @@ describe('Auth Proxy', () => {
})

it('returns status code 200', () => {
expect(response).to.have.property('statusCode', 200)
expect(response.statusCode).to.equal(200)
})
})

Expand Down Expand Up @@ -208,7 +208,7 @@ describe('Auth Proxy', () => {
})

it('returns status code 200', () => {
expect(response).to.have.property('statusCode', 200)
expect(response.statusCode).to.equal(200)
})
})
})
Expand Down