Skip to content

Commit 92ca524

Browse files
committed
Restricting access to API endpoints to top domain
1 parent cdfba2d commit 92ca524

File tree

6 files changed

+51
-31
lines changed

6 files changed

+51
-31
lines changed

lib/api/accounts/user-accounts.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ const express = require('express')
44
const bodyParser = require('body-parser').urlencoded({ extended: false })
55
const debug = require('../../debug').accounts
66

7+
const restrictToTopDomain = require('../../handlers/restrict-to-top-domain')
8+
79
const CreateAccountRequest = require('../../requests/create-account-request')
810
const AddCertificateRequest = require('../../requests/add-cert-request')
911
const DeleteAccountRequest = require('../../requests/delete-account-request')
@@ -65,16 +67,16 @@ function middleware (accountManager) {
6567

6668
router.get('/', checkAccountExists(accountManager))
6769

68-
router.post('/api/accounts/new', bodyParser, CreateAccountRequest.post)
69-
router.get(['/register', '/api/accounts/new'], CreateAccountRequest.get)
70+
router.post('/api/accounts/new', restrictToTopDomain, bodyParser, CreateAccountRequest.post)
71+
router.get(['/register', '/api/accounts/new'], restrictToTopDomain, CreateAccountRequest.get)
7072

71-
router.post('/api/accounts/cert', bodyParser, newCertificate(accountManager))
73+
router.post('/api/accounts/cert', restrictToTopDomain, bodyParser, newCertificate(accountManager))
7274

73-
router.get('/account/delete', DeleteAccountRequest.get)
74-
router.post('/account/delete', bodyParser, DeleteAccountRequest.post)
75+
router.get('/account/delete', restrictToTopDomain, DeleteAccountRequest.get)
76+
router.post('/account/delete', restrictToTopDomain, bodyParser, DeleteAccountRequest.post)
7577

76-
router.get('/account/delete/confirm', DeleteAccountConfirmRequest.get)
77-
router.post('/account/delete/confirm', bodyParser, DeleteAccountConfirmRequest.post)
78+
router.get('/account/delete/confirm', restrictToTopDomain, DeleteAccountConfirmRequest.get)
79+
router.post('/account/delete/confirm', restrictToTopDomain, bodyParser, DeleteAccountConfirmRequest.post)
7880

7981
return router
8082
}

lib/api/authn/webid-oidc.js

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ const bodyParser = require('body-parser').urlencoded({ extended: false })
99
const OidcManager = require('../../models/oidc-manager')
1010
const { LoginRequest } = require('../../requests/login-request')
1111

12+
const restrictToTopDomain = require('../../handlers/restrict-to-top-domain')
13+
1214
const PasswordResetEmailRequest = require('../../requests/password-reset-email-request')
1315
const PasswordChangeRequest = require('../../requests/password-change-request')
1416

