Compare commits
36 Commits
Author | SHA1 | Date | |
---|---|---|---|
646f653368 | |||
20c1362858 | |||
23aaf61b70 | |||
1b15b4f3b7 | |||
|
37c3c04e86 | ||
|
32e061cfe4 | ||
|
68f3c84585 | ||
|
b82a4cf4f9 | ||
|
2840b0568e | ||
|
9f6ab199de | ||
|
8c57b5c105 | ||
|
0ebdabd79a | ||
|
0de77d75b2 | ||
|
8cfdd45de7 | ||
d4af131481 | |||
a632baf6cb | |||
|
5e502244cc | ||
|
312321b79b | ||
|
03dc0d3ea4 | ||
|
7b45882aec | ||
|
427dbe9890 | ||
|
1c60102bc3 | ||
|
74ae8adace | ||
|
e301e6b8bf | ||
|
354850244b | ||
|
d1d9ab0cee | ||
|
f0cf6b82f3 | ||
|
81e2826ad0 | ||
|
8cd170f8f7 | ||
|
3969ffc5a9 | ||
|
8779144d41 | ||
|
a1d495676d | ||
|
8ba28e2046 | ||
|
7d4ea98b5f | ||
|
b320406dcc | ||
|
18af0afe2d |
137
.eslintrc
Normal file
137
.eslintrc
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
{
|
||||||
|
"extends": "airbnb-base",
|
||||||
|
"parserOptions": {
|
||||||
|
"sourceType": "script"
|
||||||
|
},
|
||||||
|
|
||||||
|
"rules": {
|
||||||
|
// Customized
|
||||||
|
"handle-callback-err": [ "error","^(e$|(e|(.*(_e|E)))rr)" ],
|
||||||
|
"comma-dangle": ["error", {
|
||||||
|
"arrays": "always-multiline",
|
||||||
|
"objects": "always-multiline",
|
||||||
|
"imports": "always-multiline",
|
||||||
|
"exports": "always-multiline",
|
||||||
|
"functions": "never"
|
||||||
|
}],
|
||||||
|
"no-empty": ["error", { "allowEmptyCatch": true }],
|
||||||
|
"no-underscore-dangle": "off",
|
||||||
|
"no-console": "off",
|
||||||
|
"no-mixed-operators": ["error", { "allowSamePrecedence": true }],
|
||||||
|
"strict": ["error", "global"],
|
||||||
|
"consistent-return": "off",
|
||||||
|
"func-names": "off",
|
||||||
|
"no-tabs": "off",
|
||||||
|
"indent": ["error", "tab"],
|
||||||
|
"no-eq-null": "off",
|
||||||
|
"camelcase": "off",
|
||||||
|
"no-new": "off",
|
||||||
|
"no-shadow": "off",
|
||||||
|
"no-use-before-define": ["error", "nofunc"],
|
||||||
|
"no-prototype-builtins": "off",
|
||||||
|
"new-cap": "off",
|
||||||
|
"no-plusplus": ["error", { "allowForLoopAfterthoughts": true }],
|
||||||
|
"object-curly-newline": "off",
|
||||||
|
"no-restricted-globals": "off",
|
||||||
|
"function-paren-newline": "off",
|
||||||
|
"import/no-unresolved": "error",
|
||||||
|
"quotes": ["error", "single", {
|
||||||
|
"avoidEscape": true,
|
||||||
|
"allowTemplateLiterals": true
|
||||||
|
}],
|
||||||
|
"no-else-return": [ "error", { "allowElseIf": true } ],
|
||||||
|
"operator-linebreak": [ "error", "after" ],
|
||||||
|
|
||||||
|
// ES6
|
||||||
|
"prefer-rest-params": "off",
|
||||||
|
"prefer-spread": "off",
|
||||||
|
"prefer-arrow-callback": "off",
|
||||||
|
"prefer-template": "off",
|
||||||
|
"no-var": "off",
|
||||||
|
"object-shorthand": "off",
|
||||||
|
"vars-on-top": "off",
|
||||||
|
"prefer-destructuring": "off",
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
"import/no-extraneous-dependencies": "off",
|
||||||
|
"import/no-dynamic-require": "off",
|
||||||
|
"import/newline-after-import": "off",
|
||||||
|
"no-bitwise": "off",
|
||||||
|
"global-require": "off",
|
||||||
|
"max-len": "off",
|
||||||
|
"no-param-reassign": "off",
|
||||||
|
"no-restricted-syntax": "off",
|
||||||
|
"no-script-url": "off",
|
||||||
|
"default-case": "off",
|
||||||
|
"linebreak-style": "off",
|
||||||
|
|
||||||
|
// "no-multi-assign": "off",
|
||||||
|
// "one-var": "off",
|
||||||
|
// "no-undef": "off",
|
||||||
|
// "max-nested-callbacks": "off",
|
||||||
|
// "no-mixed-requires": "off",
|
||||||
|
// "brace-style": "off",
|
||||||
|
// "max-statements-per-line": "off",
|
||||||
|
// "no-unused-vars": "off",
|
||||||
|
// "no-mixed-spaces-and-tabs": "off",
|
||||||
|
// "no-useless-concat": "off",
|
||||||
|
// "require-jsdoc": "off",
|
||||||
|
// "eqeqeq": "off",
|
||||||
|
// "no-negated-condition": "off",
|
||||||
|
// "one-var-declaration-per-line": "off",
|
||||||
|
// "no-lonely-if": "off",
|
||||||
|
// "radix": "off",
|
||||||
|
// "no-else-return": "off",
|
||||||
|
// "no-useless-escape": "off",
|
||||||
|
// "block-scoped-var": "off",
|
||||||
|
// "operator-assignment": "off",
|
||||||
|
// "yoda": "off",
|
||||||
|
// "no-loop-func": "off",
|
||||||
|
// "no-void": "off",
|
||||||
|
// "valid-jsdoc": "off",
|
||||||
|
// "no-cond-assign": "off",
|
||||||
|
// "no-redeclare": "off",
|
||||||
|
// "no-unreachable": "off",
|
||||||
|
// "no-nested-ternary": "off",
|
||||||
|
// "operator-linebreak": "off",
|
||||||
|
// "guard-for-in": "off",
|
||||||
|
// "no-unneeded-ternary": "off",
|
||||||
|
// "no-sequences": "off",
|
||||||
|
// "no-extend-native": "off",
|
||||||
|
// "no-shadow-restricted-names": "off",
|
||||||
|
// "no-extra-boolean-cast": "off",
|
||||||
|
// "no-path-concat": "off",
|
||||||
|
// "no-unused-expressions": "off",
|
||||||
|
// "no-return-assign": "off",
|
||||||
|
// "no-restricted-modules": "off",
|
||||||
|
// "object-curly-spacing": "off",
|
||||||
|
// "indent": "off",
|
||||||
|
// "padded-blocks": "off",
|
||||||
|
// "eol-last": "off",
|
||||||
|
// "lines-around-directive": "off",
|
||||||
|
// "strict": "off",
|
||||||
|
// "comma-dangle": "off",
|
||||||
|
// "no-multi-spaces": "off",
|
||||||
|
// "quotes": "off",
|
||||||
|
// "keyword-spacing": "off",
|
||||||
|
// "no-mixed-operators": "off",
|
||||||
|
// "comma-spacing": "off",
|
||||||
|
// "no-trailing-spaces": "off",
|
||||||
|
// "key-spacing": "off",
|
||||||
|
// "no-multiple-empty-lines": "off",
|
||||||
|
// "spaced-comment": "off",
|
||||||
|
// "space-in-parens": "off",
|
||||||
|
// "block-spacing": "off",
|
||||||
|
// "quote-props": "off",
|
||||||
|
// "space-unary-ops": "off",
|
||||||
|
// "no-empty": "off",
|
||||||
|
// "dot-notation": "off",
|
||||||
|
// "func-call-spacing": "off",
|
||||||
|
// "array-bracket-spacing": "off",
|
||||||
|
// "object-property-newline": "off",
|
||||||
|
// "no-continue": "off",
|
||||||
|
// "no-extra-semi": "off",
|
||||||
|
// "no-spaced-func": "off",
|
||||||
|
// "no-useless-return": "off"
|
||||||
|
}
|
||||||
|
}
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -216,3 +216,9 @@ pip-log.txt
|
|||||||
|
|
||||||
sftp-config.json
|
sftp-config.json
|
||||||
node_modules/
|
node_modules/
|
||||||
|
|
||||||
|
####################
|
||||||
|
# JetBrains
|
||||||
|
####################
|
||||||
|
|
||||||
|
.idea
|
||||||
|
@ -14,4 +14,6 @@ NodeBB Plugin that allows users to login/register via any configured OAuth provi
|
|||||||
|
|
||||||
## Trouble?
|
## Trouble?
|
||||||
|
|
||||||
|
The NodeBB team builds out SSO plugins for a nominal fee. [Reach out to us for a quote.](mailto:sales@nodebb.org)
|
||||||
|
|
||||||
Find us on [the community forums](http://community.nodebb.org)!
|
Find us on [the community forums](http://community.nodebb.org)!
|
3
commitlint.config.js
Normal file
3
commitlint.config.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = { extends: ['@commitlint/config-angular'] };
|
203
library.js
203
library.js
@ -1,6 +1,6 @@
|
|||||||
(function(module) {
|
'use strict';
|
||||||
"use strict";
|
|
||||||
|
|
||||||
|
(function (module) {
|
||||||
/*
|
/*
|
||||||
Welcome to the SSO OAuth plugin! If you're inspecting this code, you're probably looking to
|
Welcome to the SSO OAuth plugin! If you're inspecting this code, you're probably looking to
|
||||||
hook up NodeBB with your existing OAuth endpoint.
|
hook up NodeBB with your existing OAuth endpoint.
|
||||||
@ -11,42 +11,65 @@
|
|||||||
Step 2: Give it a whirl. If you see the congrats message, you're doing well so far!
|
Step 2: Give it a whirl. If you see the congrats message, you're doing well so far!
|
||||||
|
|
||||||
Step 3: Customise the `parseUserReturn` method to normalise your user route's data return into
|
Step 3: Customise the `parseUserReturn` method to normalise your user route's data return into
|
||||||
a format accepted by NodeBB. Instructions are provided there. (Line 137)
|
a format accepted by NodeBB. Instructions are provided there. (Line 146)
|
||||||
|
|
||||||
Step 4: If all goes well, you'll be able to login/register via your OAuth endpoint credentials.
|
Step 4: If all goes well, you'll be able to login/register via your OAuth endpoint credentials.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var User = module.parent.require('./user'),
|
const User = require.main.require('./src/user');
|
||||||
Groups = module.parent.require('./groups'),
|
const Groups = require.main.require('./src/groups');
|
||||||
meta = module.parent.require('./meta'),
|
const db = require.main.require('./src/database');
|
||||||
db = module.parent.require('../src/database'),
|
const authenticationController = require.main.require('./src/controllers/authentication');
|
||||||
passport = module.parent.require('passport'),
|
|
||||||
fs = module.parent.require('fs'),
|
|
||||||
path = module.parent.require('path'),
|
|
||||||
nconf = module.parent.require('nconf'),
|
|
||||||
winston = module.parent.require('winston'),
|
|
||||||
async = module.parent.require('async'),
|
|
||||||
|
|
||||||
constants = Object.freeze({
|
const async = require('async');
|
||||||
type: '', // Either 'oauth' or 'oauth2'
|
|
||||||
name: '', // Something unique to your OAuth provider in lowercase, like "github", or "nodebb"
|
const passport = module.parent.require('passport');
|
||||||
oauth: {
|
const nconf = module.parent.require('nconf');
|
||||||
requestTokenURL: '',
|
const winston = module.parent.require('winston');
|
||||||
accessTokenURL: '',
|
|
||||||
userAuthorizationURL: '',
|
/**
|
||||||
consumerKey: '',
|
* REMEMBER
|
||||||
consumerSecret: ''
|
* Never save your OAuth Key/Secret or OAuth2 ID/Secret pair in code! It could be published and leaked accidentally.
|
||||||
},
|
* Save it into your config.json file instead:
|
||||||
oauth2: {
|
*
|
||||||
authorizationURL: '',
|
* {
|
||||||
tokenURL: '',
|
* ...
|
||||||
clientID: '',
|
* "oauth": {
|
||||||
clientSecret: ''
|
* "id": "someoauthid",
|
||||||
},
|
* "secret": "youroauthsecret"
|
||||||
userRoute: '' // This is the address to your app's "user profile" API endpoint (expects JSON)
|
* }
|
||||||
}),
|
* ...
|
||||||
configOk = false,
|
* }
|
||||||
OAuth = {}, passportOAuth, opts;
|
*
|
||||||
|
* ... or use environment variables instead:
|
||||||
|
*
|
||||||
|
* `OAUTH__ID=someoauthid OAUTH__SECRET=youroauthsecret node app.js`
|
||||||
|
*/
|
||||||
|
|
||||||
|
const constants = Object.freeze({
|
||||||
|
type: 'oauth2', // Either 'oauth' or 'oauth2'
|
||||||
|
name: 'icynet', // Something unique to your OAuth provider in lowercase, like "github", or "nodebb"
|
||||||
|
scope: 'email image privileges',
|
||||||
|
oauth: {
|
||||||
|
requestTokenURL: '',
|
||||||
|
accessTokenURL: '',
|
||||||
|
userAuthorizationURL: '',
|
||||||
|
consumerKey: nconf.get('oauth:key'), // don't change this line
|
||||||
|
consumerSecret: nconf.get('oauth:secret'), // don't change this line
|
||||||
|
},
|
||||||
|
oauth2: {
|
||||||
|
authorizationURL: 'https://secure.icynet.eu/oauth2/authorize',
|
||||||
|
tokenURL: 'https://secure.icynet.eu/oauth2/token',
|
||||||
|
clientID: nconf.get('oauth:id'),
|
||||||
|
clientSecret: nconf.get('oauth:secret'),
|
||||||
|
},
|
||||||
|
userRoute: 'https://api.icynet.eu/api/user'
|
||||||
|
})
|
||||||
|
|
||||||
|
const OAuth = {};
|
||||||
|
let configOk = false;
|
||||||
|
let passportOAuth;
|
||||||
|
let opts;
|
||||||
|
|
||||||
if (!constants.name) {
|
if (!constants.name) {
|
||||||
winston.error('[sso-oauth] Please specify a name for your OAuth provider (library.js:32)');
|
winston.error('[sso-oauth] Please specify a name for your OAuth provider (library.js:32)');
|
||||||
@ -58,7 +81,7 @@
|
|||||||
configOk = true;
|
configOk = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
OAuth.getStrategy = function(strategies, callback) {
|
OAuth.getStrategy = function (strategies, callback) {
|
||||||
if (configOk) {
|
if (configOk) {
|
||||||
passportOAuth = require('passport-oauth')[constants.type === 'oauth' ? 'OAuthStrategy' : 'OAuth2Strategy'];
|
passportOAuth = require('passport-oauth')[constants.type === 'oauth' ? 'OAuthStrategy' : 'OAuth2Strategy'];
|
||||||
|
|
||||||
@ -67,18 +90,21 @@
|
|||||||
opts = constants.oauth;
|
opts = constants.oauth;
|
||||||
opts.callbackURL = nconf.get('url') + '/auth/' + constants.name + '/callback';
|
opts.callbackURL = nconf.get('url') + '/auth/' + constants.name + '/callback';
|
||||||
|
|
||||||
passportOAuth.Strategy.prototype.userProfile = function(token, secret, params, done) {
|
passportOAuth.Strategy.prototype.userProfile = function (token, secret, params, done) {
|
||||||
this._oauth.get(constants.userRoute, token, secret, function(err, body, res) {
|
this._oauth.get(constants.userRoute, token, secret, function (err, body/* , res */) {
|
||||||
if (err) { return done(new InternalOAuthError('failed to fetch user profile', err)); }
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var json = JSON.parse(body);
|
var json = JSON.parse(body);
|
||||||
OAuth.parseUserReturn(json, function(err, profile) {
|
OAuth.parseUserReturn(json, function (err, profile) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
profile.provider = constants.name;
|
profile.provider = constants.name;
|
||||||
|
|
||||||
done(null, profile);
|
done(null, profile);
|
||||||
});
|
});
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
done(e);
|
done(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -88,34 +114,42 @@
|
|||||||
opts = constants.oauth2;
|
opts = constants.oauth2;
|
||||||
opts.callbackURL = nconf.get('url') + '/auth/' + constants.name + '/callback';
|
opts.callbackURL = nconf.get('url') + '/auth/' + constants.name + '/callback';
|
||||||
|
|
||||||
passportOAuth.Strategy.prototype.userProfile = function(accessToken, done) {
|
passportOAuth.Strategy.prototype.userProfile = function (accessToken, done) {
|
||||||
this._oauth2.get(constants.userRoute, accessToken, function(err, body, res) {
|
this._oauth2.get(constants.userRoute, accessToken, function (err, body/* , res */) {
|
||||||
if (err) { return done(new InternalOAuthError('failed to fetch user profile', err)); }
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var json = JSON.parse(body);
|
var json = JSON.parse(body);
|
||||||
OAuth.parseUserReturn(json, function(err, profile) {
|
OAuth.parseUserReturn(json, function (err, profile) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
profile.provider = constants.name;
|
profile.provider = constants.name;
|
||||||
|
|
||||||
done(null, profile);
|
done(null, profile);
|
||||||
});
|
});
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
done(e);
|
done(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
passport.use(constants.name, new passportOAuth(opts, function(token, secret, profile, done) {
|
opts.passReqToCallback = true;
|
||||||
|
|
||||||
|
passport.use(constants.name, new passportOAuth(opts, function (req, token, secret, profile, done) {
|
||||||
OAuth.login({
|
OAuth.login({
|
||||||
oAuthid: profile.id,
|
oAuthid: profile.id,
|
||||||
handle: profile.displayName,
|
handle: profile.displayName,
|
||||||
email: profile.emails[0].value,
|
email: profile.emails[0].value,
|
||||||
|
picture: profile.picture,
|
||||||
isAdmin: profile.isAdmin
|
isAdmin: profile.isAdmin
|
||||||
}, function(err, user) {
|
}, function(err, user) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return done(err);
|
return done(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
authenticationController.onSuccessfulLogin(req, user.uid);
|
||||||
done(null, user);
|
done(null, user);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
@ -125,7 +159,7 @@
|
|||||||
url: '/auth/' + constants.name,
|
url: '/auth/' + constants.name,
|
||||||
callbackURL: '/auth/' + constants.name + '/callback',
|
callbackURL: '/auth/' + constants.name + '/callback',
|
||||||
icon: 'fa-check-square',
|
icon: 'fa-check-square',
|
||||||
scope: (constants.scope || '').split(',')
|
scope: (constants.scope || '').split(','),
|
||||||
});
|
});
|
||||||
|
|
||||||
callback(null, strategies);
|
callback(null, strategies);
|
||||||
@ -134,69 +168,59 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
OAuth.parseUserReturn = function(data, callback) {
|
OAuth.parseUserReturn = function (data, callback) {
|
||||||
// Alter this section to include whatever data is necessary
|
|
||||||
// NodeBB *requires* the following: id, displayName, emails.
|
|
||||||
// Everything else is optional.
|
|
||||||
|
|
||||||
// Find out what is available by uncommenting this line:
|
|
||||||
// console.log(data);
|
|
||||||
|
|
||||||
var profile = {};
|
var profile = {};
|
||||||
profile.id = data.id;
|
profile.id = data.uuid;
|
||||||
profile.displayName = data.name;
|
profile.displayName = data.display_name;
|
||||||
profile.emails = [{ value: data.email }];
|
profile.emails = [{ value: data.email }];
|
||||||
|
profile.isAdmin = (data.privileges || []).includes('admin');
|
||||||
|
profile.picture = data.image;
|
||||||
|
|
||||||
// Do you want to automatically make somebody an admin? This line might help you do that...
|
// eslint-disable-next-line
|
||||||
// profile.isAdmin = data.isAdmin ? true : false;
|
|
||||||
|
|
||||||
// Delete or comment out the next TWO (2) lines when you are ready to proceed
|
|
||||||
process.stdout.write('===\nAt this point, you\'ll need to customise the above section to id, displayName, and emails into the "profile" object.\n===');
|
|
||||||
return callback(new Error('Congrats! So far so good -- please see server log for details'));
|
|
||||||
|
|
||||||
callback(null, profile);
|
callback(null, profile);
|
||||||
}
|
};
|
||||||
|
|
||||||
OAuth.login = function(payload, callback) {
|
OAuth.login = function (payload, callback) {
|
||||||
OAuth.getUidByOAuthid(payload.oAuthid, function(err, uid) {
|
OAuth.getUidByOAuthid(payload.oAuthid, function (err, uid) {
|
||||||
if(err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uid !== null) {
|
if (uid !== null) {
|
||||||
// Existing User
|
// Existing User
|
||||||
callback(null, {
|
callback(null, {
|
||||||
uid: uid
|
uid: uid,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// New User
|
// New User
|
||||||
var success = function(uid) {
|
var success = function (uid) {
|
||||||
// Save provider-specific information to the user
|
// Save provider-specific information to the user
|
||||||
User.setUserField(uid, constants.name + 'Id', payload.oAuthid);
|
User.setUserField(uid, constants.name + 'Id', payload.oAuthid);
|
||||||
db.setObjectField(constants.name + 'Id:uid', payload.oAuthid, uid);
|
db.setObjectField(constants.name + 'Id:uid', payload.oAuthid, uid);
|
||||||
|
|
||||||
if (payload.isAdmin) {
|
if (payload.isAdmin) {
|
||||||
Groups.join('administrators', uid, function(err) {
|
Groups.join('administrators', uid, function (err) {
|
||||||
callback(null, {
|
callback(err, {
|
||||||
uid: uid
|
uid: uid,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
callback(null, {
|
callback(null, {
|
||||||
uid: uid
|
uid: uid,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
User.getUidByEmail(payload.email, function(err, uid) {
|
User.getUidByEmail(payload.email, function (err, uid) {
|
||||||
if(err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!uid) {
|
if (!uid) {
|
||||||
User.create({
|
User.create({
|
||||||
username: payload.handle,
|
username: payload.handle,
|
||||||
email: payload.email
|
email: payload.email,
|
||||||
|
picture: payload.picture
|
||||||
}, function(err, uid) {
|
}, function(err, uid) {
|
||||||
if(err) {
|
if(err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
@ -212,8 +236,8 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
OAuth.getUidByOAuthid = function(oAuthid, callback) {
|
OAuth.getUidByOAuthid = function (oAuthid, callback) {
|
||||||
db.getObjectField(constants.name + 'Id:uid', oAuthid, function(err, uid) {
|
db.getObjectField(constants.name + 'Id:uid', oAuthid, function (err, uid) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
@ -221,20 +245,27 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
OAuth.deleteUserData = function(uid, callback) {
|
OAuth.deleteUserData = function (data, callback) {
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
async.apply(User.getUserField, uid, constants.name + 'Id'),
|
async.apply(User.getUserField, data.uid, constants.name + 'Id'),
|
||||||
function(oAuthIdToDelete, next) {
|
function (oAuthIdToDelete, next) {
|
||||||
db.deleteObjectField(constants.name + 'Id:uid', oAuthIdToDelete, next);
|
db.deleteObjectField(constants.name + 'Id:uid', oAuthIdToDelete, next);
|
||||||
}
|
},
|
||||||
], function(err) {
|
], function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
winston.error('[sso-oauth] Could not remove OAuthId data for uid ' + uid + '. Error: ' + err);
|
winston.error('[sso-oauth] Could not remove OAuthId data for uid ' + data.uid + '. Error: ' + err);
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
callback();
|
|
||||||
|
callback(null, data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// If this filter is not there, the deleteUserData function will fail when getting the oauthId for deletion.
|
||||||
|
OAuth.whitelistFields = function (params, callback) {
|
||||||
|
params.whitelist.push(constants.name + 'Id');
|
||||||
|
callback(null, params);
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = OAuth;
|
module.exports = OAuth;
|
||||||
}(module));
|
}(module));
|
||||||
|
30
package.json
30
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "nodebb-plugin-sso-oauth",
|
"name": "nodebb-plugin-sso-oauth",
|
||||||
"version": "0.2.0",
|
"version": "0.3.4",
|
||||||
"description": "NodeBB Generic OAuth SSO",
|
"description": "NodeBB Generic OAuth SSO",
|
||||||
"main": "library.js",
|
"main": "library.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
@ -11,8 +11,10 @@
|
|||||||
"nodebb",
|
"nodebb",
|
||||||
"plugin",
|
"plugin",
|
||||||
"oauth",
|
"oauth",
|
||||||
|
"oauth2",
|
||||||
"sso",
|
"sso",
|
||||||
"single sign on",
|
"single sign on",
|
||||||
|
"login",
|
||||||
"registration"
|
"registration"
|
||||||
],
|
],
|
||||||
"author": {
|
"author": {
|
||||||
@ -26,6 +28,32 @@
|
|||||||
"readme": "",
|
"readme": "",
|
||||||
"readmeFilename": "README.md",
|
"readmeFilename": "README.md",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"async": "^2",
|
||||||
"passport-oauth": "~1.0.0"
|
"passport-oauth": "~1.0.0"
|
||||||
|
},
|
||||||
|
"nbbpm": {
|
||||||
|
"compatibility": "^1.0.1",
|
||||||
|
"index": false
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@commitlint/cli": "^8.0.0",
|
||||||
|
"@commitlint/config-angular": "^7.1.2",
|
||||||
|
"eslint": "^5.16.0",
|
||||||
|
"eslint-config-airbnb-base": "^12.1.0",
|
||||||
|
"eslint-plugin-import": "^2.8.0",
|
||||||
|
"husky": "^2.4.0",
|
||||||
|
"lint-staged": "^8.2.0"
|
||||||
|
},
|
||||||
|
"husky": {
|
||||||
|
"hooks": {
|
||||||
|
"pre-commit": "lint-staged",
|
||||||
|
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"*.js": [
|
||||||
|
"eslint --fix",
|
||||||
|
"git add"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,8 @@
|
|||||||
"url": "https://github.com/julianlam/nodebb-plugin-sso-oauth",
|
"url": "https://github.com/julianlam/nodebb-plugin-sso-oauth",
|
||||||
"library": "./library.js",
|
"library": "./library.js",
|
||||||
"hooks": [
|
"hooks": [
|
||||||
{ "hook": "filter:user.delete", "method": "deleteUserData" },
|
{ "hook": "static:user.delete", "method": "deleteUserData" },
|
||||||
|
{ "hook": "filter:user.whitelistFields", "method": "whitelistFields" },
|
||||||
{ "hook": "filter:auth.init", "method": "getStrategy" }
|
{ "hook": "filter:auth.init", "method": "getStrategy" }
|
||||||
],
|
]
|
||||||
"templates": "./templates",
|
|
||||||
"minver": "0.5.0"
|
|
||||||
}
|
}
|
||||||
|
@ -1,81 +0,0 @@
|
|||||||
<h1><i class="fa fa-key"></i> Generic OAuth Authentication</h1>
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
<form class="sso-oauth-settings">
|
|
||||||
<div class="alert alert-warning">
|
|
||||||
<p>
|
|
||||||
Please refer to your OAuth provider's documentation for appropriate values. All fields are mandatory.
|
|
||||||
</p>
|
|
||||||
<br />
|
|
||||||
<select name="oauth:type" title="OAuth Strategy" class="form-control">
|
|
||||||
<option value="x">Disabled</option>
|
|
||||||
<option value="1">OAuth</option>
|
|
||||||
<option value="2">OAuth2</option>
|
|
||||||
</select>
|
|
||||||
<hr />
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" data-strategy="1" name="oauth:key" title="OAuth Key" class="form-control input-lg" placeholder="OAuth Key">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" data-strategy="1" name="oauth:secret" title="OAuth Secret" class="form-control" placeholder="OAuth Secret">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" data-strategy="1" name="oauth:reqTokenUrl" title="Token Request URL" class="form-control" placeholder="Token Request URL">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" data-strategy="1" name="oauth:accessTokenUrl" title="Access Token URL" class="form-control" placeholder="Access Token URL">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" data-strategy="1" name="oauth:authUrl" title="Authorization URL" class="form-control" placeholder="Authorization URL">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" data-strategy="2" name="oauth2:id" title="Client ID" class="form-control input-lg" placeholder="Client ID">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" data-strategy="2" name="oauth2:secret" title="Client Secret" class="form-control" placeholder="Client Secret">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" data-strategy="2" name="oauth2:authUrl" title="Authorization URL" class="form-control" placeholder="Authorization URL">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" data-strategy="2" name="oauth2:tokenUrl" title="Token URL" class="form-control" placeholder="Token URL">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" name="oauth:userProfileUrl" title="User Profile URL" class="form-control" placeholder="User Profile URL">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<button class="btn btn-lg btn-primary" type="button" id="save">Save</button>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
require(['settings'], function(Settings) {
|
|
||||||
Settings.load('sso-oauth', $('.sso-oauth-settings'), function() {
|
|
||||||
var OAuthType = $('[name="oauth:type"]').val();
|
|
||||||
toggleFields(OAuthType);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#save').on('click', function() {
|
|
||||||
Settings.save('sso-oauth', $('.sso-oauth-settings'));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
var toggleFields = function(value) {
|
|
||||||
if (value === '1') {
|
|
||||||
$('[data-strategy="2"]').hide();
|
|
||||||
$('[data-strategy="1"]').show();
|
|
||||||
} else if (value === '2') {
|
|
||||||
$('[data-strategy="1"]').hide();
|
|
||||||
$('[data-strategy="2"]').show();
|
|
||||||
} else {
|
|
||||||
$('[data-strategy]').hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleFields(false);
|
|
||||||
$('[name="oauth:type"]').on('change', function() {
|
|
||||||
toggleFields(this.value);
|
|
||||||
})
|
|
||||||
</script>
|
|
Loading…
Reference in New Issue
Block a user