@ -4,13 +4,18 @@
'use strict' ;
'use strict' ;
const passport = require ( 'passport' ) ;
const mongoose = require ( 'mongoose' ) ;
const mongoose = require ( 'mongoose' ) ;
const Schema = mongoose . Schema ;
const OAuth2Client = mongoose . model ( 'OAuth2Client' ) ;
const OAuth2AuthorizationCode = mongoose . model ( 'OAuth2AuthorizationCode' ) ;
const OAuth2AccessToken = mongoose . model ( 'OAuth2AccessToken' ) ;
const uuidv4 = require ( 'uuid' ) . v4 ;
const uuidv4 = require ( 'uuid' ) . v4 ;
const striptags = require ( 'striptags' ) ;
const oauth2orize = require ( 'oauth2orize' ) ;
const oauth2orize = require ( 'oauth2orize' ) ;
const passport = require ( 'passport' ) ;
const generatePassword = require ( 'password-generator' ) ;
const { SiteService /*, SiteError*/ } = require ( '../../lib/site-lib' ) ;
const { SiteService /*, SiteError*/ } = require ( '../../lib/site-lib' ) ;
@ -21,69 +26,32 @@ class OAuth2Service extends SiteService {
}
}
async start ( ) {
async start ( ) {
this . models = { } ;
const serverOptions = { } ;
/ *
this . log . info ( 'creating OAuth2 server instance' , { serverOptions } ) ;
* OAuth2Client Model
this . server = oauth2orize . createServer ( serverOptions ) ;
* /
const ClientSchema = new Schema ( {
this . log . info ( 'registering OAuth2 action handlers' ) ;
created : { type : Date , default : Date . now , required : true } ,
updated : { type : Date , default : Date . now , required : true } ,
secret : { type : String , required : true } ,
redirectURI : { type : String , required : true } ,
} ) ;
this . log . info ( 'registering OAuth2Client model' ) ;
this . models . Client = mongoose . model ( 'OAuth2Client' , ClientSchema ) ;
/ *
* OAuth2AuthorizationCode model
* /
const AuthorizationCodeSchema = new Schema ( {
code : { type : String , required : true , index : 1 } ,
clientId : { type : Schema . ObjectId , required : true , index : 1 } ,
redirectURI : { type : String , required : true } ,
user : { type : Schema . ObjectId , required : true , index : 1 } ,
scope : { type : [ String ] , required : true } ,
} ) ;
this . log . info ( 'registering OAuth2AuthorizationCode model' ) ;
this . models . AuthorizationCode = mongoose . model ( 'OAuth2AuthorizationCode' , AuthorizationCodeSchema ) ;
/ *
* OAuth2AccessToken model
* /
const AccessTokenSchema = new Schema ( {
token : { type : String , required : true , unique : true , index : 1 } ,
user : { type : Schema . ObjectId , required : true , index : 1 } ,
clientId : { type : Schema . ObjectId , required : true , index : 1 } ,
scope : { type : [ String ] , required : true } ,
} ) ;
this . log . info ( 'registering OAuth2AccessToken model' ) ;
this . models . AccessToken = mongoose . model ( 'OAuth2AccessToken' , AccessTokenSchema ) ;
/ *
* Create OAuth2 server instance
* /
const options = { } ;
this . log . info ( 'creating OAuth2 server instance' , { options } ) ;
this . server = oauth2orize . createServer ( options ) ;
this . server . grant ( oauth2orize . grant . code ( this . processGrant . bind ( this ) ) ) ;
this . server . grant ( oauth2orize . grant . code ( this . processGrant . bind ( this ) ) ) ;
this . server . exchange ( oauth2orize . exchange . code ( this . processExchange . bind ( this ) ) ) ;
this . server . exchange ( oauth2orize . exchange . code ( this . processExchange . bind ( this ) ) ) ;
/ *
this . log . info ( 'registering OAuth2 serialization routines' ) ;
* Register client serialization callbacks
* /
this . log . info ( 'registering OAuth2 client serialization routines' ) ;
this . server . serializeClient ( this . serializeClient . bind ( this ) ) ;
this . server . serializeClient ( this . serializeClient . bind ( this ) ) ;
this . server . deserializeClient ( this . deserializeClient . bind ( this ) ) ;
this . server . deserializeClient ( this . deserializeClient . bind ( this ) ) ;
}
}
async serializeClient ( client , done ) {
async serializeClient ( client , done ) {
this . log . debug ( 'serializeClient' , { client } ) ;
return done ( null , client . id ) ;
return done ( null , client . id ) ;
}
}
async deserializeClient ( clientId , done ) {
async deserializeClient ( clientId , done ) {
this . log . debug ( 'deserializeClient' , { clientId } ) ;
try {
try {
const client = await this . models . Client . findOne ( { _ id : clientId } ) . lean ( ) ;
const client = await OAuth2Client
. findOne ( { _ id : clientId } )
. lean ( ) ;
this . log . debug ( 'OAuth2 client loaded' , { clientId , client } ) ;
return done ( null , client ) ;
return done ( null , client ) ;
} catch ( error ) {
} catch ( error ) {
this . log . error ( 'failed to deserialize OAuth2 client' , { clientId , error } ) ;
this . log . error ( 'failed to deserialize OAuth2 client' , { clientId , error } ) ;
@ -125,7 +93,7 @@ class OAuth2Service extends SiteService {
async processAuthorize ( clientID , redirectURI , done ) {
async processAuthorize ( clientID , redirectURI , done ) {
try {
try {
const client = await this . models . Clients . findOne ( { clientID } ) ;
const client = await OAuth2Client . findOne ( { clientID } ) ;
if ( ! client ) {
if ( ! client ) {
return done ( null , false ) ;
return done ( null , false ) ;
}
}
@ -142,7 +110,7 @@ class OAuth2Service extends SiteService {
async processGrant ( client , redirectURI , user , ares , done ) {
async processGrant ( client , redirectURI , user , ares , done ) {
try {
try {
var code = uuidv4 ( ) ;
var code = uuidv4 ( ) ;
var ac = new this . models . AuthorizationCode ( {
var ac = new OAuth2 AuthorizationCode( {
code ,
code ,
clientId : client . id ,
clientId : client . id ,
redirectURI ,
redirectURI ,
@ -159,7 +127,7 @@ class OAuth2Service extends SiteService {
async processExchange ( client , code , redirectURI , done ) {
async processExchange ( client , code , redirectURI , done ) {
try {
try {
const ac = await this . models . AuthorizationCode . findOne ( { code } ) ;
const ac = await OAuth2 AuthorizationCode. findOne ( { code } ) ;
if ( client . id !== ac . clientId ) {
if ( client . id !== ac . clientId ) {
return done ( null , false ) ;
return done ( null , false ) ;
}
}
@ -168,7 +136,7 @@ class OAuth2Service extends SiteService {
}
}
var token = uuidv4 ( ) ;
var token = uuidv4 ( ) ;
var at = new this . models . AccessToken ( {
var at = new OAuth2 AccessToken( {
token ,
token ,
user : ac . userId ,
user : ac . userId ,
clientId : ac . clientId ,
clientId : ac . clientId ,
@ -182,6 +150,46 @@ class OAuth2Service extends SiteService {
return done ( error ) ;
return done ( error ) ;
}
}
}
}
/ * *
* Creates a new OAuth2 client , and generates a Client ID and Secret for it .
* @ param { User } user The authenticated user issuing the request to create an
* "app" for use when calling DTP APIs .
* @ param { Document } clientDefinition The definition of the client to be
* created including the name and domain of the node .
* @ returns new client instance with valid _ id .
* /
async createClient ( user , clientDefinition ) {
const NOW = new Date ( ) ;
const PASSWORD_LEN = parseInt ( process . env . DTP_CORE_AUTH_PASSWORD_LEN || '64' , 10 ) ;
const client = new OAuth2Client ( ) ;
client . created = NOW ;
client . updated = NOW ;
client . node . owner = user . _ id ;
client . node . name = striptags ( clientDefinition . name . trim ( ) ) ;
client . node . domain = striptags ( clientDefinition . domain . trim ( ) . toLowerCase ( ) ) ;
client . user = user . _ id ;
client . secret = generatePassword ( PASSWORD_LEN , false ) ;
client . redirectURI = clientDefinition . redirectURI ;
await client . save ( ) ;
this . log . info ( 'new OAuth2 client created' , {
clientId : client . _ id ,
owner : user . _ id ,
node : client . node . name ,
domain : client . node . domain ,
} ) ;
return client . toObject ( ) ;
}
async getClientById ( clientId ) {
const client = await OAuth2Client
. findOne ( { _ id : clientId } )
. lean ( ) ;
return client ;
}
}
}
module . exports = {
module . exports = {