Rails RESTful API + Devise - How to check for user's credentials - ruby-on-rails-3

I've built a RESTful API with Ruby On Rails, and now I good like to know whether the user's credentials received by POST are valid or not, using Devise.
Any ideas?

Devise - getting started should set you up.
EDIT:
Devise, by default, validates users by their email and password. If you want to add validation by username, refer this wiki
Basically, you need to add username to the model and make it 'attr-accessible'
Devise sets up paths for user sign-up, sign-in and sign-out, etc.
Refer devise asciicast for these path helpers.
To write controller tests, refer to this wiki for details.
EDIT:
Sorry for not understanding your requirements. Here is how to find user from credentials. This you can use from your service to validate user.

Related

Using Omniauth both for login with Devise as well as for accessing API's

In our application, we allow the user to access their data at different providers (Google Calendar, Microsoft Outlook, Facebook timeline, etc.) through the available API's, using Omniauth. For this we have an omniauth.rb with all the necessary configs, like:
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET'], scope: 'email,user_posts,user_status,public_profile,manage_pages,instagram_basic'
provider :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET'],
name: 'google',
scope: 'email, profile, calendar.readonly',
access_type: 'offline',
prompt: 'select_account consent'
# etc...
end
Now we like to add login with Google as an alternative way to log in. Since we use Devise for our user session management, we'd like to use Devise's Omniauth features to implement login with an OAuth provider like Google. However, as soon as we make our model "omniauthable", the existing Omniauth functionality stops working throwing an No route matches [GET] "/auth/facebook" when trying to add an oauth account to access an API.
What is the correct way of combining the use of Omniauth in both Devise and in our own plain vanilla OAuth flow?
I found the answer myself: it's a matter of not using the thin wrapper of functionality that Devise adds to OmniAuth, but instead taking care of the OmniAuth routing yourself. I have described this approach here in the Devise Wiki.

How to integrate Devise and SAML?

What is the best way to get SAML working with the widely used https://github.com/plataformatec/devise?
https://github.com/apokalipto/devise_saml_authenticatable doesn't do signed/encrypted auth requests and that's a deal breaker for us, and the usual sources haven't helped.
Devise's Omniauth integration, for example, requires an app ID and secret that Onelogin's SAML connector doesn't provide.
So, the answer that worked for me is to use the gemlfile and omniauth.rb settings as outlined in https://github.com/PracticallyGreen/omniauth-saml#usage and then to follow devise's omniauth tutorial at https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview, replacing facebook with SAML. Note that you mightn't need the UID field mentioned in the tutorial, depending on how your IdP stores their users (and you wouldn't get a permanent UID if you use the transient nameid format). Use whatever uniquely identifies your user at the IdP, which is quite possibly an email address.
The devise.rb stuff added by ioblomov doesn't seem to add anything and in fact causes an issue if you do it as well as doing an omniauth.rb file. This creates a situation where the IdP does two callbacks, one using the omniauth.rb settings and another using the devise.rb settings. Given that the devise.rb settings are not complete (they don't have a consumer url for example), I can't see how even having it on its own could ever work. It is not clear to me what "devise integration" even means in the context of omniauth-saml. Once you get an auth response back (which you will just from using the omniauth.rb settings), then all you have to do is use the devise method sign_in_and_redirect in your callback controller and then you have all the usual devise stuff available to you for that user. I will submit a PR to omniauth-saml but I wouldn't be holding my breath as the project appears to be sporadically maintained at the moment.
I had to deal with recently to hook a rails app up to a university network using Shibboleth for SSO. I ended up using devise, omniauth and running on Apache with mod-shib2. I am not sure if you are using Shibboleth specifically but it is built on top of SAML. The lightweight rack-saml implementation did not work for me.
Turns out the Devise config's parameters were wrong. I documented the correct settings in a fork/PR:
https://github.com/omniauth/omniauth-saml#devise-integration

Create FTP User Accounts with Rails

