Accession
Extremely lightweight permissions for Ruby applications.
Author: Shaun Mangelsdorf
Copyright 2014-2015, Australian Access Federation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Installation
Add this line to your application's Gemfile:
gem 'accession'
Use Bundler to install the dependency:
bundle install
Usage
Accession is intended to be a lightweight and flexible way to add permissions to your model classes. It imposes very few requirements on your application.
The two major pieces of API provided by Accession are:
- The
Accession::Principal
module, which consumes a list of permission strings returned by thepermissions
method in a class and gives apermits?
method for performing a permission check. - The
Accession::Permission.regexp
pattern, which can be used to validate an Accession permission string.
To get started add a permission
method to your class that represents an
authenticated user. This method returns permissions strings associated with that
user. Once you have this method, include the Accession::Principal
module in
your class to add the permits?
method.
An example implementation is:
# app/models/permission.rb
class Permission < ActiveRecord::Base
validates :value, format: Accession::Permission.regexp
end
# app/models/role.rb
class Role < ActiveRecord::Base
has_many :permissions
end
# app/models/subject.rb
class Subject < ActiveRecord::Base
include Accession::Principal
has_and_belongs_to_many :roles
def permissions
roles.flat_map { |role| role.permissions.map(&:value) }
end
end
With this in place, a Subject
can have a permission check performed, for
example:
class ProjectsController < ApplicationController
before_action { @subject = Subject.find(session[:subject_id]) }
def index
fail('Not allowed') unless @subject.permits?('projects:list')
end
end
Permission Strings
A permission string is comprised of one or more colon-separated parts that
describe the action being permitted. Each part of the permission string can be
either a wildcard (*
), or a "word" of characters a-z A-Z 0-9 _ -
A wildcard in any position will match a single word in that position. A wildcard in the last position will match any number of words in the action string.
permission | action | result |
---|---|---|
a |
a |
permit |
a |
b |
deny |
a:b:c |
a:b:c |
permit |
a:b:c |
a:b:d |
deny |
*:b:c |
a:b:c |
permit |
a:b:* |
a:b:c |
permit |
a:* |
a:b:c |
permit |
*:c |
a:b:c |
deny |
* |
a:b:c |
permit |
a:b:* |
a:b |
deny |
a:*:* |
a:b |
deny |
Contributing
Refer to GitHub Flow for help contributing to this project.