Consuming REST APIs in Ruby - When to authenticate? - ruby

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

Related

How to stub method with specific parameter (and leave calls with other parameters unstubbed) in Mocha?

This question may seem like a duplicate of this one but the accepted answer does not help with my problem.
Context
Since Rails 5 no longer supports directly manipulating sessions in controller tests (which now inherit from ActionDispatch::IntegrationTest), I am going down the dark path of mocking and stubbing.
I know that this is bad practice and there are better ways to test a controller (and I do understand their move to integration tests) but I don't want to run a full integration test and call multiple actions in a single test just to set a specific session variable.
Scenario
Mocking/stubbing a session variable is actually quite easy with Mocha:
ActionDispatch::Request::Session.any_instance.stubs(:[]).with(:some_variable).returns("some value")
Problem is, Rails stores a lot of things inside the session (just do a session.inspect anywhere in one of your views) and stubbing the :[] method obviously prevents access to any of them (so session[:some_other_variable] in a test will no longer work).
The question
Is there a way to stub/mock the :[] method only when called with a specific parameter and leave all other calls unstubbed?
I would have hoped for something like
ActionDispatch::Request::Session.any_instance.stubs(:[]).with(:some_variable).returns("some value")
ActionDispatch::Request::Session.any_instance.stubs(:[]).with(anything).returns(original_value)
but I could not find a way to get it done.
By what I see, this is a feature not available in mocha
https://github.com/freerange/mocha/issues/334
I know this does exist in rspec-mock
https://github.com/rspec/rspec-mocks/blob/97c972be57f2c060a4a7fb8a3c5700a5ede693f0/spec/rspec/mocks/stub_implementation_spec.rb#L29
One hacky way that you an do it though, is to store the original session in an object, then mock that whenever a controller receives session, it returns another mock object, and in this you may either return a mocked velue, or delegate the call to the original session
class MySession
def initialize(original)
#original = original
end
def [](key)
if key == :mocked_key
2
else
original[key]
end
end
end
let!(original_session) { controller.send(:session) }
let(:my_session) { MySession.new(original_session) }
before do
controller.stubs(:session) { my_session }
end
Guess that mocha also allows you to do block mocking, so you don't need the class, but you need that original_session to be called
But I don't see a clean way

Two step construction. Useful or just a code smell?

Normally I expect that once an object is constructed, it should be ready for use, period. No two step construction. If you need calling two constructors for using an object something is very wrong... right?
class Contact
attr_accessor :auth_token
def initialize(contact_hash)
...
end
def edit(...)
auth_token.can! :read, self
end
end
token = AuthorizationToken.new(session)
contact = SomeService.get_contact(...)
contact.edit(...)
# raise error because auth_token is not set
contact.auth_token = token
contact.edit(...)
The code above represents my current dilemma: I want SomeService to give me Contact objects, but I do not want that service to be concerned about an existing session, or authorization at all.
My current approach is adding this extra class:
class QueryService
def initialize(session)
token = AuthorizationToken(session)
end
def get_contact
contact = SomeService.get_contact(...)
contact.token = token
end
end
contact = QueryService.new(session).get_contact(...)
contact.edit(...)
This solution gives me the most freedom to use authorization concerns inside the core domain object Contact, implement them in an external class AuthorizationToken and implement services that are not concerned about the current user session SomeService.
However the two step construction is killing me. It feels strange: An object that is not fully initialized for some operations???
This is not a plain case of dependency injection, but more exactly a context injection. So most of the articles about avoiding DI in Ruby do not really solve my problem. I am wondering if there is a more Ruby way to solve this, or this is just as clean as it can get.
Looks like your Contact class serves two purposes - storing contact data and doing some authorized requests - so yes it does violate the Single Responsibility Principle.
This could be fixed by splitting the Contact class into two - one maybe a Struct or even a plain hash to store the data, and the second that has does the requests.
And I think the most Ruby way to do it would be to return hashes from SomeService and instantiate with Contact.new(data, auth_token) later on.

{grape} authorization

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

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 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