{grape} authorization - ruby

I'm attempting to create a restful, json api in ruby - so I'm using grape (https://github.com/intridea/grape) inside of Rack.
I'm not using Rails for this project, so cancan, sorcery, etc... don't seem to be the best options. Plus, I'd hate to mix in a bunch of imperative logic into grape's declarative DSL.
While grape has built in authentication support, I do not see anything about authorization. It seems like this would be a common enough use case that this road would have been traveled before, but after some pretty thorough digging in google and the grape codebase itself I have turned up nothing.
Has anyone implemented something like this for their project in grape? What did you use?

This may be a little too late, but anyway. I'd recommend you use Pundit for authorization, it's deadly simple. To use it in your Grape API endpoints, you would need to include Pundit helpers:
class API < Grape::API
format :json
helpers Pundit
helpers do
def current_user
resource_owner
end
end
mount FoosAPI
end
Now in you API endpoints, you should be able to use authorize foo, action? as you would always do in Rails controllers:
class FoosAPI < Grape::API
get ':id' do
foo = Foo.find(params[:id])
authorize foo, :show?
present foo, with: FooEntity
end
end
Hope it helps!

I thought I can give short comment on this, but the field is to short, sorry if it will not be right answer but:
You mentioned sorcery - I think it is authentication system and got nothing to do with an authorization. (I do not know sorcery gem implementation - just repeating statement from documentation and assuming that description enumerates such systems it replaces and it is valid definition). I guess it is just mistake.
Fundamental question you should ask yourself is...
How much role-based system do you develop? I think if this is only matter of public/private/admin roles probably you should consider just moving it to different APIs.
That can be cumbersome in some circumstances but worth a try for not complicated none additive roles. Simple mount in grape will solve the problem OOTB.
Real problem is if you think about some expandable/dynamic role system or you want to be just DRY. That can be painful ;-). I think Rayan's Bytes cancan gem implementation should help you understand how such problem can be solved on higher abstract level. For particular (without higher abstraction - such as dynamic roles) implementation it should be fine to just use currently given helpers from grape and delegate their responsibilities to model (basic usage).
helpers do
def current_user
#current_user ||= User.authorize!(env)
end
def authenticate!
error!('401 Unauthorized', 401) unless current_user
end
end
so all the story is about how to implement User.authorize!(env) and I believe that should be done in your model and depends strictly on your needs.

I don't know whether my answer is in time for you. I recently have the same problem with the Grape and authorization in a Rails4 project. And after trying, I found out a way for this.
In my project, I'm using the pundit for authorization, it asks me to create a policy folder, and create the authorize rules for each Model, each rule is a Ruby class, something like this(from pundit Github page)
class PostPolicy < ApplicationPolicy
def update?
user.admin? or not record.published?
end
end
then in the Grape API, I just use this class for the authorization, code like this:
desc "hide a post"
post :hide do
authenticate!
error!( "user unauthorized for this" ) unless PostPolicy.new(current_user, #post).hide_post?
#post.update hidden: true
{ hidden: #post.hidden }
end
the authenticate! and current_user helpers are customized helpers. By this way, I can reuse the authorize rules created when developing website parts.
This works for me. Hope the Pundit way can solve your problems for Grape authorization

Related

Consuming REST APIs in Ruby - When to authenticate?

I'll try to keep this as brief and to the point as possible.
I'm writing a Ruby gem, modeled after the Diplomat gem, that's a wrapper around a product's REST API. The API I'm consuming makes use of token based authentication; an API token is sent via a POST, and a session is returned as a cookie. I'm making use of the Faraday cookiejar middleware for handling the cookie that's returned by the API. The problem I'm struggling with, conceptually, is when to authenticate.
I have two classes, one called RestClient and one called Volume; the latter inherits from the former. As it stands now RestClient's init method builds a connection object and authenticates, while Volume's init method calls super and passes a path. My thinking here is that when any class that inherits from RestClient is initialized it'll authenticate the user.
class RestClient
def initialize(api_path)
<build connection>
auth
end
def auth
<post token, get session cookie>
end
end
class Volume < RestClient
def initialize
super('/volume')
end
def volumes
<send GET, receive volumes>
end
end
obj = Volume.new #Creates object, authenticates user
obj.volumes #Returns list of volumes
I guess my question is..am I headed down the right track? Should I hold off authenticating until a method is first called on the object, rather than authenticating when it's initialized? Am I going about this entirely incorrectly?
what you are asking here is more of a code-style question. there is no right or wrong here. i was about to vote to close because i think it is primarily opinion-based.
since i have an opinion, i'm writing an answer instead.
a) do not over-think
just implement the stuff, if it works, it is good enough
b) rule of 3
if you have implemented 3 things of the same kind and a pattern emerges, refactor!
c) refuse to use inheritance
when in doubt, do not use inheritance. a module will be good enough most of the time.
to your question specifically:
i would not use an initializer to make http calls. they are error-prone and error-handling from within initializers or around those is really ugly. it makes testing a pain in the ass.
what i would do is to just implement whatever you need in simple methods.
what is wrong with calling authenticate before making another api call? putting it into a block may make it really nice and readable:
client.authenticate do |session|
session.volumes
end
if this is too ugly for your use-case, you could do it lazily before any other method call that might require authentication.
Is cookie the only auth your API supports? Very often server-oriented (server-to-server) REST APIs also implement better auth strategies that allow you to pass in auth with every request.
All that being said, what you also can do is something like this:
client = MyApi::Client.for_user(username: ..., password: ....)
#...or
client = MyApi::Client.for_token(token)
volumes = MyApi::Volumes.get(client: client)
This way for where auth is required you would be doing a good thing by "encouraging your class to be used right" - that you simply won't be instantiating the client without authentication data, and won't be initializing your remote objects/calls without a client.
Then, within the client, what you can do is a memoized auth on first request
def perform(http_method, url, ...)
#auth_cookie ||= #client.get_cookie_by_authentication
...
end

