Skip to content

Commit c70c1ff

Browse files
OIDC Integration - WIP
- WIP (fix standard warnings) - WIP (moving oidcConfig to config.json) - Add OIDC Issuer discovery link header on OPTIONS - Refactor OIDC client/handler code - Bump dep version, fix gitignore - Integrate Sign In w WebID page with OIDC login - Fix OIDC create user functionality - Fix storing redirectTo URL in session - Remove unneeded options obj (oidc.js) - WIP (create account using webid as OIDC _id) - Fix extraneous oidcIssuerHeader - WIP (fix response types) - Fix token() params - Fix authCallback() - WIP (switch to implicit workflow) - WIP (fix registration configs) - wip - Switch to authz code flow - Move createOIDCUser to oidc-rp-client (from identity-provider) - Implement OIDC /signout support - Do not create a Solid account folder if OIDC user creation fails - WIP - signin session / resume workflow - Signin api: send 500 error if oidc client not initialized - Remove invalid test - Implement user creation via api - Add username & pw auth logic to signin.js - Add bcrypt compilation Travis CI directives - Mount OIDC Identity Provider API into solid server routes - Initialize multi-rp client store collections - Change oidc packages to use github links - Disable the certificate test for the time being - Derive session cookie domain from root uri - Bump oidc-op-express dep - Output auth method at startup - Implement injected Provider logout() behavior - Remove legacy signout logic - Refactoring OIDC initialization from server config in create-app - Simplify createApp() - Move unit tests to their own test/unit/ folder - Refactor lib/api/authn/ files - Move tests to test/unit/ and test/integration/ - Implement CreateOidcAccountRequest and unit tests - Add OIDC account creation integration tests - Extract OidcManager code to external lib - Fix Provider Discover integration tests - Fix existing Login workflow integration test - Implement DiscoverProviderRequest, refactor - Extract login logic to LoginByPasswordRequest - Unit tests for LoginByPasswordRequest - Implement login via either username or webid - Add /login integration tests - Normalize webid if needed during provider discovery - Render Obtain Consent handlebars view - Save provider config on startup, install nyc / code coverage - Move options handler to before authentication or account api - Ensure local client registered on startup
1 parent 65ac8d1 commit c70c1ff

64 files changed

Lines changed: 2838 additions & 763 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ node_modules/
55
npm-debug.log
66
config/account-template
77
config/email-templates
8-
/accounts
9-
/profile
10-
/inbox
11-
/.acl
12-
/config.json
13-
/settings
8+
accounts
9+
profile
10+
inbox
11+
.acl
12+
config.json
13+
settings
14+
db/
1415
.nyc_output
1516
coverage

.travis.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,11 @@ addons:
1111
- nic.localhost
1212
- tim.localhost
1313
- nicola.localhost
14+
apt:
15+
sources:
16+
- ubuntu-toolchain-r-test
17+
packages:
18+
- gcc-4.8
19+
- g++-4.8
20+
env:
21+
- TRAVIS=travis CXX=g++-4.8

