@scispike/domain-object-security
v1.0.0-rc.2
Published
Domain object security
Downloads
4
Maintainers
Readme
domain-object-security
This library allows you to secure your domain objects, so that you can ask questions like "Can Sally read Bob's account balance?" or "Can bank teller Jan close account #123?"
DEPRECATION NOTE: Since the time this package was created, SciSpike has been acquired by Northscaler. There will be no further development on this module. Instead, development will continue at either @northscaler/method-access-controller for functionality related to
RoleTypeBasedObjectAccessControlRepository
, which has been rename there toMethodAccessController
, or @northscaler-public/securable-trait forSecurable
. You can see all of Northscaler's public Node.js modules at https://www.npmjs.com/search?q=%40northscaler.
The primary export of this module is a trait called Securable
, which you can cause your class(es) to express; see our mutrait
package for full trait support in JavaScript.
TL;DR
File Account.js
:
const { traits } = require('mutrait')
const { Securable } = require('@scispike/domain-object-security')
class Account extends traits(Securable) {
constructor (balance = 0, openedAt = new Date()) {
super(balance, openedAt)
this._balance = balance
this.openedAt = openedAt
this.closedAt = null
}
get balance () { return this._balance }
deposit (amount) { this._balance += amount }
withdraw (amount) { this._balance -= amount }
close (at = new Date()) { this.closedAt = at }
get open () { return !this.closed }
get closed () { return !!this.closedAt }
}
module.exports = Account
File index.js
:
const Account = require('./Account')
const sally = 'sally'
const keith = 'keith'
const acct = new Account()
console.log(acct.secured) // false
console.log(acct.grants({ principals: sally, actions: 'get balance' })) // true
console.log(acct.grants({ principals: sally, actions: 'close' })) // true
console.log(acct.grants({ principals: keith, actions: 'get balance' })) // true
console.log(acct.grants({ principals: keith, actions: 'close' })) // true
acct.grant({ principal: sally, action: 'get balance' })
acct.grant({ principal: sally, action: 'close' })
console.log(acct.secured) // true
console.log(acct.grants({ principals: sally, actions: 'get balance' })) // true
console.log(acct.grants({ principals: keith, actions: 'close' })) // false
console.log(acct.grants({ principals: sally, actions: 'get balance' })) // true
console.log(acct.grants({ principals: keith, actions: 'close' })) // false
TIP: When you combine this library with method interception via
@scispike/aspectify
and withClsHookedContext
orZoneJsContext
from@scispike/nodejs-support
, you can completely isolate the crosscutting concern of security.
File Secured.js
:
const { Before } = require('@scispike/aspectify')
const Context = require('@scispike/nodejs-support/context/ClsHookedContext')
const Secured = Before(({ thisJoinPoint }) => {
if (!thisJoinPoint.thiz || thisJoinPoint?.thiz === thisJoinPoint?.clazz) {
return // because we're in a static context or there's no securable to call securable.grants on
}
const token = Context().get('token')
if (!thisJoinPoint.thiz.grants({
principals: token.principal,
actions: thisJoinPoint.fullName
})) {
const e = new Error(`E_UNAUTHORIZED`)
e.principal = token.principal
e.clazz = thisJoinPoint.clazz.constructor.name
e.method = thisJoinPoint.fullName
throw e
}
})
module.exports = Secured
File Account.js
:
const { traits } = require('mutrait')
const { Securable } = require('@scispike/domain-object-security')
const Secured = require('./Secured')
class Account extends traits(Securable) {
constructor (balance = 0, openedAt = new Date()) {
super(balance, openedAt)
this._balance = balance
this.openedAt = openedAt
this.closedAt = null
}
@Secured
get balance () { return this._balance }
@Secured
deposit (amount) { this._balance += amount }
@Secured
withdraw (amount) { this._balance -= amount }
@Secured
close (at = new Date()) { this.closedAt = at }
@Secured
get open () { return !this.closed }
@Secured
get closed () { return !!this.closedAt }
}
module.exports = Account
TODO
There's more to write here, but for now, see the tests in src/test/unit/Securable.spec.js
for usage.