Recommended use of couchrest model in a multi-tenant app

I'm looking for recommendations on how to implement multi-tenancy with couchrest model in a rails app. For my multi-tenant app, I'm thinking of two options:
{ edit - removed my ugly options because they'll only confuse future readers }
I would like this to work well with 10K users.
SOLUTION:
Based on Sam's advice, here's what I did and it's working well -
In my case, I needed to override the proxy_database method because the standard naming for proxy databases didn't match my naming.
created the master
class Site < CouchRest::Model::Base
property :name
property :slug
proxy_for :users
proxy_for ...(all the other multi-tenant models)
# Databases are on same server in this example
def proxy_database
#db ||= self.server.database!(slug)
end
end
Then in each multi-tenant model
class User < CouchRest::Model::Base
...
proxied_by :site
In ApplicationHelper create a 'site' method that you can reuse in all your controllers.
module ApplicationHelper
def site
db_name = current_user.db_name
#site ||= Site.create(slug: "#{db_name}_#{Rails.env}" )
end
Then controller might do something like:
def show
user = site.users.find(params[:id])
render :json => user
end
You might want to checkout the Proxying feature of CouchRest Model for this. More details can be found here:
http://www.couchrest.info/model/proxying.html
Although I have no personal experience, I understand that CouchDB handles >10k databases. Here is a good thread of ways of scaling the number of users:
http://comments.gmane.org/gmane.comp.db.couchdb.user/13862
A few considerations to take into account when dealing with lots of databases:
File system sub-directory count, not a problem with Ext4.
Namespace databases to split between sub-directories and/or servers.
System open file limit. Usually around 10k. Probably fine if not all databases are accessed at the same time.
Hope that helps.

Best Practice for sharing global data over several Thor tasks

I am currently building a Thor executable that supports several different tasks. Some tasks inoke other tasks. For example
Auth
authenticates the local user
Create
Invoke Auth
Does something
Invoke Configure
Configure:
Invoke Auth
Does something
The nice thing about thor is that I can now call all of the three tasks separately, but be sure that authenticate for example is only called once through invoke.
But what is now the best way to share Data between those tasks. For example when Authenticating I want to set the User-ID of the current user. Thus when I want to request Data from our webservice I can take the user id from anywhere in my code the same way.
Right now I am implementing this through Modules, but I am not really sure if this is the best way to do it.
Using Singleton would be another way, but somehow this seems like a little bit too much for this purpose.
Maybe you guys have experience with a better way to do this, or maybe using modules is the best way to store the information anyway.
I would have done something like this:
module PRJ
class << self
attr_accessor :api_key, :account_name, :api_version, :api_url, ......
def configure
yield self
end
end
end
require "#{directory_of_all_other_classes}"
require 'thor'
class CLI < Thor
include Thor::Actions
def login
...
PRJ.api_key = response[:api_key]
end
As you want to invoke Auth in every cases, so I think it should be in main CLI file.
Regarding storing and using data it would be better to use attributes instead of constant. I may not be right about this but I prefer using class attributes.
Now you can access and change PRJ.api_key from anywhere (require PRJ module in every file)
P.S. The structure of code snippet might not be accurate, I just wanted to share some basic skeleton. Do something like above for remaining classes.
If you just need to store simple data structures I would go for common class variables
class Test < Thor
##my_shared_var = nil
desc 'my_first_task','sdfasdf'
def my_first_task
##my_shared_var = 'foo'
end
desc 'my_second_task','sdfasdf'
def my_second_task
invoke :my_first_task
puts ##my_shared_var
end
end

How to skip before filters in Rails Forem Gem

I would like to allow anonymous access to my forums. I am using the Forem Gem and the Devise Gem. I have a before_filter in my ApplicationController that ensures users are logged in.
before_filter :authenticate_user!
In my own controllers I use skip_filter to allow anonymous access to actions but I do not know how to do this for the controllers in the Forem Gem.
I could move the before_filter statement from my ApplicationController into each of my own Controllers but I would rather not.
Thanks for the answer Ryan, Just like to point out that the file should be:
forem/application_controller_decorator.rb otherwise it won't load with that initialiser code (note: underscore - not dash).
And to re-iterate, the initialiser code should be :
Rails.application.config.to_prepare do
Dir.glob(Rails.root.join("app/**/*_decorator*.rb")) do |c|
Rails.configuration.cache_classes ? require(c) : load(c)
end
end
So that it will reload on every request in development mode.
Hopefully that will save someone a few hours!
The best place for this would be a file inside your app/controllers directory at forem/application_controller-decorator.rb that contains this content:
Forem::ApplicationController.class_eval do
skip_before_filter :authenticate_member!
end
You would then need to include this file using lines like this in a file called config/initiailizers/load_decorators.rb:
Dir.glob(Rails.root.join("app/**/*_decorator*.rb")) do |c|
Rails.configuration.cache_classes ? require(c) : load(c)
end
This would allow you to specify other decorators as well, for any other class of Forem, if you so desired.
I stole this idea from Spree (which I work on full-time now), and I think it's pretty solid. You can see the original implementation of it here.

How to access Warden current user in business logic in Rails3

I am using Rails Warden plugin. It defines a helper method 'user' that returns current user. See the link for the source code.
Now I have an business logic object that does not have any reference to the controller. But I would like to get the current user. Is there any way of accessing this?
I have tried
ActionController::Base.helpers.user
or even
RailsWarden::Mixins::HelperMethods.user
with no luck. Thanks.
Now I have an business logic object
that does not have any reference to
the controller. But I would like to
get the current user. Is there any way
of accessing this?
So why can't you just pass the current user to those methods?
Additionally you can mix them in.
I strongly discourage you to write the static helpers (it is not Java, it is Ruby!).
Instead, where you need those helpers include them as a module:
module SuperLogic
def calculate_stuff(current_user=nil)
(current_user || user || self).bills.sum
end
edn
Then include this where you need it:
# user model
class User
include SuperLogic
#it will get the `calculate_stuff` method
end
# controller
include SuperLogic
# so you can use it as one of
calculate_stuff user
calculate_stuff
and so on...
additionally where you access your business logic, you can just create an instance of the class instead of "static" methods (in ruby they are "class" methods):
# controller
def calculate
#result = BusinessLogic.new(user).calculate_stuff
end
This is probably the easiest thing you can do.
Really, you don't need to access whole HTTP context in your business objects (I'm not even talking about testing it).
The way I think of business logic, it's something that sits between the controller and the model. I think it would be ok to pass an instance of the request to the logic methods, and since you're using warden, you can get the user from 'request.env['warden'].user'.
I haven't encountered a good reason not to have logic methods be static (self.) methods of a module. Maybe Dmytrii's suggestion works for you, but I prefer to 'require' than to dynamically include one-off logic bits.

Resources