This repository was archived by the owner on Nov 18, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
145 lines (120 loc) · 3.55 KB
/
index.js
File metadata and controls
145 lines (120 loc) · 3.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
'use strict';
const passport = module.parent.require('passport');
const nconf = module.parent.require('nconf');
const winston = module.parent.require('winston');
const { Issuer, Strategy, custom } = require('openid-client');
const AUTH_OIDC_BASE_PATH = '/auth/oidc';
const AUTH_OIDC_LOGIN_PATH = `${AUTH_OIDC_BASE_PATH}/login`;
const AUTH_OIDC_CALLBACK_PATH = `${AUTH_OIDC_BASE_PATH}/callback`;
const CLOCK_TOLERANCE = 10;
const controllers = require('./lib/controllers');
const { UserHelper, SettingsHelper } = require('./lib/helpers');
/**
* Initializes the plugin
* @param {Object} data
* @param {Function} callback
*/
async function init({ router, middleware }, callback) {
try {
winston.info('Setting up OpenID Connect UI routes...');
router.get('/admin/oidc', middleware.admin.buildHeader, controllers.renderAdminPage);
router.get('/api/admin/oidc', controllers.renderAdminPage);
callback();
} catch (err) {
callback(err);
}
}
/**
* Adds menu item in admin.
* @param {Object} header
* @param {Function} callback
*/
async function addMenuItem(header, callback) {
header.authentication.push({
route: '/oidc',
icon: 'fa-openid',
name: 'OpenID Connect',
});
callback(null, header);
}
/**
* Finds or Creates the logged user as needed.
* @param {TokenSet} tokenSet
* @param {Object} profile
* @param {Function} callback
*/
async function verify(tokenSet, profile, callback) {
try {
const claims = tokenSet.claims();
let uid = await UserHelper.getUidByIssuerAndSubject(claims.iss, claims.sub);
if (uid) {
callback(null, { uid });
return;
}
uid = await UserHelper.create({
username: claims.preferred_username || claims.email,
email: String(claims.email).toLowerCase(),
oidcIssuer: claims.iss,
oidcSubject: claims.sub,
});
callback(null, { uid });
} catch (err) {
callback(err);
}
}
/**
* Creates the Passport Strategy to login with OpenID Connect.
*
* @param {Array} strategies
* @param {Function} callback
*/
async function getStrategy(strategies, callback) {
try {
const config = await SettingsHelper.get('oidc');
if (!config.discoverUrl || !config.clientId || !config.clientSecret) {
winston.warn('[oidc] OpenID Connect configuration missing, disabling.');
callback(null, strategies);
return;
}
winston.verbose('[oidc] Fetching OpenID Connect Issuer informations ...');
const issuer = await Issuer.discover(config.discoverUrl);
winston.verbose('[oidc] Creating OpenID Connect Passport Strategy ...');
const client = new issuer.Client({
client_id: config.clientId,
client_secret: config.clientSecret,
redirect_uris: [nconf.get('url') + AUTH_OIDC_CALLBACK_PATH],
});
// Adding some timestamp tolerance as they may be a little different
// if nodebb and the OpenID Connect server are on two separate
// hosts.
client[custom.clock_tolerance] = CLOCK_TOLERANCE;
const strategy = new Strategy({
client,
params: {
// In OpenID Connect,
// => issuer and subject in the 'openid' scope
// => email in the 'email' scope
// => username in the 'profile' scope ( as 'preferred_username' )
// scope: 'openid email profile'
},
}, verify);
passport.use(strategy.name, strategy);
strategies.push({
name: strategy.name,
url: AUTH_OIDC_LOGIN_PATH,
callbackURL: AUTH_OIDC_CALLBACK_PATH,
icon: 'fa-openid',
scope: 'openid email profile',
});
winston.verbose('[oidc] Strategy initialized ...');
callback(null, strategies);
} catch (err) {
winston.error(err);
callback(err);
}
}
module.exports = {
init,
addMenuItem,
getStrategy,
};