I am building an api for others to use. This is a simple enough Json request the user passes as some data and we pass some back.
What I would love is to secure our api and have some sort of user system where we can turn users on and off and we can log how many requests each user makes.
What would be the best way to do this in Rails? I don't want it to slow down the request. I can see ways of doing it using devise maybe but would be great to hear other people's opinions.
Thanks
Another way is to use 3scale (http://www.3scale.net) - it's free up to a traffic cap but handles all the key management, users, documentation etc. and there's a ruby library which you can drop into your code if you're using rails. (other libs are here: https://support.3scale.net/libraries).
I've done this before using the Token Authentication capabilities of devise (see https://github.com/plataformatec/devise ).
I found the following setup works:
Create a user account for each api user.
Configure devise for token authentication
Set the Token Authentication configuration to require the token to be submitted with each request.
This will allow you to enable and disable individual users as well as to track every request back to the api user that made the call.
If you're really interested in tracking usage you may want to consider also creating a database table where you track all api requests. This can be setup to belong_to the users table so that you easily find all requests from different users (e.g., #user.api_requests).
The count of all requests made by a user would be:
#user.api_requests.count
# or use a where clause to find how many of each type
#user.api_requests.where("api_request_type = ?", 'SomeAPICallType').count
One final note -- I recently used the Grape library for building out an API. I thought it was pretty well done and it worked great for our needs. I especially like the ability it provided to version APIs. Details are here: https://github.com/intridea/grape/wiki
Related
I am building an API-only (for now) Rails app to serve as the back end for an Android app I'm building. I was previously using Firebase but wanted to do more processing on application data and I didn't want to bloat the mobile client with all the logic, so I am moving away from Firebase's real-time database and backing the application data using Rails. I was also using Firebase's authentication which is very straightforward. But it seems less complex for the overall system to keep all of this functionality in one place, so I'd like to perform auth and user management in the Rails app as well.
I have installed devise_token_auth (seen here) and finished the basic configuration. The /auth route works correctly if params are provided and creates a user. sign_in and sign_out both successfully create sessions and return some header information. The important parts returned are client, access-token, and uid, which I need to use in future calls to the API. I believe these are invalidated and replaced with each subsequent call. At this part of the flow is where I'm not sure how to proceed. I don't understand how the data in these headers is associated with the user who signed in and how I can validate that they own a resource they request. To summarize the question another way:
How can I sign a user into the API and then validate which user is making subsequent API calls?
My Android app is a task manager, so I need to be able to validate for example that if user 1 requests task 3, that they own that resource. I'm also unsure how to direct index calls using the API. That is, when the index endpoint is hit (/tasks), how can I identify from the data in the API headers which user's tasks I should retrieve.
I haven't been able to find any solid tutorials or samples using devise_token_auth so I'm having trouble stitching together the interaction between the pieces I have now. I know this is a meaty question - thanks in advance for any guidance.
How can I [...] validate which user is making subsequent API calls?
With the current_user method. This is a built-in feature to the devise_token_auth gem.
I need to be able to validate for example that if user 1 requests task 3, that they own that resource
There are many different approaches you could take. You could just write some custom logic in each controller action, using the current_user method (and return 403 forbidden if necessary).
Or, you could use a popular "framework" solution for this such as CanCanCan or Pundit. I, and probably most of the modern community, would recommend Pundit.
I highly advise you to read that library's README, as it's extremely helpful. But for the example above, you could write something like this:
class TasksController
def show
task = Task.find(params[:id])
authorize(task) # !!!
render task
end
end
# app/policies/task_policy.rb
class TaskPolicy
def show?
record.user == user
end
end
(Note that by default, the "user" in Pundit policies calls the method: current_user. This is all explained in the project's README.)
when the index endpoint is hit (/tasks), how can I identify from the data in the API headers which user's tasks I should retrieve
Again, this is all handled as part of Pundit's standard features. You just need to define a TaskPolicy::Scope and call policy_scope(Task) in the controller - as explained here.
If I have a single server with multiple domains, what is the preferred method for implementing a single-sign-on solution on the same domain. I am currently using devise, have a few million cookies in place on separate domains, and am stuck. On top of just implementing SSO, I also need to migrate the various cookies to a central domain. Regarding the various servers, they only have one single page that requires me to show different states depending on whether or not the user is logged in.
I have tried the following:
CORS: pick one domain as the central auth hub. From all other domains make cross domain checks to see if the user is logged in. For migrating cookies, detect if there's a "current_user" object, send it to the client, make a CORS request, sign the user in and kill the token. Works Great! BUT... After building it for 2-3 weeks, it TOTALLY FAILS in IE. Even IE11, I'm noticing the default setting is disabling this behavior.
tried tinkering with the session store at
Rails.application.config.session_store
with no luck.
I am currently experimenting with the following:
JSONP: I have someone right now trying to convert the above to JSONP instead while I try some other options:
Set up a custom OAUTH provider. Like before, it will be the "central domain" if the person is signed in, return to the requested domain with a token from which the users can make requests. https://github.com/songkick/oauth2-provider
Looking at this but it looks outdated? https://github.com/rubycas/rubycas-client. I also get the feeling this could have been a solution if I rolled this out from the get-go, but given how far we are into the project, it's unclear to me how I'd transfer the existing cookies. Also it's unclear if this requires two applications for me to get up and running ( one for client(s), one for auth server)
As I go through each of these possibilities, if anyone has had any experience doing what I'm doing, please do inform me and save me a whole lot of work :)
The best way unless this is a toy app is probably to set up an oauth provider.
We use Doorkeeper with Devise for this and it works great. It will be worth your time to set a little time aside to read through the documentation and watch a talk or two on youtube if you're not already familiar with the strategy but once you understand the core concepts its actually pretty simple to set up with the help of this gem.
There is a quick video run down on http://railscasts.com/episodes/353-oauth-with-doorkeeper
I have a Rails 4 application. I use devise for authentication and opro for providing oauth2 with my API. All requests are authorized with pundit policies and until now, this setup was totally fine.
Currently, my authorization is always done on a per-user basis. This makes sense, as usually every request is done on behalf of a particular user who is either authenticated in a session or by providing the oauth-token.
The new challenge is: I have certain API-consumers (let me call them devices from now on), whose requests cannot be seen as requests from a particular user. One is an Asterisk Server that can exchange information with the API, another is a GPS Tracking Box that continuously pushes trackpoints to the API.
Thus, I need to authorize certain API-operations on a per-device basis, meaning there is not necessarily a current_user available. Having no current_user however screws up my authorization concept.
I have already considered several approaches to the problem:
creating dedicated users for each device and authorizing them to do the specific action
pro: does not screw up my authorization scheme
contra: would mean to rethink the User-Model, as currently I only have "natural users" that require name, birthday, email, etc
creating dedicated controllers with adapted authorization scheme
pro: high flexibility
contra:
authentication for devices required
extra API endpoints required, does not feel very DRY
I am searching for a best-practice approach for such a situation. I believe this is not an extra-ordinary problem and there must be good solutions for this out there.
You need a separate layer that does the authorization check as well as global attributes called caller_id and caller_type (these are just examples).
You then want to implement a logic e.g.:
if caller_type == device and caller_id == ... then
if caller_type == user and caller_id == ... then
To do that you can just custom-code your own little class. Alternatively you could use XACML to define your authorization logic. See this blog post which applies XACML to servlets. The same principle could be done for your Rails application.
HTH,
David.
I'm finding a solution to detect cheaters creating many accounts at my website.
I have found permanent cross-browser cookies: http://samy.pl/evercookie/
But it written on JS, and I need something to use in rails controller. Is there any gem or plugin like evercookie?
Once I was searching for Evercookie solution for Rails, didn't find and wrote a gem 'evercookie'. You can try it.
Documentation is available on github
Email token (Devise, Sorcery)
Can you send an email to a new user?
A simple solution that many websites use is sending the user an email with a security token. A good Rails gem for this is Devise, and another is Sorcery which makes it simple to build your own custom authentication.
Third-party sign in (OmniAuth, OpenId, Facebook Connect, Twitter, etc.)
Can you authenticate the user with a third-party service?
The OmniAuth gem can connect to many third-party services and let the user authenticate using an existing account on Google, Yahoo, Facebook, Twitter, LinkedIn, and open services including LDAP and Shibboleth.
The OpenId gem works well with Google, Yahoo, and many other large providers; you can also use OpenId within OmniAuth.
In all these cases you would track the sending, so that a user can't apply again too quickly by using the same phone number, postal address, credit card, etc.
Phone Message (Twilio)
Can you send your user a text message?
The Twilio gem enables sending text messages to phone numbers. The concept is that your
app sends them a text message with a verification code.
Snail mail (postalmethods)
The postalmethods gem lets you send real, physical postcards in the postal mail. You can send a postcard with a verification code. This may take a few days, so some sites use this in conjunction with a "probationary period" for new users where they are somewhat sandboxed from causing any trouble. (for example, they can read info, but not post info).
Credit card (BrainTree)
Related ideas are to have the user send you something that requires a credit card, such as using a payment gateway like BrainTree or ActiveMerchant.
You can verify the card is open and valid without charging any money to it. Or you could require a tiny minimum payment, such as requiring the user to send you one dollar via PayPal, Google Payments, Amazon Dev Pay, etc.
Credit card numbers have internal structure (like a checksum) so you could verify that the number is the right format and checksum. A simple script is flame.org
Image Captchas (recaptcha)
To block bots, captchas such as Ruby recaptcha work very well.
Ruby has other captcha solutions and any of these are likely fine.
Karma (hypothes.is)
This isn't a gem, but it's a concept. Give new users limited privileges, such as read-only access. Let users earn new privileges by being a member for a certain amount of time, or by contributing content, or by connecting with friends and peers within your site, etc.
This is how sites like StackOverflow work, and there's a lot of good information about these approaches at http://hypothes.is
Combos
The most powerful approach is combinations of these techniques.
Perhaps give a new user some basic capabilities, such as reading information, and then let him earn new capabilities by doing one or more of the authentications above. This is how Google and Facebook add some features: you can sign up easily, then authenticate other emails, then authenticate your phone number, then authenticate your postal address.
No, there is no Rail drop-in solution and it wouldn't make much sense.
evercookie is written in JavaScript and additionally uses a SWF (Flash) object for the Local Shared Objects and PHPs for the server-side generation of cached PNGs and ETags.
Almost all of the Evercookie techniques rely on special Javascript APIs to the browser, so there's no way of porting them to a server-side technology (except for the small PHP part).
A gem might make integration and updates easier, but it would still be Javascript for the client side.
Please consider the ethical implications of Evercookie. It is a proof of concept, not a tool to be widely used, in my opinion.
If you want to roll out your own solution, a good starting point (with cookies) would be:
def create
if cookies[:xyz]
render :text => 'cheater!'
else
# save the user first (you may need to display the form again), and then set the cookie
cookies[:xyz] = { :value => "1", :expires => 1.day.from_now }
end
end
EDIT: this is not comparable to evercookie, just a simple alternative.
EDIT 2: I already said that captchas are what the author should probably use, so am I being downvoted for showing what a starting point would be if he still wants to use cookies?
I've been working on the development of an Android app in my spare time for several months now. I've done all of my planning for the on-device side (except for server-side interaction), but I've been met with a very steep learning curve for the on-server side implementation. I've researched for about a month with no real leads. Consequently, I'm really at a dead end. The app that I'm working on included these minimal requirements:
Must offer account creation/authentication to the server from the
device
Must maintain some sort of session that allows the user authorization
to make changes that will impact only the on-server user data within the context of the account that they are logged in to.
The ability to log out/be logged out by the server under certain conditions.
A web interface will not be necessary, as this service is only to be consumed by Android devices.
I've decided that a Rails implementation is the most desirable option for me. My experience with Rails and servers in general is very limited. A friend recommended that I read though "Agile Web Development with Rails" in order to get up to speed. I made it through enough of the Depot Application demo in order to understand ORM libraries, the MVC pattern, and scaffolding, but then I got fed up with the way that the book presents the information. Everything is very sequential, and the authors seem to omit a lot of the "how", saying that they'll explain later, and to just not worry about it until that point. That's not the way I learn. I digress.
So far I've used scaffolding in Rails to generate a model, view, and a controller for an Accounts table. I've set up attributes for a username, password, session_key (a randomly generated key that the user should receive and use to connect from their device after login), etc using scaffolding. I am validating the username and session_key to ensure that they're unique, and my alphanumeric key generation is working properly (all of which is done in the model).
Now I'd like to focus on managing sessions in a restful manner. I know that I'll need to implement this by having Android devices pass their user's session key to the server when making HTTP requests and accessing resources etc., but other than that I'm at a loss.
I'm looking for someone to provide me with a good resource (or explanation) outlining how HTTP requests and responses work in general, how JSON information can be received and parsed using a request, and how to otherwise manage restful authorization (assuming that the user has already been assigned their session key). If my approach isn't quite right, please let me know what you would suggest.
Thanks!
For authentication, you might want to check out: http://railscasts.com/episodes/250-authentication-from-scratch You'll basically just be performing the authentication using the session_key. There are other more complicated things you might do, and you could check out authlogic, devise, sorcery, etc. to see how they implement keeping sessions alive. Since you need log outs, and presumably the need to log back in, I would suggest looking into using the session key you describe as the master authentication and then have a perishable key of some sort that gets reset after every request and sent back to the client as a keepalive. Depending on your ultimate needs, that might be enough security and functionality.
For JSON receiving, rails has built-in parsing. Look into respond_to. For sending back JSON, you can use any number of methods. The most basic is to just allow rails to automatically convert the JSON (which happens when respond_with is used, as in the link). You could also build out presenter classes or use something a little more formal like rabl.