Skip to content

manyfold3d/caber

Repository files navigation

Caber

GitHub Actions Workflow Status Maintainability Test Coverage Libraries.io dependency status for latest release

GitHub Release Gem Downloads (for latest version) Dependent repos (via libraries.io)

A simple ReBAC / Zanzibar backend plugin for Rails apps. Allows you to easily specify permission relationships between pairs of objects, e.g. granting edit permission on a document to a specific user, like in Google Docs.

Installation

Add caber to your Rails application's Gemfile:

bundle add caber

Then, run the installer:

rails g caber:install

This will create an initializer and a migration to add the caber_relations to your database.

Set up the permission types you want in the config/initializers/caber.rb file - a default is provided, but you can change it to whatever combination of permissions you'd like.

Usage

To use Caber, include Caber::Subject in any of your models that can be given permissions (e.g. Users), and include Caber::Object in the things that subjects are given permission TO (e.g. documents):

class User < ApplicationRecord
  include Caber::Subject
end

class Document < ApplicationRecord
  include Caber::Object
end

Now you're ready to grant some permissions! To give someone permission on something:

document.grant_permission_to "viewer", user

You can query permissions in both directions:

document.grants_permission_to? "viewer", user
user.has_permission_on? "viewer", document

You can also check more than one permission at once by passing an array. The check will be positive if either are granted:

document.grants_permission_to? ["viewer", "editor"], user
user.has_permission_on? ["viewer", "editor"], document

Global permissions

To grant or query permissions globally (for instance, for a public view permission), you can use a nil subject:

document.grant_permission_to "viewer", nil

Relationships

In order to query lists of available objects, subjects need to be told what types they can be granted permission on. For each type, after including Caber::Subject, call can_have_permissions_on with the ActiveRecord class you want to be able to get lists of. permitted_* relationships are then automatically added for that type:

class User < ApplicationRecord
  include Caber::Subject
  can_have_permissions_on Document
end

user.permitted_documents
# => all documents with any granted permission

user.permitted_documents.with_permission "viewer"
# => all documents that the user has viewer permission on

user.permitted_documents.with_permission ["viewer", "editor"]
# => all documents that the user has viewer or editor permission on

The inverse relationship is also possible by specifying can_grant_permissions_to on objects:

class Document < ApplicationRecord
  include Caber::Object
  can_grant_permissions_to User
end

document.permitted_users
# => all users with any permission

document.permitted_users.with_permission "viewer"
# => all users with viewer permission

document.permitted_users.with_permission ["viewer", "editor"]
# => all users with viewer or editor permission

Revoking permissions

You can revoke some or all permissions from a user:

# Remove a specific permission
document.revoke_permission("viewer", user)

# Remove all permissions from a user
document.revoke_all_permissions(user)

Finding objects

You can get lists of objects that a user has some permission on:

Document.granted_to "viewer", user
# => All the documents that user has "viewer" permission on

Usage with other gems

Pundit

Caber makes for nice clear Pundit policies:

class DocumentPolicy < ApplicationPolicy
  class Scope < ApplicationPolicy::Scope
    def resolve
      scope.granted_to(["viewer", "editor", "owner"], user)
    end
  end

  def update?
    record.grants_permission_to? ["editor", "owner"], user
  end
end

Rolify

Caber doesn't include groups specifically, but you can integrate it easily with a role management gem like Rolify pretty easily. Make your Role class a subject, and you can grant permissions to roles:

class Document < ApplicationRecord
  include Caber::Object
  can_grant_permissions_to Role
end

class Role < ApplicationRecord
  include Caber::Subject
  can_have_permissions_on Document

  scopify
end

document.grant_permission_to "editor", Role.find_by(name: "editor")

User.with_role(document.permitted_roles.with_permission("editor"))
# => all users with a role that can edit the document

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/manyfold3d/caber. This project is intended to be a safe, welcoming space for collaboration; everyone interacting in the Caber project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

Acknowledgements

This gem was created as part of Manyfold, with funding from NGI0 Entrust, a fund established by NLnet with financial support from the European Commission's Next Generation Internet program.

NLnet foundation logo NGI Zero Logo

Name: "ReBAC".downcase.reverse