2014-01-29 16:42:06 +00:00
( function ( module ) {
"use strict" ;
var User = module . parent . require ( './user' ) ,
2014-07-22 14:03:52 +00:00
Groups = module . parent . require ( './groups' ) ,
2014-02-22 04:10:12 +00:00
meta = module . parent . require ( './meta' ) ,
2014-01-29 16:42:06 +00:00
db = module . parent . require ( '../src/database' ) ,
passport = module . parent . require ( 'passport' ) ,
2014-01-29 16:42:50 +00:00
fs = module . parent . require ( 'fs' ) ,
path = module . parent . require ( 'path' ) ,
nconf = module . parent . require ( 'nconf' ) ,
winston = module . parent . require ( 'winston' ) ,
2014-07-10 07:22:44 +00:00
async = module . parent . require ( 'async' ) ,
2014-01-29 16:42:50 +00:00
passportOAuth ;
2014-01-29 16:42:06 +00:00
var constants = Object . freeze ( {
'name' : "Generic OAuth" ,
'admin' : {
2014-03-19 00:04:18 +00:00
'route' : '/plugins/sso-oauth' ,
2014-01-29 16:42:06 +00:00
'icon' : 'fa-key'
}
} ) ;
var OAuth = { } ;
2014-07-22 14:03:52 +00:00
OAuth . init = function ( app , middleware , controllers , callback ) {
2014-03-19 00:04:18 +00:00
function render ( req , res , next ) {
res . render ( 'admin/plugins/sso-oauth' , { } ) ;
}
2014-02-04 17:09:46 +00:00
2014-03-19 00:04:18 +00:00
app . get ( '/admin/plugins/sso-oauth' , middleware . admin . buildHeader , render ) ;
app . get ( '/api/admin/plugins/sso-oauth' , render ) ;
2014-07-22 14:03:52 +00:00
callback ( ) ;
2014-03-19 00:04:18 +00:00
} ;
2014-02-04 17:09:46 +00:00
2014-03-19 00:04:18 +00:00
OAuth . getStrategy = function ( strategies , callback ) {
meta . settings . get ( 'sso-oauth' , function ( err , settings ) {
2014-03-19 12:42:01 +00:00
if ( err ) {
winston . error ( '[plugins/sso-oauth] Could not retrieve OAuth settings: ' + err . message ) ;
} else if ( ! settings ) {
settings = { } ;
}
2014-03-19 00:04:18 +00:00
var oAuthKeys = [ 'oauth:reqTokenUrl' , 'oauth:accessTokenUrl' , 'oauth:authUrl' , 'oauth:key' , 'oauth:secret' ] ,
oAuth2Keys = [ 'oauth2:authUrl' , 'oauth2:tokenUrl' , 'oauth2:id' , 'oauth2:secret' ] ,
configOk = oAuthKeys . every ( function ( key ) {
return settings [ key ] ;
} ) || oAuth2Keys . every ( function ( key ) {
return settings [ key ] ;
} ) ,
opts ;
2014-03-19 12:42:01 +00:00
if ( settings [ 'oauth:type' ] === '2' ) {
passportOAuth = require ( 'passport-oauth' ) . OAuth2Strategy ;
} else if ( settings [ 'oauth:type' ] === '1' ) {
passportOAuth = require ( 'passport-oauth' ) . OAuthStrategy ;
}
2014-03-19 00:04:18 +00:00
if ( passportOAuth && configOk ) {
if ( settings [ 'oauth:type' ] === '1' ) {
// OAuth options
opts = {
requestTokenURL : settings [ 'oauth:reqTokenUrl' ] ,
accessTokenURL : settings [ 'oauth:accessTokenUrl' ] ,
userAuthorizationURL : settings [ 'oauth:authUrl' ] ,
consumerKey : settings [ 'oauth:key' ] ,
consumerSecret : settings [ 'oauth:secret' ] ,
callbackURL : nconf . get ( 'url' ) + '/auth/generic/callback'
} ;
passportOAuth . Strategy . prototype . userProfile = function ( token , secret , params , done ) {
this . _oauth . get ( settings [ 'oauth:userProfileUrl' ] , token , secret , function ( err , body , res ) {
if ( err ) { return done ( new InternalOAuthError ( 'failed to fetch user profile' , err ) ) ; }
try {
var json = JSON . parse ( body ) ;
var profile = { provider : 'generic' } ;
// Uncomment the following lines to include whatever data is necessary
// NodeBB requires the following: id, displayName, emails, e.g.:
// profile.id = json.id;
// profile.displayName = json.name;
// profile.emails = [{ value: json.email }];
done ( null , profile ) ;
} catch ( e ) {
done ( e ) ;
}
} ) ;
} ;
} else if ( settings [ 'oauth:type' ] === '2' ) {
// OAuth 2 options
opts = {
authorizationURL : settings [ 'oauth2:authUrl' ] ,
tokenURL : settings [ 'oauth2:tokenUrl' ] ,
clientID : settings [ 'oauth2:id' ] ,
clientSecret : settings [ 'oauth2:secret' ] ,
callbackURL : nconf . get ( 'url' ) + '/auth/generic/callback'
} ;
passportOAuth . Strategy . prototype . userProfile = function ( accessToken , done ) {
this . _oauth2 . get ( settings [ 'oauth:userProfileUrl' ] , accessToken , function ( err , body , res ) {
if ( err ) { return done ( new InternalOAuthError ( 'failed to fetch user profile' , err ) ) ; }
try {
var json = JSON . parse ( body ) ;
var profile = { provider : 'generic' } ;
// Alter this section to include whatever data is necessary
2014-07-22 14:03:52 +00:00
// NodeBB *requires* the following: id, displayName, emails.
// Everything else is optional.
2014-03-19 00:04:18 +00:00
2014-03-19 12:42:01 +00:00
profile . id = json . id ;
profile . displayName = json . name ;
profile . emails = [ { value : json . email } ] ;
2014-03-19 00:04:18 +00:00
2014-07-22 14:03:52 +00:00
// Do you want to automatically make somebody an admin? This block might help you do that...
// profile.isAdmin = json.isAdmin ? true : false;
2014-03-19 00:04:18 +00:00
// Find out what is available by uncommenting this line:
// console.log(json);
// Delete or comment out the next TWO (2) lines when you are ready to proceed
2014-07-22 14:03:52 +00:00
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 done ( new Error ( 'Congrats! So far so good -- please see server log for details' ) ) ;
2014-03-19 00:04:18 +00:00
done ( null , profile ) ;
} catch ( e ) {
done ( e ) ;
}
} ) ;
} ;
}
2014-02-04 17:09:46 +00:00
2014-03-19 00:04:18 +00:00
passport . use ( 'Generic OAuth' , new passportOAuth ( opts , function ( token , secret , profile , done ) {
2014-07-22 14:03:52 +00:00
OAuth . login ( {
oAuthid : profile . id ,
handle : profile . displayName ,
email : profile . emails [ 0 ] . value ,
isAdmin : profile . isAdmin
} , function ( err , user ) {
2014-03-19 00:04:18 +00:00
if ( err ) {
return done ( err ) ;
2014-02-04 17:09:46 +00:00
}
2014-03-19 00:04:18 +00:00
done ( null , user ) ;
2014-02-04 17:09:46 +00:00
} ) ;
2014-03-19 00:04:18 +00:00
} ) ) ;
strategies . push ( {
name : 'Generic OAuth' ,
url : '/auth/oauth' ,
callbackURL : '/auth/generic/callback' ,
icon : 'check' ,
scope : ( settings [ 'oauth:scope' ] || '' ) . split ( ',' )
2014-01-29 16:42:06 +00:00
} ) ;
2014-03-19 00:04:18 +00:00
callback ( null , strategies ) ;
} else {
winston . info ( '[plugins/sso-oauth] OAuth Disabled or misconfigured. Proceeding without Generic OAuth Login' ) ;
callback ( null , strategies ) ;
}
} ) ;
2014-01-29 16:42:06 +00:00
} ;
2014-07-22 14:03:52 +00:00
OAuth . login = function ( payload , callback ) {
OAuth . getUidByOAuthid ( payload . oAuthid , function ( err , uid ) {
2014-01-29 16:42:06 +00:00
if ( err ) {
return callback ( err ) ;
}
if ( uid !== null ) {
// Existing User
callback ( null , {
uid : uid
} ) ;
} else {
// New User
var success = function ( uid ) {
// Save provider-specific information to the user
2014-07-22 14:03:52 +00:00
User . setUserField ( uid , 'oAuthid' , payload . oAuthid ) ;
db . setObjectField ( 'oAuthid:uid' , payload . oAuthid , uid ) ;
if ( payload . isAdmin ) {
Groups . join ( 'administrators' , uid , function ( err ) {
callback ( null , {
uid : uid
} ) ;
} ) ;
} else {
callback ( null , {
uid : uid
} ) ;
}
2014-01-29 16:42:06 +00:00
} ;
2014-07-22 14:03:52 +00:00
User . getUidByEmail ( payload . email , function ( err , uid ) {
2014-01-29 16:42:06 +00:00
if ( err ) {
return callback ( err ) ;
}
if ( ! uid ) {
2014-07-22 14:03:52 +00:00
User . create ( {
username : payload . handle ,
email : payload . email
} , function ( err , uid ) {
2014-01-29 16:42:06 +00:00
if ( err ) {
return callback ( err ) ;
}
success ( uid ) ;
} ) ;
} else {
success ( uid ) ; // Existing account -- merge
}
} ) ;
}
} ) ;
} ;
OAuth . getUidByOAuthid = function ( oAuthid , callback ) {
2014-02-04 17:09:46 +00:00
db . getObjectField ( 'oAuthid:uid' , oAuthid , function ( err , uid ) {
2014-01-29 16:42:06 +00:00
if ( err ) {
return callback ( err ) ;
}
callback ( null , uid ) ;
} ) ;
} ;
2014-03-19 00:04:18 +00:00
OAuth . addMenuItem = function ( custom _header , callback ) {
2014-01-29 16:42:06 +00:00
custom _header . authentication . push ( {
"route" : constants . admin . route ,
"icon" : constants . admin . icon ,
"name" : constants . name
} ) ;
2014-03-19 00:04:18 +00:00
callback ( null , custom _header ) ;
} ;
2014-01-29 16:42:06 +00:00
OAuth . addAdminRoute = function ( custom _routes , callback ) {
fs . readFile ( path . resolve ( _ _dirname , './static/admin.tpl' ) , function ( err , template ) {
custom _routes . routes . push ( {
"route" : constants . admin . route ,
"method" : "get" ,
"options" : function ( req , res , callback ) {
callback ( {
req : req ,
res : res ,
route : constants . admin . route ,
name : constants . name ,
content : template
} ) ;
}
} ) ;
callback ( null , custom _routes ) ;
} ) ;
} ;
2014-07-10 07:22:44 +00:00
OAuth . deleteUserData = function ( uid , callback ) {
async . waterfall ( [
async . apply ( User . getUserField , uid , 'oAuthid' ) ,
function ( oAuthIdToDelete , next ) {
db . deleteObjectField ( 'oAuthid:uid' , oAuthIdToDelete , next ) ;
2014-07-09 07:32:44 +00:00
}
2014-07-10 07:22:44 +00:00
] , function ( err ) {
if ( err ) {
winston . error ( 'Could not remove OAuthId data for uid ' + uid + '. Error: ' + err ) ;
return callback ( err ) ;
2014-07-09 07:32:44 +00:00
}
2014-07-10 07:22:44 +00:00
callback ( ) ;
2014-07-09 07:32:44 +00:00
} ) ;
} ;
2014-01-29 16:42:06 +00:00
module . exports = OAuth ;
} ( module ) ) ;