npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

access-controls

v0.5.6

Published

rule based access-controls engine for node.js (browser compatible)

Downloads

95

Readme

Build Status

install

node.js

npm install --save access-controls

browser

Use the file in dist/access-controls.js

<script src="access-controls.js"></script>


var procedure = new AccessControls(accessControlList)

procedure.authorize(obj, action, roles, context, function(err, authDecision) {
  // authDecision attributes
  // authorize: true | false
  // history: a list of the ACLs run
  // inherit: if there is an inheritance condition to access this entity
  // filters: an array of filters if some fields need filtering.
  //          You can use procedure.applyFilters(authDecision.filters, obj) to
  //          apply them
})

Usage

var accessControlList = [{
  name: 'EMEA_region',
  roles: ['EMEA'],
  control: 'required',
  actions: 'r',
  conditions: [{
      attributes: {
        'region': 'EMEA'
      }
    }
  ]
}, {
  name: 'legal_group',
  roles: ['legal'],
  control: 'required',
  actions: ['load'],
  conditions: [{
      attributes: {
        'group': 'legal'
      }
    }
  ]
}, {
  name: 'admin all access',
  roles: ['admin'],
  control: 'sufficient',
  actions: ['load', 'list', 'save', 'remove']
}]

var procedure = new AccessControlProcedure(accessControlList)

proc = procedure.authorize(obj, context, action)

proc.on('deny', function(details) {

})

proc.on('grant', function(details) {

})

proc.on('dependency', function(details) {

})

Access Controls

An access control procedure runs a set of ACLs against a given pair of entity and action

An ACL is composed of:

  • a list of roles which are required for this ACL to authorize
  • a set of actions (save, update, get, list)
  • on a given entity (the type as well as specific attributes values)
  • a control type (one of required|requisite|sufficient) that determine what happens should the ACL fail or succeed:
    • required — The service result must be successful for authentication to continue. If the test fails at this point, the user is not notified until the results of all service tests that reference that interface are complete.
    • requisite — The service result must be successful for authentication to continue. However, if a test fails at this point, the user is notified immediately with a message reflecting the first failed required or requisite service test.
    • sufficient — The service result is ignored if it fails. However, if the result of a service flagged sufficient is successful and no previous services flagged required have failed, then no other results are required and the user is authenticated to the service.

IMPORTANT: The order in which required ACLs are called is not critical. Only the sufficient and requisite control flags cause order to become important.

Examples:

    si.use( '..', {
      accessControls: [{
        name: 'access to foobar entities',
        roles: ['foobar'],
        entities: [{
          zone: undefined,
          base: undefined,
          name: 'foobar'
        }],
        control: 'required',
        actions: ['save', 'load', 'list', 'remove'],
        conditions: []
      },{
        name: 'access to foobar EMEA entities',
        roles: ['EMEA'],
        entities: [{
          zone: undefined,
          base: undefined,
          name: 'foobar'
        }],
        control: 'required',
        actions: ['save', 'load', 'list', 'remove'],
        conditions: [{
            attributes: {
              'region': 'EMEA'
            }
          }
        ]
      },{
        name: 'access to foobar EMEA entities',
        roles: ['private_items'],
        entities: [{
          zone: undefined,
          base: undefined,
          name: 'item'
        }],
        control: 'required',
        actions: ['load'],
        conditions: [{
            attributes: {
              'status': 'private'
            }
          }
        ]
      }]
    })

Field level access/masking

Field masking works a bit differently compared to other ACLs.

It is possible to mask or deny access to specific fields IF the access roles are not met.

For example:

si.use( '..', {
  accessControls: [{
    name: 'access to foobar entities',
    roles: ['foobar', 'ssn'],
    entities: [{
      zone: undefined,
      base: undefined,
      name: 'foobar'
    }],
    control: 'filter',
    actions: ['load'],
    conditions: [{
        attributes: {
          'status': 'private'
        }
      }
    ],
    filters: {
      lastName: false,
      ssn: function(value) {
        if(value) {
          value = '***-***-' + value.substr(-4)
        }
      }
    }
  }]
})

Will:

  • mask the field ssn and only display the last 4 digits
  • completely hide the field lastName

for all access except those with roles foobar and ssn.

manual validation

You can manually invoke the ACLs by setting the perm$ attribute in the arguments:

  var publicAccess = si.delegate({perm$:{roles:[]}})
  var pf1 = publicAccess.make('item',{number: 1, status: 'public'})

  var privateAccess = si.delegate({perm$:{roles:['private_items']}})
  var pf2 = privateAccess.make('item',{number: 2, status: 'private'})

current context

In some cases, you want to run access controls against the current logged in user. For this, you can reference the current user in an ACL:

si.use( '..', {
  accessControls: [{
    name: 'todos: owner only',
    roles: ['my_todos'],
    entities: [{
      zone: undefined,
      base: undefined,
      name: 'todo'
    }],
    control: 'required',
    actions: ['save', 'load', 'list', 'remove'],
    conditions: [{
        attributes: {
          'owner': '{user.id}'
        }
      }
    ]
  }]
})

The above will allow users to only create, read, update or delete 'todo' objects where they are the owner.