@@ -65,29 +67,29 @@ function middleware (oidc) {
6567
const router = express.Router('/')
6668

6769
// User-facing Authentication API
68-
router.get(['/login', '/signin'], LoginRequest.get)
70+
router.get(['/login', '/signin'], restrictToTopDomain, LoginRequest.get)
6971

70-
router.post('/login/password', bodyParser, LoginRequest.loginPassword)
72+
router.post('/login/password', restrictToTopDomain, bodyParser, LoginRequest.loginPassword)
7173

72-
router.post('/login/tls', bodyParser, LoginRequest.loginTls)
74+
router.post('/login/tls', restrictToTopDomain, bodyParser, LoginRequest.loginTls)
7375

74-
router.get('/account/password/reset', PasswordResetEmailRequest.get)
75-
router.post('/account/password/reset', bodyParser, PasswordResetEmailRequest.post)
76+
router.get('/account/password/reset', restrictToTopDomain, PasswordResetEmailRequest.get)
77+
router.post('/account/password/reset', restrictToTopDomain, bodyParser, PasswordResetEmailRequest.post)
7678

77-
router.get('/account/password/change', PasswordChangeRequest.get)
78-
router.post('/account/password/change', bodyParser, PasswordChangeRequest.post)
79+
router.get('/account/password/change', restrictToTopDomain, PasswordChangeRequest.get)
80+
router.post('/account/password/change', restrictToTopDomain, bodyParser, PasswordChangeRequest.post)
7981

80-
router.get('/.well-known/solid/logout/', (req, res) => res.redirect('/logout'))
82+
router.get('/.well-known/solid/logout/', restrictToTopDomain, (req, res) => res.redirect('/logout'))
8183

82-
router.get('/goodbye', (req, res) => { res.render('auth/goodbye') })
84+
router.get('/goodbye', restrictToTopDomain, (req, res) => { res.render('auth/goodbye') })
8385

8486
// The relying party callback is called at the end of the OIDC signin process
85-
router.get('/api/oidc/rp/:issuer_id', AuthCallbackRequest.get)
87+
router.get('/api/oidc/rp/:issuer_id', restrictToTopDomain, AuthCallbackRequest.get)
8688

8789
// Static assets related to authentication
8890
const authAssets = [
89-
['/.well-known/solid/login/', '../static/popup-redirect.html', false],
90-
['/common/', 'solid-auth-client/dist-popup/popup.html']
91+
['/.well-known/solid/login/', '../static/popup-redirect.html', false, true],
92+
['/common/', 'solid-auth-client/dist-popup/popup.html', true, true]
9193
]
9294
authAssets.map(args => routeResolvedFile(router, ...args))
9395

lib/capability-discovery.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* @module capability-discovery
44
*/
55
const express = require('express')
6+
const restrictToTopDomain = require('./handlers/restrict-to-top-domain')
67

78
const serviceConfigDefaults = {
89
'api': {
@@ -31,7 +32,7 @@ function capabilityDiscovery () {
3132
const router = express.Router('/')
3233

3334
// Advertise the server capability discover endpoint
34-
router.get('/.well-known/solid', serviceCapabilityDocument(serviceConfigDefaults))
35+
router.get('/.well-known/solid', restrictToTopDomain, serviceCapabilityDocument(serviceConfigDefaults))
3536
return router
3637
}
3738

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const HTTPError = require('../http-error')
2+
3+
module.exports = function (req, res, next) {
4+
const locals = req.app.locals
5+
const ldp = locals.ldp
6+
const serverUri = locals.host.serverUri
7+
const hostname = ldp.resourceMapper.resolveUrl(req.hostname)
8+
if (hostname === serverUri) {
9+
return next()
10+
}
11+
return next(new HTTPError(403, 'Not allowed to access top-level APIs on accounts'))
12+
}

lib/utils.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const url = require('url')
2121
const debug = require('./debug').fs
2222
const getSize = require('get-folder-size')
2323
var ns = require('solid-namespace')($rdf)
24+
const restrictToTopDomainHandler = require('./handlers/restrict-to-top-domain')
2425

2526
/**
2627
* Returns a fully qualified URL from an Express.js Request object.
@@ -178,10 +179,11 @@ function stripLineEndings (obj) {
178179
/**
179180
* Adds a route that serves a static file from another Node module
180181
*/
181-
function routeResolvedFile (router, path, file, appendFileName = true) {
182+
function routeResolvedFile (router, path, file, appendFileName = true, restrictToTopDomain = false) {
182183
const fullPath = appendFileName ? path + file.match(/[^/]+$/) : path
183184
const fullFile = require.resolve(file)
184-
router.get(fullPath, (req, res) => res.sendFile(fullFile))
185+
const restrictHandler = restrictToTopDomain ? restrictToTopDomainHandler : (req, res, next) => next()
186+
router.get(fullPath, restrictHandler, (req, res) => res.sendFile(fullFile))
185187
}
186188

187189
/**

test/integration/account-creation-oidc-test.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,21 +80,21 @@ describe('AccountManager (OIDC account creation tests)', function () {
8080
})
8181

8282
it('should not create WebID if no username is given', (done) => {
83-
let subdomain = supertest('https://nicola.' + host)
83+
let subdomain = supertest('https://' + host)
8484
subdomain.post('/api/accounts/new')
8585
.send('username=&password=12345')
8686
.expect(400, done)
8787
})
8888

8989
it('should not create WebID if no password is given', (done) => {
90-
let subdomain = supertest('https://nicola.' + host)
90+
let subdomain = supertest('https://' + host)
9191
subdomain.post('/api/accounts/new')
9292
.send('username=nicola&password=')
9393
.expect(400, done)
9494
})
9595

9696
it('should not create a WebID if it already exists', function (done) {
97-
var subdomain = supertest('https://nicola.' + host)
97+
var subdomain = supertest('https://' + host)
9898
subdomain.post('/api/accounts/new')
9999
.send('username=nicola&password=12345&acceptToc=true')
100100
.expect(302)
@@ -112,14 +112,14 @@ describe('AccountManager (OIDC account creation tests)', function () {
112112
})
113113

114114
it('should not create WebID if T&C is not accepted', (done) => {
115-
let subdomain = supertest('https://nicola.' + host)
115+
let subdomain = supertest('https://' + host)
116116
subdomain.post('/api/accounts/new')
117117
.send('username=nicola&password=12345&acceptToc=')
118118
.expect(400, done)
119119
})
120120

121121
it('should create the default folders', function (done) {
122-
var subdomain = supertest('https://nicola.' + host)
122+
var subdomain = supertest('https://' + host)
123123
subdomain.post('/api/accounts/new')
124124
.send('username=nicola&password=12345&acceptToc=true')
125125
.expect(302)
@@ -150,14 +150,15 @@ describe('AccountManager (OIDC account creation tests)', function () {
150150
}).timeout(20000)
151151

152152
it('should link WebID to the root account', function (done) {
153-
var subdomain = supertest('https://nicola.' + host)
154-
subdomain.post('/api/accounts/new')
153+
const domain = supertest('https://' + host)
154+
domain.post('/api/accounts/new')
155155
.send('username=nicola&password=12345&acceptToc=true')
156156
.expect(302)
157157
.end(function (err) {
158158
if (err) {
159159
return done(err)
160160
}
161+
const subdomain = supertest('https://nicola.' + host)
161162
subdomain.get('/.meta')
162163
.expect(200)
163164
.end(function (err, data) {
@@ -185,7 +186,7 @@ describe('AccountManager (OIDC account creation tests)', function () {
185186

186187
describe('after setting up account', () => {
187188
beforeEach(done => {
188-
var subdomain = supertest('https://nicola.' + host)
189+
var subdomain = supertest('https://' + host)
189190
subdomain.post('/api/accounts/new')
190191
.send('username=nicola&password=12345&acceptToc=true')
191192
.end(done)
@@ -294,7 +295,7 @@ describe('Signup page where Terms & Conditions are not being enforced', () => {
294295
})
295296

296297
it('should not enforce T&C upon creating account', function (done) {
297-
var subdomain = supertest('https://nicola.' + host)
298+
var subdomain = supertest('https://' + host)
298299
subdomain.post('/api/accounts/new')
299300
.send('username=nicola&password=12345')
300301
.expect(302, done)

0 commit comments

Comments
 (0)