Reference Source

js/security/todo/authentication_plugin_passport.js


// NPM IMPORTS
import assert from 'assert'
import passport from 'passport'

// COMMON IMPORTS
import T           from 'devapt-core-common/dist/js/utils/types'
import Credentials from 'devapt-core-common/dist/js/base/credentials'

import AuthenticationPlugin from './authentication_plugin'



let context = 'common/security/authentication_plugin_passport'



/**
 * Authentication base class for Passport strategies.
 * @abstract
 * @author Luc BORIES
 * @license Apache-2.0
 */
export default class AuthenticationPluginPassport extends AuthenticationPlugin
{
    /**
     * Create an Authentication class for all Passport strategies.
	 * @param {string} arg_name - plugin name.
	 * @param {string} arg_class - plugin class name.
     * @param {string|undefined} arg_log_context - optional.
     * @returns {nothing}
     */
	constructor(arg_name, arg_class, arg_log_context)
	{
		super(arg_name, 'AuthenticationPluginPassport', arg_log_context ? arg_log_context : context)
		
		this.is_authentication = true
		
		this.passport = passport
		this.strategies = {}
		this.strategies_names = []
	}
	
    
	/**
     * Enable authentication plugin with contextual informations.
     * @param {object|undefined} arg_settings - optional contextual settings.
     * @returns {object} - a promise object of a boolean result (success:true, failure:false)
     */
	enable(arg_settings)
	{
        const resolved_promise = super.enable(arg_settings)
        
        // SET FIELD NAMES FOR USER NAME
        if (arg_settings && T.isString(arg_settings.username_fieldname) )
        {
            this.username_fieldname = arg_settings.username_fieldname
        }
        
        // SET FIELD NAMES FOR PASSWORD
        if (arg_settings && T.isString(arg_settings.password_fieldname) )
        {
            this.password_fieldname = arg_settings.password_fieldname
        }
        
        // SET FIELD NAMES FOR ID
        if (arg_settings && T.isString(arg_settings.id_fieldname) )
        {
            this.id_fieldname = arg_settings.id_fieldname
        }
        
        // SET REDIRECTION ROUTE ON SUCCESS
        if (arg_settings && T.isString(arg_settings.success_redirect) )
        {
            this.success_redirect = arg_settings.success_redirect
        }
        
        // SET REDIRECTION ROUTE ON FAILURE
        if (arg_settings && T.isString(arg_settings.failure_redirect) )
        {
            this.failure_redirect = arg_settings.failure_redirect
        }
        
        // SET USE OF SESSION FLAG
        if (arg_settings && T.isBoolean(arg_settings.use_session) )
        {
            this.use_session = arg_settings.use_session
        }
        
        return resolved_promise
	}
    
    
	/**
     * Disable authentication plugin with contextual informations.
     * @param {object|undefined} arg_settings - optional contextual settings.
     * @returns {object} - a promise object of a boolean result (success:true, failure:false)
     */
	disable(arg_settings)
	{
        const resolved_promise = super.disable(arg_settings)
        return resolved_promise
	}
    
    
    /**
     * Apply authentication plugin io given server. Use a middleware.
     * @param {object} arg_server - Runtime server (Express/Restify server for example)
     * @returns {nothing}
     */
    apply_on_server(arg_server)
    {
        this.info('apply authentication on ' + arg_server.get_name())
        
        assert(T.isObject(arg_server), context + ':apply_on_server:bad server object')
        assert(arg_server.is_server, context + ':apply_on_server:bad server instance')
        
        // SERVER INIT MW: f(req,res,next)
        const mw_init = this.passport.initialize()
        assert(T.isFunction(mw_init), context + ':apply_on_server:bad middleware init function')
        arg_server.server.use(mw_init)
        
        // ENABLE PASSPORT SESSION
        if (this.use_session)
        {
            const mw_session = this.passport.session()
            assert(T.isFunction(mw_session), context + ':apply_on_server:bad middleware session function')
            arg_server.server.use(mw_session)
        }
    }
    
    
    /**
     * Get a authentication middleware to use on servers (see Connect/Express middleware signature).
     * @returns {function} - function(request,response,next){...}
     */
    create_middleware()
    {
        // USE PASSPORT STRATEGY
        const strategy = this.get_passport_strategy()
        assert(T.isObject(strategy), context + ':create_middleware:bad strategy object')
        this.passport.use(strategy)
        
        // STRATEGY NAME
        assert(T.isFunction(this.get_passport_strategy_name), context + ':create_middleware:bad strategy name function')
        const strategy_name = this.get_passport_strategy_name()
        assert(T.isString(strategy_name), context + ':create_middleware:bad stragegy name')
        
        const mw = passport.authenticate(strategy_name, { session: this.use_session })
        assert(T.isFunction(mw), context + ':create_middleware:bad middleware function')
        return mw
    }
    
    
    /**
     * Get a authentication route middleware to use on servers (see Connect/Express middleware signature).
     * @returns {function} - function(request,response){...}
     */
    create_route_middleware()
    {
        // USE PASSPORT STRATEGY
        const strategy = this.get_passport_strategy()
        assert(T.isObject(strategy), context + ':create_middleware:bad strategy object')
        this.passport.use(strategy)
        
        // STRATEGY NAME
        assert(T.isFunction(this.get_passport_strategy_name), context + ':create_middleware:bad strategy name function')
        const strategy_name = this.get_passport_strategy_name()
        assert(T.isString(strategy_name), context + ':create_middleware:bad stragegy name')
        
        // ROUTE MW: f(req,res)
        const mw = passport.authenticate(strategy_name, { session: this.use_session })
        assert(T.isFunction(mw), context + ':create_middleware:bad middleware function')
        
        return mw
    }
    
    
    /**
     * Get Passport strategy provided by this class.
     * @abstract
     * @returns {object} - Passport strategy instance
     */
    // get_passport_strategy()
    // {
    //     this.error_not_implemented()
    //     return null
    // }
    
    add_strategy(arg_name, arg_instance)
    {
        this.strategies_names.push('local')
    }
    
    
    add_local_strategy()
    {
        const self = this
        
        const LocalStrategy = passport_local.Strategy
        // const LocalStrategy = passport_local.BasicStrategy
        
        // BUILD LOCAL STRATEGY SETTINGS
        const settings = {}
        if (this.username_fieldname)
        {
            settings.usernameField = this.username_fieldname
        }
        if (this.password_fieldname)
        {
            settings.passwordField = this.password_fieldname
        }
        if (this.success_redirect)
        {
            settings.successRedirect = this.success_redirect
        }
        if (this.failure_redirect)
        {
            settings.failureRedirect = this.failure_redirect
        }
        settings.failureFlash = true
        
        // CREATE AND RETURN A LOCAL STRATEGY INSTANCE
        const strategy = new LocalStrategy(
            settings,
            function(arg_username, arg_password, arg_done_cb)
            {
                self.debug('LocalStrategy.authenticate')
                console.log(context + '.LocalStrategy:mw')
                
                const credentials = { 'user':arg_username, 'password':arg_password }
                const instance = new Credentials(credentials)
                instance.done_cb = arg_done_cb
                this.authenticate(instance)
            }
        )
        
        
        this.add_strategy('local', strategy)
    }
}