Rails: authentication through different domains - ruby-on-rails

I have to integrate the web application I am developing, with an external web application in order to use their services.
Unfortunately this is my very first work and I am a bit confused.
They asked me to provide the verification URL with login token to help them identify which users come from my website.
Users from my app want to get information from 3party app database
To do that, the 3party app need to know who they are because, there are different roles in app. And each of them will have different privileges on the 3party app
Login to 3party app has to be in my app. They just want a verification URL with login token.
Is it possible to use token authentication through devise to do that?
Can I generate a token, store it in clients browser and than use that to get them authenticated in the external domain?

I hope this answer isn't too obvious. Sounds like you're just starting off on this and need some guidance.
From what I read, I get the following requirements:
You need to be able to be the authentication authority for another app
The 3rd party app wants to exchange and verify credentials via auth tokens
The 3rd party app wants the urls to the API calls to do this from you app
I'll cover this in a broad sense, and let you search out a specific solution. Basically you need a way to generate secure authentication tokens. Devise should do this, along with authlogic and several others. What you don't want to do is try to roll your own auth token generation. Definitely use the gems out there to do this for you.
Once you've got tokens being generated, here's an overview of the basic transaction, where an auth token is simply passed as a parameter into a controller action (https is your friend in this transaction, FYI).
3rd party app makes an API call with a token provided by your app
Your app checks the auth token for validity, and takes whatever action is requested, if the authentication succeeds
Your app responds with authentication success/failure code, and any other response data that the 3rd party app requested, if the authentication was successful
How the tokens are handed off to the 3rd party app, so it can use it to make API requests, is a matter of how you want your app to work. However, a common practice is to use a method is something which follows the following pattern:
When the 3rd party app needs to make an API request on a user's behalf, the 3rd party app redirects to your app where the user enters their credentials (if they haven't already). This way the 3rd party app never gets the user's username+password directly.
Assuming a successful authentication, your app then redirects back to your callback URL, passing in as a parameter the auth token generated by your app. That auth token is what is used in future API calls, until and unless the auth token expires (it's up to you when they expire, of course, since you're the authentication authority).
If at all possible, it would be great if you can actually use an OAuth provider or some other mechanism that already exists to act as a 3rd party authentication means that both your app, and the 3rd party app trusts. To go down that route, check out this Railscast: http://railscasts.com/episodes/235-omniauth-part-1
...but of course, since you already have an existing app, and especially in enterprise apps, it's less common to be able to integrate oauth providers into your application. But either way, whenever possible it's almost always preferable to offload the authentication mechanism to another party. This is mostly because you want security experts to be worrying about, and updating their authentication services, and to leave the app code to you.
On the other hand, even if you don't go with an OAuth provider as way of solving this, the railscast noted above will give you an idea and pattern to follow when building your own API/callback mechanism. What you'll wind up with is a series of API calls/actions. The routes (urls to these API calls) can, of course, be anything. But as an example, they might look something like this:
/api/auth/:id {:controller=>"api", :action=>"auth"}
...which takes as parameters, the a unique key identifying the 3rd party app, along with the 3rd party app's secret key (essentially a password), and a callback url for both success and failures, and responds with success/failure, and a valid auth token upon success.
/api/some/restful/resource/call # example API call for some RESTful resource you make available
... etc. ...
Like I said, even if you don't go with a 3rd party authentication provider, following the railscast I posted (as well as the follow up episodes) will give you an idea of the implementation pattern that other robust APIs out there use. Setting up a demo application to do facebook authentication would also be very instructive, and would probably only take you a couple of hours, just to get a handle on the workflow.

Related

How poorly have I implemented OAuth/OpenId?