Ok I'm not sure how to approach or explain this but I'll give it a try.
I'm developing a rails app on my mac using Devise for auth.
I would like to do the following:
When a user joins the site, the app creates an ftp user account with the same login credentials (email/password) they used to sign up. That way they can upload files via ftp using the root url of the site and their login credentials.
When the user updates their login credentials, their ftp user account needs to be updated with the same credentials.
Does paperclipftp or carrierwaveftp handle this? What would be the best way to accomplish this.
Thanks
Rather than setting up individual FTP accounts for each one of your site's users, this post walks through writing a controller action that handles the FTP authentication response instead, using your Rails users' credentials. It uses pure-ftpd and a custom authentication module to send an HTTP request with the credentials to your Rails app, which will then verify them by whatever means you'd like, and return the appropriate FTP response to the client.
I haven't tried it out, but I'm working on the same issue and this approach makes sense to me.

Multiple authentication schemes with Devise and Rails 3

This is probably a common question, but I haven't seen any complete answers to it anywhere:
I have an Rails 3 app that is using Devise for authentication on the web and is working fine. All actions on all controllers are authenticated and the routes are all restful. Users get redirected to a web page to enter their username and password and then can access the resources.
Now I need to add an API to the system. Most of the controllers/actions will be shared between the web and API users, but the API users will have a different authentication scheme (API keys perhaps).
So, if a web user goes to
/projects/1/users
to see the users on the web, an API user should go to
/api/v1/projects/1/users
to see the same thing with a parameter like APIKey=abcd.... either in the header or params to allow authentication.
I know the solution is around overriding the SessionController and the Routes but can't find a detailed answer about this anywhere.
You might be able to achieve the same results by using Token authentication:
http://rdoc.info/github/plataformatec/devise/master/Devise/Models/TokenAuthenticatable

How do you make rails 3 work as a backend for mobile apps with support for session_id's in the request?

I am trying to build a rails 3 back-end for a mobile application. However, I am new to creating rails 3 apps.
Users will need to have a session on the server, but I have no support for normal cookies, so I would need to send a session_id along with every request.
What kind of authentication system should I use in rails 3, is there a gem?
I have read that in rails 2 it was possible to set the session_id from the URL, but that this function is stripped from rails 3 due to security concerns. Is this even true? If there is a way to do this, I am very interested, despite the possible security holes.
Usually I'd use HTTP Digest authentication to solve this problem. Most of the Rails authentication plugins (such as Authlogic, probably Devise) will support HTTP Basic or Digest authentication though a plugin. In this way, you don't have to worry about expired cookies and the like.
You can also pass an api_key parameter instead of a session id.
In many cases I've used an api key as the HTTP Basic username. This gives clean URLs and session-less authentication.
The security problem you're probably referring to is Cross-Site Request Forgery. It is indeed a real problem. Its why you hide actions with side effects (create, update, destroy) behind forms with a CSRF token. Otherwise a malicious link can perform unintended actions to a site that you're already authenticated to without needing to know your credentials.
As long as your API key isn't easily discoverable by anyone in an automated fashion, the risk should be minimal.
Update
A small update: Devise no longer has authentication_token as its implementation was deemed too insecure. A good alternative is Brian Auton's suggestion.
The summary of his method is that he generates an authentication_key AND authentication_secret in a separate model. You then authenticate by sending both your key and secret, if a match is found you are temporarily signed in as a user.
In your application controller this looks like so:
class ApplicationController < ActionController::Base
before_filter :authenticate_from_token
protected
def authenticate_from_token
if current_token.try :authenticatable
sign_in token.authenticatable, store: false
end
end
def current_token
AuthenticationToken.find_authenticated({
secret: (params[:secret] || request.headers[:secret]),
secret_id: (params[:secret_id] || request.headers[:secret_id]),
})
end
end
The authenticatable of the token in this case is a User model, or any other thing that has been made authenticatable (the tokens are polymorphic). As you can see it can easily be made to work with Devise.
I like this method a lot and have implemented it in a recent API. Do read up on it on his website.
Old answer
Outdated answer, kept for reference to older versions of Devise: Devise has a 'authentication_token' column which I can use for authenticating a user. I could have a login API method which I will send a username + password too, then get the token back and store that locally to sign all my other calls with. It basically is a cookie system, but one that is directly supported by Devise.
On top of this I could re-generate the token on either every call or on every 'session'.