js/base/security.js
// NPM IMPORTS
import assert from 'assert'
import { fromJS } from 'immutable'
// COMMON IMPORTS
import T from 'devapt-core-common/dist/js/utils/types'
import Errorable from 'devapt-core-common/dist/js/base/errorable'
// SERVER IMPORTS
import AuthenticationManager from '../security/authentication_manager'
import AuthorizationManager from '../security/authorization_manager'
/**
* Contextual constant for this file logs.
* @private
* @type {string}
*/
const context = 'server/base/security'
/**
* @file Security class - main security features wrapper.
* @author Luc BORIES
* @license Apache-2.0
*/
export default class Security extends Errorable
{
/**
* Create a Security instance.
*
* @param {RuntimeBase} arg_runtime - runtime.
* @param {string} arg_log_context - trace logging context string.
* @param {object} arg_settings - runtime settings.
*
* @returns {nothing}
*/
constructor(arg_runtime, arg_log_context, arg_settings)
{
const logger_manager = (arg_settings && arg_settings.logger_manager) ? arg_settings.logger_manager : undefined
super(arg_log_context ? arg_log_context : context, logger_manager)
/**
* Class test flag.
* @type {boolean}
*/
this.is_security = true
/**
* Application is read only flag.
* @type {boolean}
*/
this.is_readonly = true
/**
* Authentication manager instance.
* @type {AuthenticationManager}
*/
this.authentication_manager = new AuthenticationManager(arg_runtime, context + '.authentication', logger_manager)
/**
* Authorization manager instance.
* @type {AuthorizationManager}
*/
this.authorization_manager = new AuthorizationManager(arg_runtime, context + '.authorization', logger_manager)
if (arg_settings)
{
const logger_manager_only = Object.keys(arg_settings).length == 1 && arg_settings.logger_manager
if ( ! logger_manager_only)
{
if ( ! arg_settings.has )
{
arg_settings = fromJS(arg_settings)
}
this.load(arg_settings)
}
}
}
/**
* Load security settings.
*
* @param {object} arg_settings - runtime settings (Immutable object).
*
* @returns {nothing}
*/
load(arg_settings)
{
this.enter_group('load')
// this.debug('settings', arg_settings)
// console.log(context + '.load:arg_settings', arg_settings)
assert(T.isObject(arg_settings), context + ':bad settings object')
assert(T.isFunction(arg_settings.has), context + ':bad settings immutable')
assert(arg_settings.has('authentication'), context + ':bad settings.authentication')
assert(arg_settings.has('authorization'), context + ':bad settings.authorization')
const authentication = arg_settings.get('authentication')
const authorization = arg_settings.get('authorization')
this.is_readonly = arg_settings.get('is_readonly')
this.authentication_manager.load(authentication)
this.authorization_manager.load(authorization)
/*
TODO
https://gist.github.com/danwit/e0a7c5ad57c9ce5659d2
https://github.com/OptimalBits/node_acl
http://www.hamiltonchapman.com/blog/2014/3/25/user-accounts-using-sequelize-and-passport-in-nodejs
*/
this.leave_group('load')
}
/**
* Get authentication plugins manager.
*
* @returns {object} - a PluginsManager instance
*/
get_authentication_manager()
{
return this.authentication_manager
}
/**
* Get authorization plugins manager.
*
* @returns {object} - a PluginsManager instance.
*/
get_authorization_manager()
{
return this.authorization_manager
}
/**
* Get authentication plugins manager.
*
* @returns {object} - a PluginsManager instance.
*/
authentication()
{
assert( T.isObject(this.authentication_manager) && this.authentication_manager.is_authentication_manager, context + ':bad authentication_manager object')
return this.authentication_manager
}
/**
* Authenticate a user with giving credentials.
*
* @param {Credentials} arg_credentials - credentials object.
*
* @returns {Promise} - a promise of boolean.
*/
authenticate(arg_credentials)
{
this.enter_group('authenticate')
const auth_mgr = this.authentication()
let promise = Promise.resolve(true)
if (auth_mgr.authentication_is_enabled)
{
promise = auth_mgr.authenticate(arg_credentials)
}
this.leave_group('authenticate')
return promise
}
/**
* Get authorization plugins manager.
*
* @returns {object} - a PluginsManager instance.
*/
authorization()
{
assert( T.isObject(this.authorization_manager) && this.authorization_manager.is_authorization_manager, context + ':bad authorization_manager object')
return this.authorization_manager
}
/**
* Authenticate a user with giving credentials.
*
* @param {object} arg_permission - permission plain object.
* @param {object} arg_credentials - credentials object.
*
* @returns {Promise} - a promise of boolean.
*/
authorize(arg_permission, arg_credentials)
{
this.enter_group('authorize')
const auth_mgr = this.authorization()
let promise = Promise.resolve(true)
if (auth_mgr.authorization_is_enabled)
{
promise = auth_mgr.authorize(arg_permission, arg_credentials)
}
// const promise = this.authorization().authorize(arg_permission, arg_credentials)
this.leave_group('authorize')
return promise
}
// PREDEFINED ERRORS
/**
* Error wrapper - on bad user.
*
* @returns {nothing}
*/
error_bad_user()
{
this.error('bad user')
}
/**
* Error wrapper - on bad credentials.
*
* @returns {nothing}
*/
error_bad_credentials()
{
this.error('bad credentials')
}
}
/*
EXAMPLE OF CONFIGURATION
"security":{
"is_readonly":false,
"connexions":["connexions.json"],
"authentication": {
"enabled":true,
"expiration":60,
"secret":"APPPPPPP449++((éç(à",
"mode":"database",
"model":"MODEL_AUTH_USERS",
"username":"login",
"password":"password",
"alt": {
"mode":"jsonfile",
"file":"users.json",
"login":"demo",
"password":"demo"
}
},
"authorization": {
"enabled":true,
"mode":"database",
"model":"MODEL_AUTH_USERS_ROLES",
"role":"label",
"username":"users_login",
"alt": {
"mode":"jsonfile",
"file":"users.json"
},
"roles":{
"*": {
"list_resources":"ROLE_RESOURCES_LIST",
"get_resource":"ROLE_RESOURCE_GET"
},
"views": {
"list_resources":"ROLE_RESOURCES_LIST",
"get_resource":"ROLE_RESOURCE_GET"
}
}
}
}
*/
/*
AUTHENTICATION
"authentication": {
"enabled":true,
"expiration":60,
"secret":"APPPPPPP449++((éç(à",
"mode":"database",
"model":"MODEL_AUTH_USERS",
"username":"login",
"password":"password",
"alt": {
"mode":"jsonfile",
"file":"users.json",
"login":"demo",
"password":"demo"
}
},
"authentication":
mandatories:"enabled", "mode"
mode:
database:
model:mandatory
username:mandatory
password:mandatory
jsonfile:
file:mandatory
username:mandatory
password:mandatory
*/