Skip to content

Commit 560c570

Browse files
Allow login via TLS with externally hosted WebIDs
1 parent 5fe555d commit 560c570

File tree

5 files changed

+92
-28
lines changed

5 files changed

+92
-28
lines changed

lib/models/account-manager.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -345,18 +345,19 @@ class AccountManager {
345345
username: userData.username,
346346
email: userData.email,
347347
name: userData.name,
348+
externalWebId: userData.externalWebId,
348349
webId: userData.webid || userData.webId ||
349350
this.accountWebIdFor(userData.username)
350351
}
351352

352-
if (userConfig.webId && !userConfig.username) {
353-
userConfig.username = this.usernameFromWebId(userConfig.webId)
354-
}
355-
356353
if (!userConfig.webId && !userConfig.username) {
357354
throw new Error('Username or web id is required')
358355
}
359356

357+
if (userConfig.webId && !userConfig.username) {
358+
userConfig.username = this.usernameFromWebId(userConfig.webId)
359+
}
360+
360361
return UserAccount.from(userConfig)
361362
}
362363

lib/models/authenticator.js

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
const debug = require('./../debug').authentication
44
const validUrl = require('valid-url')
55
const webid = require('webid/tls')
6+
const provider = require('oidc-auth-manager/src/preferred-provider')
7+
const { domainMatches } = require('oidc-auth-manager/src/oidc-manager')
68

79
/**
810
* Abstract Authenticator class, representing a local login strategy.
@@ -293,6 +295,10 @@ class TlsAuthenticator extends Authenticator {
293295
webid.verify(certificate, callback)
294296
}
295297

298+
discoverProviderFor (webId) {
299+
return provider.discoverProviderFor(webId)
300+
}
301+
296302
/**
297303
* Ensures that the extracted WebID URI is hosted on this server. If it is,
298304
* returns a UserAccount instance for that WebID, throws an error otherwise.
@@ -304,13 +310,27 @@ class TlsAuthenticator extends Authenticator {
304310
* @return {UserAccount}
305311
*/
306312
ensureLocalUser (webId) {
307-
if (this.accountManager.externalAccount(webId)) {
308-
debug(`WebID URI ${JSON.stringify(webId)} is not a local account`)
313+
const serverUri = this.accountManager.host.serverUri
309314

310-
throw new Error('Cannot login: Selected Web ID is not hosted on this server')
315+
// if (this.accountManager.externalAccount(webId)) {
316+
if (domainMatches(serverUri, webId)) {
317+
// This is a locally hosted Web ID
318+
return Promise.resolve(this.accountManager.userAccountFrom({ webId }))
311319
}
312320

313-
return this.accountManager.userAccountFrom({ webId })
321+
debug(`WebID URI ${JSON.stringify(webId)} is not a local account, verifying preferred provider`)
322+
323+
return this.discoverProviderFor(webId)
324+
.then(preferredProvider => {
325+
debug(`Preferred provider for ${webId} is ${preferredProvider}`)
326+
327+
if (preferredProvider === serverUri) { // everything checks out
328+
return this.accountManager.userAccountFrom({ webId, username: webId, externalWebId: true })
329+
}
330+
331+
throw new Error(`This server is not the preferred provider for Web ID ${webId}`)
332+
})
333+
// return Promise.reject(new Error('Cannot login: Selected Web ID is not hosted on this server'))
314334
}
315335
}
316336

package-lock.json

Lines changed: 36 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
"node-forge": "^0.6.38",
6060
"nodemailer": "^3.1.4",
6161
"nomnom": "^1.8.1",
62-
"oidc-auth-manager": "^0.10.0",
62+
"oidc-auth-manager": "^0.11.1",
6363
"oidc-op-express": "^0.0.3",
6464
"rdflib": "^0.15.0",
6565
"recursive-readdir": "^2.1.0",

test/unit/tls-authenticator-test.js

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,24 +134,44 @@ describe('TlsAuthenticator', () => {
134134
})
135135

136136
describe('ensureLocalUser()', () => {
137-
it('should throw an error if the user is not local to this server', () => {
137+
it('should throw an error if external user and this server not the preferred provider', done => {
138138
let tlsAuth = new TlsAuthenticator({ accountManager })
139139

140140
let externalWebId = 'https://alice.someothersite.com#me'
141141

142-
expect(() => tlsAuth.ensureLocalUser(externalWebId))
143-
.to.throw(/Cannot login: Selected Web ID is not hosted on this server/)
142+
tlsAuth.discoverProviderFor = sinon.stub().resolves('https://another-provider.com')
143+
144+
tlsAuth.ensureLocalUser(externalWebId)
145+
.catch(err => {
146+
expect(err.message).to.match(/This server is not the preferred provider for Web ID https:\/\/alice.someothersite.com#me/)
147+
done()
148+
})
144149
})
145150

146151
it('should return a user instance if the webid is local', () => {
147152
let tlsAuth = new TlsAuthenticator({ accountManager })
148153

149154
let webId = 'https://alice.example.com/#me'
150155

151-
let user = tlsAuth.ensureLocalUser(webId)
156+
return tlsAuth.ensureLocalUser(webId)
157+
.then(user => {
158+
expect(user.username).to.equal('alice')
159+
expect(user.webId).to.equal(webId)
160+
})
161+
})
162+
163+
it('should return a user instance if external user and this server is preferred provider', () => {
164+
let tlsAuth = new TlsAuthenticator({ accountManager })
165+
166+
let externalWebId = 'https://alice.someothersite.com#me'
167+
168+
tlsAuth.discoverProviderFor = sinon.stub().resolves('https://example.com')
152169

153-
expect(user.username).to.equal('alice')
154-
expect(user.webId).to.equal(webId)
170+
tlsAuth.ensureLocalUser(externalWebId)
171+
.then(user => {
172+
expect(user.username).to.equal(externalWebId)
173+
expect(user.webId).to.equal(externalWebId)
174+
})
155175
})
156176
})
157177

0 commit comments

Comments
 (0)