I can't help but think I've implemented Open ID slightly incorrectly, but I also cannot find why I've done the implementation the way I have is bad or not.
Scenario:
Website - Used forms authentication before being updated to use OWIN. Forms auth has been stripped out.
Website now supports OpenId to Okta. This is being implemented for a large company of our users to facilitate their logins. This is functional.
The method I use for the site models how Microsoft does logins. On email domain detection, we redirect the user to the login page for their domain. In this case, Okta. We receive the callback, and look up the user in our existing data, and generate a cookie based on our existing data (or create a new user account if they don't have one).
Essentially, just using Okta to confirm they are a valid user, and then we log them in with our user data. We foresee doing this for other companies as well.
Problem:
I have a desktop (WPF) client that requires a login to our website. This talks to API's that already exist using an auth key/token system we built many years ago. Ideally, we do something similar. Use Okta to verify the user is a user of that system, then generate a token that can be used for these API's.
Here is where I'm not sure I've done this appropriately.
The desktop client calls an API endpoint on our site with the email domain the user entered. We verify the user's domain is allowed to use SSO, and if so, we issue back a challenge endpoint for the client to call. This challenge endpoint is then called by the desktop client to launch the users default browser.
This challenge endpoint is an endpoint on OUR website, that essentially triggers the challenge to the IdP. After login, a callback is called on OUR website, to process the auth response. We verify the user's account is valid, and get the refresh token from the response. With the refresh token, and an identifier of the user, this data is then sent back to the desktop client using localhost:randomPort so the client can consume the refresh token and identitifer. (Note that I do encrypt the refresh token and identifier's before returning them to the client)
This refresh token is then POSTed to OUR website, along with their identifier (so we can identify the IdP we should call), then use an OIDC client to verify the refresh token is still valid. If the refresh token is still valid, we generate an app token and return it.
Is there a glaring issue with how this is implemented that I'm not seeing? How can I do this differently?
You seem to be missing the role of an Authorization Server (AS) that you own, to manage connections to other systems and to issue tokens to your apps.
You seem to have some good separation and to be doing quite a few things well - eg you are using your own tokens rather than foreign Okta tokens. The main issue is likely to be growing the system.
PREFERRED BEHAVIOUR
An AS should result in simpler code and a system that is easier to extend:
You can add new authentication methods quickly
This should involve just adding a connection (eg Okta) to your AS
Doing so requires zero code changes in your UIs and APIs
Your UIs just use standard OpenID Connect flows and call AS endpoints, regardless of the authentication method used
Your APIs just verify tokens issued by the AS, then authorize requests, regardless of the authentication method used
Some scripting is needed in the AS, but typically this is small.
FEATURES
In terms of what an AS should do for you, have a browse of the Curity Concepts Pages. I work there, and we try to write about the science of OAuth and the common extensibility features software companies need.
CHOOSING YOUR MOMENTS
Integrating an AS and getting past all the blocking issues is a gradual journey though, and involves learning. So it requires choosing your moments, spikes and getting buy in from your stakeholders.
The main objective should always be simple and standard code in your apps, that is easy to scale. OAuth and the Authorization Server give you design patterns that help with this.

What are you supposed to do after an OAuth2 call succeeds?

At work we have never used 3rd party Auth solutions and I'm trying to inform myself of how they work for my personal projects. Getting the response is easy enough, but feel a bit lost on what to do after I get the response back. Am I supposed to send the auth token to the backend so it can be verified then trigger my app's login process for the given e-mail address/username? Logging them in essentially without a password?
There's two basic use cases for OAuth 2.0 which will determine what you do after the user is authorized. Your use case can also determine which OAuth 2.0 permission scopes you request the user to authorize your app for.
1. Single Sign-on
A simple use case for using a 3rd party OAuth solution is to leverage the 3rd party to perform authentication. Two reasons for this include:
Your users may wish the convenience of logging in with another provider (like Google, Facebook, Twitter, etc.), one where he or she may already have an active session.
You may not wish to implement your own login / authentication / password reset process.
Either way, a common way to implement this is to make an API request using the token to retrieve the user's email address after a successful authentication, which you then map to your own user database to establish an authenticated session for your service. Since you only need to retrieve the user's email address and minimal other information (e.g. name) in this use case, you can ask for a minimal set of scopes.
I do this in my oauth2more library where after receiving a token, I have a generic interface to load a user data which I convert to a SCIM user object. Because I've abstracted the code to retrieve user info in this manner, it's easy to support SSO across mulitple auth providers.
2. Using Service Features
A slightly different use case is that you want the user to authorize your app so you can make commands on behalf of the user via API. In this case, you will use the token to call more general APIs to accomplish your goals. A caveat is that you will need to make sure you ask for the proper permissions when asking the user to authorize your app.
As an example, one thing I've done is ask the user to sign in with Google so I can then make API calls to create and edit Google Sheets and Google Slides using APIs on their behalf.

Use password credential flow and some 3rd party authorization server

