Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/pragmarb/pragma-policy
Resource authorization as simple as POROs.
https://github.com/pragmarb/pragma-policy
api authorization ecosystem policy pragma ruby ruby-on-rails
Last synced: about 2 months ago
JSON representation
Resource authorization as simple as POROs.
- Host: GitHub
- URL: https://github.com/pragmarb/pragma-policy
- Owner: pragmarb
- License: mit
- Created: 2016-11-15T17:30:14.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2020-01-08T22:46:21.000Z (about 5 years ago)
- Last Synced: 2024-04-24T12:25:26.260Z (9 months ago)
- Topics: api, authorization, ecosystem, policy, pragma, ruby, ruby-on-rails
- Language: Ruby
- Homepage:
- Size: 49.8 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# Pragma::Policy
[![Build Status](https://travis-ci.org/pragmarb/pragma-policy.svg?branch=master)](https://travis-ci.org/pragmarb/pragma-policy)
[![Coverage Status](https://coveralls.io/repos/github/pragmarb/pragma-policy/badge.svg?branch=master)](https://coveralls.io/github/pragmarb/pragma-policy?branch=master)
[![Maintainability](https://api.codeclimate.com/v1/badges/e51e8d7489eb72ab97ba/maintainability)](https://codeclimate.com/github/pragmarb/pragma-policy/maintainability)Policies provide fine-grained access control for your API resources.
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'pragma-policy'
```And then execute:
```console
$ bundle
```Or install it yourself as:
```console
$ gem install pragma-policy
```## Usage
To create a policy, simply inherit from `Pragma::Policy::Base`:
```ruby
module API
module V1
module Article
class Policy < Pragma::Policy::Base
end
end
end
end
```By default, the policy does not return any objects when scoping and forbids all operations.
You can start customizing your policy by defining a scope and operation predicates:
```ruby
module API
module V1
module Article
class Policy < Pragma::Policy::Base
class Scope < Pragma::Policy::Base::Scope
def resolve
scope.where('published = ? OR author_id = ?', true, user.id)
end
enddef show?
record.published? || record.author_id == user.id
enddef update?
record.author_id == user.id
enddef destroy?
record.author_id == user.id
end
end
end
end
end
```You are ready to use your policy!
### Retrieving records
To retrieve all the records accessible by a user, use the `.accessible_by` class method:
```ruby
posts = API::V1::Article::Policy::Scope.new(user, Article.all).resolve
```### Authorizing operations
To authorize an operation, first instantiate the policy, then use the predicate methods:
```ruby
policy = API::V1::Article::Policy.new(user, post)
fail 'You cannot update this post!' unless policy.update?
```Since raising when the operation is forbidden is so common, we provide bang methods a shorthand
syntax. `Pragma::Policy::NotAuthorizedError` is raised if the predicate method returns `false`:```ruby
policy = API::V1::Article::Policy.new(user, post)
policy.update! # raises if the user cannot update the post
```### Reusing Pundit policies
If you already use [Pundit](https://github.com/varvet/pundit), there's no need to copy-paste
policies for your API. You can use `Pragma::Policy::Pundit` to delegate to your existing policies
and scopes:```ruby
module API
module V1
module Article
class Policy < Pragma::Pundit::Policy
# This is optional: the inferred default would be ArticlePolicy.
self.pundit_klass = CustomArticlePolicy
end
end
end
end
```Note that you can still override specific methods if you want, and we'll keep delegating the rest
to Pundit:```ruby
module API
module V1
module Article
class Policy < Pragma::Pundit::Policy
def create?
# Your custom create policy here
end
end
end
end
end
```### Passing additional context
If you want to pass additional context to the policy, just pass it instead of the user object.
Pragma::Policy never uses your context in any way, so you can pass whatever you want:```ruby
policy = API::V1::Article::Policy.new(OpenStruct.new(ip: request.remote_ip, user: user), post)
policy.update!
```In your policy, you can use `#context` as an alias for `#user` for convenience:
```ruby
module API
module V1
module Article
class Policy < Pragma::Pundit::Policy
def update?
record.author_id == context.user.id || context.ip == '127.0.0.1'
end
end
end
end
end
```If you are using [pragma-rails](https://github.com/pragmarb/pragma-rails), you may change the
context passed to the policy by defining a `#policy_context` method on your controller. This way you
are not forced to override `#current_user` or `#pragma_user`:```ruby
module API
module V1
class PostsController < ApplicationController
# ...private
def policy_context
OpenStruct.new(ip: request.remote_ip, user: current_user)
end
end
end
end
```## Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/pragmarb/pragma-policy.
## License
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).