Giter Site home page Giter Site logo

kmwang / permissions Goto Github PK

View Code? Open in Web Editor NEW

This project forked from tuhlmann/permissions

0.0 1.0 0.0 21 KB

A library that handles user roles and permissions. Modeled after Apache Shiro's permissions: http://shiro.apache.org/permissions.html

License: Eclipse Public License 1.0

Clojure 100.00%

permissions's Introduction

permissions

A library that handles user roles and permissions. Modeled after Apache Shiro's WildcardPermission.

Please see the JavaDoc for WildcardPermission for detailed information.

See permissions_test.cljc for examples.

Clojars Project

Installation

To install, add the following to your project :dependencies:

[agynamix/permissions "0.2.0-SNAPSHOT"]

Usage

A permission consists of three parts; a domain, a set of actions, and a set of entities.

If any of those is not given it defaults to a wildcard permission, or "*".

A domain is usually an area in your application that this permission should be applicable for. For instance if you have an area in your application managing user accounts, domain could be "users". You might have privileged users that are allowed to edit user accounts and those that can only read them. So one permission could be "users:read" while other could receive "users:edit" (it's up to you how you name these actions or how many you introduce.

Finally, you might want to allow some users only to edit some user records, that's where the third part, the entity list comes in. "users:edit:12345,12346" would require users to either name that entity in the list of entities they are allowed to edit. Or alternatively as in the examples above, if you omit that field it becomes "*" the wildcard permission. A wildcard permission in any of the three fields means the user has all permissions, either for all domains (first part, that's something only the super power root user should get), all actions for the mentioned domain, or all entities for a given list of actions. I've really never before used the entities field to limit access to resources. But it's there if your use case requires it.

The permissions library consists of two parts. The permissions namespace defines the low level API of permission and the implied-by? method used to test if a resource permission (the first parameter) is implied (has access to) by the second permission or list of permissions.

It also holds a factory method make-permission that should make it trivial to create a permission a la:

(make-permission "company") ;; allows all actions on domain 'company'
(make-permission "company" "read") ;; allows read action on domain 'company'
(make-permission "company:edit,update:123,124") ;; allows edit/update action on domain 'company' and entity 123/124

The second part is for conveniently interacting with maps that contain a set of roles and permissions. It expects a key :roles and/or :permissions in the given map. It will construct a set of permissions by pulling all permissions attached to the given roles and the single permissions found into one and then checks if any of those permissions would allow the user to access the resources (as defined by the permission attached to that resource).

(has-permission? user-map permission-or-string)

(lacks-permission? user-map permission-or-string)

In order to know how to resolve permissions from roles it has to be initialized with a map whose keys are the role names and the values are sets of permissions (either Permission records or strings)

A role map might look like this:

(def roles {"user/admin"    "user:*"
            "user/all"      #{"user:read" "user:write"}
            "admin/all"     "*"
            "company/super" #{"company:read" "company:write" "company:edit" "company:delete"}
            "contacts/read" #{"contacts:read"}
            "timeline/edit" #{"timeline:edit" "timeline:read"}
            "project/all"   #{"contacts/read" "timeline/edit" "project:read"}
            }

Please note that the map of roles and associated permissions can hold nested roles. If a role is found on the right side of the map (as value of another role key) it is looked up in the role map and replaced by the found values for this nested role key. This is done recursively for arbitrarily nested roles.

This feature can be used for instance to limit access to different sections (domains) of an application by checking against different permissions which are grouped together as roles by domain. Then you could define a role that would slurp all roles for these domains and assign this role to users that are allowed access to every part of the applications.

Initialize the role mapping with:

(agynamix.roles/init-roles roles)

A user might look like this:

(def user {:roles #{"user/all" "company/super"}
           :permissions #{"library:read" "company:gibberish"}
           ... lots of other keys
           }

Please have a look at roles_test.cljc for examples.

Bitmask Permissions

Instead of attaching literal permission strings to a user record or to a resource you can also attach one or more numbers that represent bitmasks. This works as follows:

In your application you need to define a mapping of role to permissions just as described above. But instead of choosing keywords as names for roles you choose a number that is a multiple of two (that has only 1 bit set):

(def roles {1 "user:*"
            2   #{"user:read" "user:write"}
            4  "*"
            8 #{"company:read" "company:write" "company:edit" "company:delete"}
            }

You can map the number to one or more permissions, whatever suits your application.

Initialize the role mapping like so:

(:require [agynamix.roles :refer :all]
          [agynamix.bitmask-roles :refer :all])
            
(init-roles roles bitmask-permission-resolver bitmask-role-resolver)

It's important that you define the bitmap resolvers when initializing the role mapping!

Then in the user you declare the roles and permissions given to that user like so:

(def user {:roles 10
           :permissions #{"library:read" "company:gibberish"}
           ... lots of other keys
           }

That number 10 sets the bits at positions 2 and 8, thus role permissions given to the roles 2 and 8 are added to that user.

In addition you can still set arbitrary permissions using the :permissions key in the user record if you want. Or you could simple omit the key if it's not needed.

Similarly you give a resource one or more bitmask numbers. These numbers are reduced to the associated permissions as described in the role mapping above. If they reduce to multiple permissions, then all resource permissions must be met by the user (its like they are anded together).

Please have a look at bitmask_roles_test.cljc for examples.

License

Copyright © 2016 FIXME

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.