bin/lib/init.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ module.exports = function (program) {
3030

3131
// Prompt to the user
3232
inquirer.prompt(questions)
33+
// .then((answers) => {
34+
// let store = new KVPFileStore()
35+
// return store.createCollection('clients')
36+
// .then(() => {
37+
// return answers
38+
// })
39+
// })
3340
.then((answers) => {
3441
// setting email
3542
if (answers.useEmail) {

bin/lib/options.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,11 @@ module.exports = [
5252
question: 'Select authentication strategy',
5353
type: 'list',
5454
choices: [
55+
'WebID-OpenID Connect',
5556
'WebID-TLS'
5657
],
57-
prompt: false,
58-
default: 'WebID-TLS',
58+
prompt: true,
59+
default: 'WebID-OpenID Connect',
5960
filter: (value) => {
6061
if (value === 'WebID-TLS') return 'tls'
6162
},

lib/api/authn/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict'
22

33
module.exports = {
4-
signin: require('./signin'),
5-
signout: require('./signout')
4+
oidc: require('./webid-oidc'),
5+
tls: require('./webid-tls')
66
}

lib/api/authn/signin.js

Lines changed: 0 additions & 33 deletions
This file was deleted.

lib/api/authn/signout.js

Lines changed: 0 additions & 9 deletions
This file was deleted.

lib/api/authn/webid-oidc.js

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
'use strict'
2+
/**
3+
* OIDC Relying Party API handler module.
4+
*/
5+
6+
const express = require('express')
7+
const debug = require('../../debug')
8+
const util = require('../../utils')
9+
const error = require('../../http-error')
10+
const bodyParser = require('body-parser').urlencoded({ extended: false })
11+
12+
const DiscoverProviderRequest = require('../../requests/discover-provider-request')
13+
const { LoginByPasswordRequest } = require('../../requests/login-request')
14+
15+
/**
16+
* Returns a router with OIDC Relying Party and Identity Provider middleware:
17+
*
18+
* 1. Adds a Relying Party (RP) callback handler on '/api/oidc/rp/:issuer_id'
19+
* 2. Sets up a static content handler for signin/signup apps
20+
* 3. Adds a set of Identity Provider (OP) endpoints on '/'
21+
*
22+
* Usage (in create-app.js):
23+
*
24+
* ```
25+
* app.use('/', oidcHandler.api(oidc))
26+
* ```
27+
* @method middleware
28+
*
29+
* @param oidc {OidcManager}
30+
*
31+
* @return {Router} Express router
32+
*/
33+
function middleware (oidc) {
34+
const router = express.Router('/')
35+
36+
// User-facing Authentication API
37+
router.get('/api/auth/discover', (req, res) => {
38+
res.sendFile('discover-provider.html', { root: './static/oidc/' })
39+
})
40+
router.post('/api/auth/discover', bodyParser, discoverProvider)
41+
42+
router.post(['/login', '/signin'], bodyParser, login)
43+
44+
router.post('/logout', logout)
45+
46+
// The relying party callback is called at the end of the OIDC signin process
47+
router.get('/api/oidc/rp/:issuer_id', (req, res, next) => {
48+
// Exchange authorization code for id token
49+
authCodeFlowCallback(oidc, req)
50+
// Redirect the user back to returnToUrl
51+
.then(() => { resumeUserFlow(req, res) })
52+
.catch(next)
53+
})
54+
55+
// Initialize the OIDC Identity Provider routes/api
56+
// router.get('/.well-known/openid-configuration', discover.bind(provider))
57+
// router.get('/jwks', jwks.bind(provider))
58+
// router.post('/register', register.bind(provider))
59+
// router.get('/authorize', authorize.bind(provider))
60+
// router.post('/authorize', authorize.bind(provider))
61+
// router.post('/token', token.bind(provider))
62+
// router.get('/userinfo', userinfo.bind(provider))
63+
// router.get('/logout', logout.bind(provider))
64+
let oidcProviderApi = require('oidc-op-express')(oidc.provider)
65+
router.use('/', oidcProviderApi)
66+
67+
return router
68+
}
69+
70+
function discoverProvider (req, res, next) {
71+
return DiscoverProviderRequest.handle(req, res)
72+
.catch(error => {
73+
error.status = error.status || 400
74+
next(error)
75+
})
76+
}
77+
78+
function login (req, res, next) {
79+
return LoginByPasswordRequest.handle(req, res)
80+
.catch(error => {
81+
error.status = error.status || 400
82+
next(error)
83+
})
84+
}
85+
86+
function logout (req, res, next) {
87+
req.session.userId = ''
88+
req.session.identified = false
89+
res.status(200).send()
90+
}
91+
92+
function authCodeFlowCallback (oidc, req) {
93+
debug.oidc('in authCodeFlowCallback()')
94+
95+
if (!req.params || !req.params.issuer_id) {
96+
return Promise.reject(error(400, 'Invalid auth response uri - missing issuer id'))
97+
}
98+
99+
let issuer = getIssuerId(req)
100+
101+
return oidc.clients.clientForIssuer(issuer)
102+
.then(client => {
103+
return validateResponse(client, req)
104+
})
105+
.then(response => {
106+
initSessionUserAuth(response, req)
107+
})
108+
.catch((err) => {
109+
debug.oidc(err)
110+
throw error(400, err)
111+
})
112+
}
113+
114+
function getIssuerId (req = {}) {
115+
return req.params && decodeURIComponent(req.params.issuer_id)
116+
}
117+
118+
function validateResponse (client, req) {
119+
let url = util.fullUrlForReq(req)
120+
return client.validateResponse(url, req.session)
121+
}
122+
123+
function initSessionUserAuth (authResponse, req) {
124+
let webId = extractWebId(authResponse)
125+
req.session.accessToken = authResponse.params.access_token
126+
req.session.refreshToken = authResponse.params.refresh_token
127+
req.session.userId = webId
128+
req.session.identified = true
129+
}
130+
131+
function extractWebId (authResponse) {
132+
return authResponse.decoded.payload.sub
133+
}
134+
135+
/**
136+
* Redirects the user back to their original requested resource, at the end
137+
* of the OIDC authentication process.
138+
* @method resumeUserFlow
139+
*/
140+
function resumeUserFlow (req, res) {
141+
debug.oidc('In resumeUserFlow handler:')
142+
143+
if (req.session.returnToUrl) {
144+
let returnToUrl = req.session.returnToUrl
145+
// if (req.session.accessToken) {
146+
// returnToUrl += '?access_token=' + req.session.accessToken
147+
// }
148+
debug.oidc(' Redirecting to ' + returnToUrl)
149+
delete req.session.returnToUrl
150+
return res.redirect(302, returnToUrl)
151+
}
152+
res.send('Resume User Flow (failed)')
153+
}
154+
155+
module.exports = {
156+
middleware,
157+
discoverProvider,
158+
login,
159+
logout,
160+
extractWebId,
161+
authCodeFlowCallback,
162+
getIssuerId,
163+
initSessionUserAuth,
164+
resumeUserFlow,
165+
validateResponse
166+
}
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
module.exports = handler
2+
module.exports.authenticate = authenticate
23

34
var webid = require('webid/tls')
4-
var debug = require('../debug').authentication
5-
var error = require('../http-error')
5+
var debug = require('../../debug').authentication
6+
var error = require('../../http-error')
7+
8+
function authenticate () {
9+
return handler
10+
}
611

712
function handler (req, res, next) {
813
var ldp = req.app.locals.ldp

lib/api/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@
33
module.exports = {
44
authn: require('./authn'),
55
messages: require('./messages'),
6+
oidc: require('./authn/webid-oidc'),
7+
tls: require('./authn/webid-tls'),
68
accounts: require('./accounts/user-accounts')
79
}

0 commit comments

Comments
 (0)