This is more of a general question but I hope it is still valid for SO.
So far I have learned, that in general, a mobile app (such as official Pinterest app) use the Password credential flow to let their users login and access the API directly. (let's just assume they use OAuth for this)
So they collect username and password, send it to their server and get a token in return which is used for subsequent requests.
Now a user did not want to register and created an account using e.g. Facebook as the authorization server. So my question is:
How is this flow implemented?
My educated guess:
User chooses "Login with Facebook" in mobile app
Facebook Login Page opens with return_uri = mobile app
Mobile app receives auth token
Mobile app uses client credentials and says the API: Use this token for user X
Is this correct?
First of all, apps should not use the Password Credentials Grant. The specification is rather clear about it:
In the traditional client-server authentication model, the client
requests an access-restricted resource (protected resource) on the
server by authenticating with the server using the resource owner's
credentials. In order to provide third-party applications access to
restricted resources, the resource owner shares its credentials with
the third party. This creates several problems and limitations
The specification then goes on describing those problems.
And about the Resource Owner Password Credentials Grant:
The authorization server should take special care when enabling this grant type and only allow it when other flows are not viable.
The entire purpose of OAuth 2.0, I to not have to use something like the Password Credentials Grant, where the user hands over their password to the application.
About your second question: what happens when a user does not want to register and create an account with your app, but wants to use e.g. Facebook for authentication?
Remember that both the Implicit Grant, as well as the Authorization Code Grant, work by using a browser control to authenticate the user. In that browser session with the Authorization Server, you are free to authenticate your user in any which way you want. Certainly, you can use your own user/password database, but you could also use other mechanisms, such as WS-Federation. In your case, it sounds like the user want to authenticate using Facebook.
Authenticating using Facebook is then not done by your client app, but by your Authorization Server. It typically does that by using the Facebook Authorization Code Grant, followed by a call to read the user's profile to obtain their Facebook user id, name, and so on.
If you do not want to build such an Authorization server yourself, you can use an existing one. Several companies offer login-as-a-service solutions, including the one I work for.
UPDATE: You asked several follow up questions in a comment below. I'll answer them briefly here:
First of all, the fact that some companies that use OAuth to secure their services allow for a Password Credentials Grant, does not imply that you should. In fact, there are probably more examples of companies that don't offer this possibility, than companies that do.
There are real trust issues, and real security risks with sharing your password with a device app. To start with, the app on the device is easier to hack than a server. Furthermore, if you give the app your password, presumably that app also needs to store it somewhere for future use. As a user, I just have to hope that that storage is safe form possible malware running on my machine. For more issues, see the introduction in the OAuth 2.0 specification mentioned above.
Secondly, all good Authorization Servers differentiate between First Party Clients and Third Party Clients. A First Party Client such as yours is controlled by the same company that controls the Authorization Server, and for such an app the Authorization Server does not ask for user permission to share data, since it makes no sense to talk about sharing data with yourself. That is why the web sites of these companies don't ask you whether you allow to share the data they hold on your behalf with them. They already have it, and there is no "sharing" going on.
Of course, you might argue that you have never seen any of these companies talking about this distinction between First Party Clients and Third Party Clients. But the reason they don't should be obvious: when you deal with them, you are always a Third Party App. They don't need to tell you that they treat themselves differently.
The mechanism I would choose in your scenario depends on the nature of the client app, and the nature of the services it accesses. What are your requirements?
Anyway, if the device the application is running on has a secure storage facility, such as Windows Phone 8.1, I would probably consider using the Authorization Code Grant without client credentials. That way, the user never has to log in again. If we're talking about a web site or a SPA, I would consider the Implicit Grant (where the "remember me" feature, if any, is offered by the Authorization Server). Again, the specification gives advantages and disadvantages of each grant type for several scenario's.

restful api (rails), mvc javascript app (ember or backbone) and token based authentication

I read about token based authentication and get the general id. What I don't understand is why on the frontend (ember in my case) I would need such a token if all communication is with your own restful api backend (rails in my case). If you communicate strictly with your own backend, and you leave the authentication in that backend then why do you need the token in your ember app?
Your backend would serve as a proxy sometimes but is that bad? Is it better to do it directly from the ember app if possible?
I would (mainly) go to twitter for queries.
Thanks for sharing your ideas.
I'm a bit new to this topic myself, but your question is also a bit unclear. If you mean the consumer key tokens that are used in oAuth systems, these are required to ensure that the third-party using your API has actually been granted access to use it - anyone without a consumer key cannot use your API.
Alternatively, if you are referring to users being authenticated using an authentication token...
When you create a rails app that has authentication (for example using the devise gem) a sessions controller is also created/used. Sessions(/cookies) are basically a way of 'remembering' that the user has logged in. This avoids having to resend username/password with every action the user performs in order to authenticate him/her for that action.
This approach works perfectly fine when it comes to web apps because all browsers support cookies. However, this is not true when it comes to mobile apps. It is not possible to keep a session/cookies when using a native app (well it is technically possible, but from what I've read it seems to require quite a bit of manual labor and a bit of code wizardry to get it working correctly).
Now, when you create an API for your app, you need to bear in mind that your API may be used for creating a mobile app (either by you in the future or if you open it to the public). This means that using sessions probably isn't a good idea. For each request that requires authorization the username/password will need to be sent to ensure the user has access to perform the requested action. But sending username/password with each request is definitely a bad idea. That's where token authentication comes in. If you've ever used devise, you will notice there is an option to enable token authentication. This basically allows the 3rd party to send a token rather than the username/password and works just the same. The good thing about this approach is that even if a token gets stolen they can expire and a new one can be generated without the user even realising and without the users password being stolen.
(I'm fairly new to the topic myself, from what I've gathered so far that seems to be how things work. Now if I have made any mistakes in my explanation/understanding I hope people will jump in an correct me.)

Use OAuth 2.0 Tokens to login to Salesforce.com

Currently we are not using OAuth with our apps but we are working on making the shift, we have direct login and capture the user/pass that was entered and store those. We then turn around and use the stored credentials for a feature that allows the user to open a record within Salesforce.com, we pass the user/pass in to the login endpoint along with a starting URL to the specific record, this works great and is a well liked feature as it is a simple SSO from the App to Salesforce.com where the user can see all data that may not be visible within the app.
Moving to OAuth 2.0 and using the standard webflow, we no longer can capture the user/pass, which is actually a good thing as far as security is concerned. We would however like to keep this functionality, is there anyway of SSO'ing into Salesforce.com by passing along one of the OAuth tokens or some kind of sesson id?
After reading more and thinking about what OAuth accomplishes I feel like this probably isn't possible being that the tokens obtained are meant to be used only with the API and not with the front end system. I hope that I am wrong though and there is a way to login to the front end using these tokens.
EDIT
Ok I am editing to hopefully make this more clear. Currently user's authenticate using the login() API method with their user/pass, we store this user/pass locally (not ideal). We then sync a subset of data that the users can access anytime within the app, being that it is a subset, we have a feature to "SSO" to the Salesforce.com front-end. This simply opens Salesforce.com in a web-view (UIWebView) using the URL https://ns8.salesforce.com/?pw=PASSWORD&un=username#example.com&startURL=/recordId. This will log us in to Salesforce.com and open the specified record.
Moving forward we want to use OAuth 2.0 with the web flow so that we aren't handling the user/pass and so that we do not have to deal with Security Tokens or opening specific IP ranges to allow login without a Security Token.
With that said, is there anyway to use the tokens/credentials received from the OAuth authentication to open Salesforce.com, automatically log the user in, and goto a specific record?
I may have mis-used "single sign on" before, but in a sense, this simulates an SSO from our App to Salesforce.com, in that our users can touch a single button within the app and be logged in to the Salesforce.com web interface.
When you request an OAuth token, you can specify what scope it has, options include api only (the original type of tokens), or other options which include the ability to use the token with the UI pages. (see the scope parameter detail in the help). One of the still missing peices is a way to bootstrap the UI with that token when all you can do is tell a browser/webview to goto a URL, but a widely used (but unsupported) way is via frontdoor.jsp, e.g. you'd open https://{instance}/secur/frontdoor.jsp?sid={the_Access_token}&retURL={optional_relative_url_to_open} remember to URLEncode the 2 values.
So I think you are saying your application uses the SFDC username and password to just authenticate to retrieve a record from SFDC to display in your app?
IF this is correct - which I think it is - then you could just use the standard Salesforce Single Sign On system to authenticate. There is a guide here which outlines the process of setting up a SAML SSO system with Pat Patterson writing an interesting feature on how the security system works here. He has also written a great blog post on DeveloperForce here about the nitty details of OAuth in general for Force.com and not just the SAML setup. I have used the OAuth system in an iPad app against SFDC and it works quickly and easily. I can't see why your system should be unable to use the protocol as you desire.
Direct access into Salesforce is a key benefit of SSO and definitely provided. I'm not sure where you read that SSO in Salesforce is API only. From the SSO PDF pbattisson linked for you:
With single sign-on, users only need to memorize a single password to
access both network resources or external applications and Salesforce.
When accessing Salesforce from inside the corporate network, users are
logged in seamlessly, without being prompted to enter a username or
password. When accessing Salesforce from outside the corporate
network, users' corporate network login works to log them in. With
fewer passwords to manage, system administrators receive fewer
requests to reset forgotten passwords.
OAuth 1 & 2 are both supported, though I'm a fan of OAuth 2 since 1 has really finicky additional steps involving the order of parameters and their encoding sequences. I recently wrote an Apex-Twitter integration and quickly realized it wasn't going to be as easy as Facebook, which uses OAuth 2.0.
But in your case it sounds like you just want to provide users with the ability to actually login to Salesforce and go to a specific landing page once authenticated. This is definitely doable.
Good luck!

Resources