Skip to content

Commit 2efc42f

Browse files
Extract /logout handler to LogoutRequest
1 parent c70c1ff commit 2efc42f

7 files changed

Lines changed: 130 additions & 53 deletions

File tree

lib/api/authn/webid-oidc.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ const error = require('../../http-error')
1010
const bodyParser = require('body-parser').urlencoded({ extended: false })
1111

1212
const DiscoverProviderRequest = require('../../requests/discover-provider-request')
13+
const LogoutRequest = require('../../requests/logout-request')
14+
1315
const { LoginByPasswordRequest } = require('../../requests/login-request')
1416

1517
/**
@@ -41,7 +43,11 @@ function middleware (oidc) {
4143

4244
router.post(['/login', '/signin'], bodyParser, login)
4345

44-
router.post('/logout', logout)
46+
router.get('/logout', logout)
47+
48+
router.get('/goodbye', (req, res) => {
49+
res.sendFile('goodbye.html', { root: './static/oidc/' })
50+
})
4551

4652
// The relying party callback is called at the end of the OIDC signin process
4753
router.get('/api/oidc/rp/:issuer_id', (req, res, next) => {
@@ -84,9 +90,8 @@ function login (req, res, next) {
8490
}
8591

8692
function logout (req, res, next) {
87-
req.session.userId = ''
88-
req.session.identified = false
89-
res.status(200).send()
93+
return LogoutRequest.handle(req, res)
94+
.catch(next)
9095
}
9196

9297
function authCodeFlowCallback (oidc, req) {

lib/models/oidc-manager.js

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const url = require('url')
44
const debug = require('./../debug').oidc
55

66
const OidcManager = require('oidc-auth-manager')
7+
const LogoutRequest = require('../requests/logout-request')
78

89
/**
910
* Returns an instance of the OIDC Authentication Manager, initialized from
@@ -29,7 +30,7 @@ function fromServerConfig (argv) {
2930
}
3031

3132
let authCallbackUri = url.resolve(providerUri, '/api/oidc/rp')
32-
let postLogoutUri = url.resolve(providerUri, '/signed_out.html')
33+
let postLogoutUri = url.resolve(providerUri, '/goodbye')
3334

3435
let options = {
3536
providerUri,
@@ -101,15 +102,8 @@ function obtainConsent (authRequest) {
101102
}
102103

103104
function logout (logoutRequest) {
104-
let req = logoutRequest.req
105-
req.session.accessToken = ''
106-
req.session.refreshToken = ''
107-
// req.session.issuer = ''
108-
req.session.userId = ''
109-
req.session.identified = false
110-
// Inject post_logout_redirect_uri here? (If Accept: text/html)
111-
debug('LOGOUT behavior')
112-
return logoutRequest
105+
return LogoutRequest.handle(logoutRequest.req, logoutRequest.res)
106+
.then(() => logoutRequest)
113107
}
114108

115109
module.exports = {

lib/requests/logout-request.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
'use strict'
2+
3+
const debug = require('./../debug').authentication
4+
5+
class LogoutRequest {
6+
/**
7+
* @constructor
8+
* @param options
9+
* @param options.request {IncomingRequest} req
10+
* @param options.response {ServerResponse} res
11+
*/
12+
constructor (options) {
13+
this.request = options.request
14+
this.response = options.response
15+
}
16+
17+
static handle (req, res) {
18+
return Promise.resolve()
19+
.then(() => {
20+
let request = LogoutRequest.fromParams(req, res)
21+
22+
return LogoutRequest.logout(request)
23+
})
24+
}
25+
26+
static fromParams (req, res) {
27+
let options = {
28+
request: req,
29+
response: res
30+
}
31+
32+
return new LogoutRequest(options)
33+
}
34+
35+
static logout (request) {
36+
debug(`Logging out user ${request.request.session.userId}`)
37+
38+
request.clearUserSession()
39+
request.redirectToGoodbye()
40+
}
41+
42+
clearUserSession () {
43+
let session = this.request.session
44+
45+
session.accessToken = ''
46+
session.refreshToken = ''
47+
session.userId = ''
48+
session.identified = false
49+
session.subject = ''
50+
}
51+
52+
redirectToGoodbye () {
53+
this.response.redirect('/goodbye')
54+
}
55+
}
56+
57+
module.exports = LogoutRequest

static/oidc/goodbye.html

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1">
6+
<title>Logged Out</title>
7+
<!-- Bootstrap CSS and Theme for demo purposes -->
8+
<link rel="stylesheet" href="css/bootstrap-3.3.6.min.css">
9+
</head>
10+
<body>
11+
<div class="container">
12+
<h3>You have logged out.</h3>
13+
</div>
14+
<div class="container">
15+
<form method="get" action="/login">
16+
<button type="submit" class="btn btn-primary"
17+
id="login">Login Again</button>
18+
</form>
19+
</div>
20+
</body>
21+
</html>

static/oidc/signed_out.html

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

test/unit/login-by-password-request.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ chai.should()
99
const HttpMocks = require('node-mocks-http')
1010
const url = require('url')
1111

12-
// const defaults = require('../../config/defaults')
1312
const {
14-
// LoginRequest,
1513
LoginByPasswordRequest
1614
} = require('../../lib/requests/login-request')
1715

test/unit/logout-request.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use strict'
2+
3+
const chai = require('chai')
4+
const expect = chai.expect
5+
const HttpMocks = require('node-mocks-http')
6+
7+
const LogoutRequest = require('../../lib/requests/logout-request')
8+
9+
describe('LogoutRequest', () => {
10+
it('should clear user session properties', () => {
11+
let req = {
12+
session: {
13+
userId: 'https://alice.example.com/#me',
14+
identified: true,
15+
accessToken: {},
16+
refreshToken: {},
17+
subject: {}
18+
}
19+
}
20+
let res = HttpMocks.createResponse()
21+
22+
return LogoutRequest.handle(req, res)
23+
.then(() => {
24+
let session = req.session
25+
expect(session.userId).to.be.empty
26+
})
27+
})
28+
29+
it('should redirect to /goodbye', () => {
30+
let req = { session: {} }
31+
let res = HttpMocks.createResponse()
32+
33+
return LogoutRequest.handle(req, res)
34+
.then(() => {
35+
expect(res.statusCode).to.equal(302)
36+
expect(res._getRedirectUrl()).to.equal('/goodbye')
37+
})
38+
})
39+
})

0 commit comments

Comments
 (0)