# ![Lamassu](http://res.cloudinary.com/huyderman/image/upload/c_lpad,dpr_2.0,f_auto,g_center,h_150,w_888/v1523625102/lamassu) [![Gem Version](https://badge.fury.io/rb/lamassu.svg)](https://badge.fury.io/rb/querylicious) [![Build Status](https://gitlab.com/huyderman/lamassu/badges/master/build.svg)](https://gitlab.com/huyderman/lamassu/pipelines) [![Coverage](https://gitlab.com/huyderman/lamassu/badges/master/coverage.svg?job=rspec)](http://huyderman.gitlab.io/lamassu/coverage) [![Join the chat at https://gitter.im/lamassu-rb/Lobby](https://badges.gitter.im/lamassu-rb/Lobby.svg)](https://gitter.im/lamassu-rb/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) > Lamassu is an functional authorization framework for Ruby, based on > callable policy objects and policy containers ## Installation Add this line to your application's Gemfile: ```ruby gem 'lamassu' ``` And then execute: $ bundle Or install it yourself as: $ gem install lamassu ## Usage To use Lamassu, you need an Guardian for your project: ```rb MyGuardian = Lamassu::Guardian.new ``` You can then register policies for various Modules with the guardian, and if authorized: ```rb include Dry::Monads::Result::Mixin Article = Struct.new(:title, :owner, :published) MyGuardian.policies.for Article do policy :read, proc do |user, article| if article.published || user == article.owner Success(:allowed) else Failure(:no_access) end end end article = Article.new('My Article', :bob, true) MyGuardian.authorize(:bob, article, :read) # => Success(:allowed) ``` A policy can be any callable object returning a `dry-monads` `Result` object, or an object responding to `to_result`. When building an application with many policies, it's recommended to create proper policy objects by including `Lamassu::Policy`: ```rb # app/policies/article/read_policy.rb class ReadPolicy include Lamassu::Policy def call(user, article) if article.published || user == article.owner Success(:allowed) else Failure(:disallowed) end end end MyGuardian.policies.for Article do policy :read, ReadPolicy.new end ``` ### Subsets Since the result is wrapped in a `Result`, the policy object can also be used to return a subset or selection of data: ```rb class ReadPolicy include Lamassu::Policy def call(user, _) articles = ArticleRepository.select do |article| article.owner == user || article.published end if articles.empty? Failure(nil) else Success(articles) end end end result = guardian.authorize(:bob, article, :read) # => Success([#
, ...]) result.value! if result.success? # => [#
, ...] ``` Example usages for this include to return only the articles a user have authorization to view, or transform an object to remove any fields the user is authorized to read. ### Policy adapters Lamassu comes with several "policy adapters" for convenience when creating policies: ```rb MyGuardian.policies.for Article do check :write, (proc { true }) map :published, (proc { ArticleRepository.select(&:published) }) end ``` Both adapters wraps a callable object, and returns a valid policy object. The `check` adapter is used with an callable object that returns a truish or falsish value, and wraps the result in `Success` or `Failure` respectively. The `map` adapter wraps a callable object, and wraps any output in a `Success`. These adapters are meant for simple applications or to ease porting existing ones. It's recommended to create proper policy objects when possible, as you have better control over the return value. ### Web frameworks Lamassu don't currently include any integrations with any web frameworks. It's meant to be flexible and usable with any framework, but the details will depend on the chosen framework. To simplify calling lamassu, it could be useful to create a helper to include in your controllers: ```rb module AuthorizationHelper # Convenience method for checking authorization where the user object is # available through `current_user`, and the scope is the current controller. def authorize(policy) MyGuardian.authorize(current_user, self, policy) end end ``` ## Development After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. To install this gem onto your local machine, run `bundle exec rake install`. ## Contributing Bug reports and pull requests are welcome on GitHub at https://gitlab.com/huyderman/lamassu/issues. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](CODE_OF_CONDUCT.md). ## License The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). ## Code of Conduct Everyone interacting in the Lamassu project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](CODE_OF_CONDUCT.md). ## Acknowledgments * [dry-rb](https://dry-rb.org/) collection of gems which have both a great inspiration, and without this library would not be possible * [Pundit](https://github.com/varvet/pundit) which is an great authorization library and have been an influence of some of the design of Lamassu * Alex Daily ([@Alexis@beepboop.one](https://beepboop.one/@Alexis) or [@heyalexdaily@twitter.com](https://twitter.com/heyalexdaily)) who created the awesome logo for Lamassu.