How to authenticate based on devise encrypted password? - ruby-on-rails

I have two Rails apps using devise for authentication: a website and an API. Even though I'm the owner of these 2 apps, for many reasons, I wanted complete separation between the two. When a user signs up on the website, an account is automatically created on the API side. The biggest problem I have is keeping the users table in sync between the two apps. I ended up with a bunch of RESTful API callbacks on the website user model which create/update the API user.
The second part is calling the API on behalf of the user logged into the website. Problem is that I don't have the user's decrypted password so I can make the API call. All API calls use basic HTTP authentication. The passwords are hashed into the database and cannot be decrypted (which is a good thing, thank you devise). Because I keep all users columns in sync between the 2 databases, my website users encrypted_password column is identical to my API users encrypted_password column.
So, what options do I have for solving this? I'm thinking either modifying the API such that an admin call for each regular call takes an admin username and password and a user ID (to get that user's transactions for example). Or, implement a shared database between the 2 apps - but I have a lot of associations between users and other models... how would indexing even work?! Or, hijack the devise authentication and compare encrypted_password (from my website) to encrypted_password (to my API) - since they are the exact same; but this opens a security can of worms. Or, create keys authentication and generate unique GUIDs for users... but then that would be just as bad as having decrypted password stored in a database. I hate all these solutions. Perhaps someone has a better idea?

When you authenticate a user in Devise it takes the plaintext password and combines it with a pepper and passes it through bcrypt. If the encypted password matches the value in the DB the record is returned.
The pepper is based on your rails app secret. So unless the two apps have the exact same secret then authentication will fail even if you have the correct encrypted password. Remember that the input to bcrypt has to be identical to give the same result. That means the same plaintext, salt, pepper and number of stretches.
You're correct in that sharing the passwords back and forth is not a solid solution. You are also correct in that using UUIDs instead of a numerical auto-incrementing id is part of the solution.
What you can do is implement your own authentication provider. The Doorkeeper gem makes it pretty easy to setup your own OAuth provider (or you can use Auth0 if using an external service is acceptable).
The web app would use Devise + OmniAuth to authenticate users against the authentication provider and use the credentials returned to identify the user in the web application.
For the API application I would use Knock for JWT authentication. Where the API server proxies to your authentication server via the oauth gem.
However you should consider at this point if your web and API app really should be running on separate DBs. Keeping writes in sync across both DBs can be quite the task and your should ask yourself if your really need it at this stage.

JWTs would make it easy to include information such as user id right in the JWT without relying on external persistence such as a users table. Just ensure the token is correctly signed and don't store personal information in it such as email since usually JWTs are not encrypted but only signed.
I actually did a write up tutorial on this while back if interested.
https://www.moesif.com/blog/technical/restful-apis/Authorization-on-RESTful-APIs/

Related

In the example oauth2 server for Authlib, why is user_id tied to client meta data?

I'm working with authlib for an oidc provider server. I'm using example-oauth2-server as a learning tool. I'm trying to understand why, in the database schema, the User_ID is tied to the client. I understand this is an oauth2 server as opposed to oidc. But the confusion still stands. Am I meant to be registering a client for each human/service user? This isn't a requirement in either oauth2 or oidc right? In fact there's nothing at all in oidc client registration docs about a user_id field in relation to client metadata.
In a different oidc library I used, the registration is "user agnostic" for the lack of a better phrase. I can't wrap my head around why it should not be. I mean, I CAN create a client for each user, but why should I want to do so if I wanted, for example, an Android app capable of authentication and authorization via my oidc provider? Could I not achieve something similar (assuming the purpose is to specifically identify which user is logging in,which, you can determine by the fact that said specific user is logging in) by storing the user_id in some other table?
Any direction or even discussion would be appreciated.

Rails Devise token and cookie session at same time

I have a rails web which has been using cookie session authentication (devise) from its beginning. Now, we are developing an ionic mobile application which uses the API available from the rails application.
I have considered to use JWT or token authentication for this new application but I can't find a way to combine both authentication methods, cookie and JWT. Also, both applications have different requirements. For example, in the web a user can have concurrent sessions only if he/she has a certain role. On the opposite, in the mobile application it is possible to have concurrent session without any restriction.
I have reading a lot trying to figure how to combine both methods but I can't find the way. Maybe I should consider to use only one of the methods (JWT) or use another approach (doorkeeper).
Finally I have found a solution. According to refaelos and Zac Stewart, I have combined devise with JWT gem, using the last as a new strategy for the first. By this way, when I don't use JWT tokens, devise will choose the default strategy (database_authenticatable in my case). Otherwise, it will use JWT strategy.
However, when the user is not authenticated and make a post request to Session#create to get the credentials, the strategy chosen by devise/warden is database_authenticatable. In order to avoid this, I needed to add a new parameter to the request but only for this case because, as I said, when the token appears in the request, the new strategy is selected.
See also:
An Introduction to Using JWT Authentication in Rails

How to secure basic methods like user creation in an API

I'm learning about developing APIs with rails, but I can't find how to secure the base methods like user creation. Let's say I have a rails backend API and a frontend mobile app. I want the app to be able to make API calls to create a new user. Off course, not everyone should be able to create a new user, so it should have some kind of authentication. I could use basic or digest authentication (doesn't really matter, because I'll definitely use SSL), but then I would have to hardcode the credentials into my app. If the credentials are discovered somehow, I would have to change them, but that would mean that all instances of the app are no longer authenticated and they can't create users anymore.
The things I would like to have:
Only my apps should be able to use the user creation calls.
It should be easy to change the credentials, or the credentials should change automatically over time. If they would involve the date and time for example, it would be harder to crack.
It should be impossible (or VERY hard) to beat the system behind it, while having knowledge of a couple of the credentials over time.
Would it be possible for example to let my apps generate public and private key pairs at random and use them? What's the standard way of securing these calls?
Thanks in advance,
Rugen Heidbuchel
I could share my own experience:
https protocol communication with API. That is your last sentence about private/public keys, all is built in into https.
Doorkeeper (we combine it with Devise) gem for Oauth (github accounts in my case) as authentication, while you can use pairs of user/passwords instead.
CanCanCan gem as authorization (User creation restriction is about authorization and not authentication)
Set of that three tools should provide essential security level for your API. I believe cancancan could be under discussion, while devise is mostly industry standard.

Using rails secret to salt authentication keys in devise

I am creating an ember app that has devise worked in for authentication. I'm really getting stuck with how all these different tokens come into play.
I'm reimplementing the recently deprecated :token_authenticatable devise "strategy" using the method described here. I'd like to add token authentication to my API and sign requests to that with the user's token.
What I'm wondering is, even though it's using Devise.secure_compare to thwart timing attacks, it's still storing the authentication_token in plain text, so if anyone were to gain access to the database, those tokens could potentially used to steal a session, no?
Devise seems to use two different types of "tokens" in the modules:
Creating a token with Devise.friendly_token and storing it as plain text. Then doing a look up by this token (as used in :rememberable).
Creating a salted token with Devise.token_generator (as seem in :confirmable).
The second method looks to me like the token is salted using Devise.secret_key which is derived from the Rails secret in config/secrets.yml. That way the token is encrypted and if the database was exposed for some reason, the tokens couldn't be used, right? Would be the equivalent of having a private key (rails secret) and a public key (authentication_token).
I have quite a few concerns:
Should I use Devise.token_generator to create my authentication_tokens?
What is the word on security for these type of tokens?
How does the CSRF token factor into Devise?
Devise does a lot of things, and not necessarily the things your particular application needs or in the way your applications needs. I found it wasn't a good fit for my application. The lack of support/removal of api token authentication provided enough motivation to move on and implement what I needed. I was able to implement token auth from scratch fairly easily. I also gained full flexibility for managing user signup/workflows/invitations and so on without the constraints and contortions required of Devise. I still use Warden which Devise also uses for its Rack middleware integration.
I've provided an example of implementing token authentication/authorisation on another stackoverflow question. You should be able to use that code as a starting point for your token authentication, and implement any additional token protection you require. I'm also using my oAuth token approach with Ember.js.
Also consider if encrypting tokens is just hand-waving because depending on your deployment environment and how you manage your master key/secret, it may be giving a false sense of security. Also remember that encryption says NOTHING about the integrity/validity of the token or related authentication/authorisation information, unless you also have a MAC/signature that encompasses everything used in your access decision. So whilst you may go to the trouble of protecting tokens from attackers whom have access to your database, it may be trivial for those same attackers to inject bogus tokens or elevate privileges for existing users in your database, or just steal or modify the real data which may be what they really want to achieve!
I've made some large comments in respect of providing integrity and confidentiality controls for ALL authentication/authorisation information (which tokens are part of) on the Doorkeeper gem. I would suggest reading the full issue to get an idea of the scope of the problem and things to consider because none of the gems currently do what should be done. I've provided an overview on how to avoid storing tokens on the server altogether and I've provided some sample token generation and authentication code in a gist which also deals with timing based attacks.

Simple way to authenticate users in ASP.NET MVC without providers

I'm trying to understand how authentication in ASP.NET MVC works. I do not want the built-in MembershipProvider creating a local database behind the scenes. I've also looked at some blog posts talking about custom membership providers. While looking for a much simpler forms authentication model, I found the following:
FormsAuthentication.SetAuthCookie("myusername", true);
FormsAuthentication.SignOut();
The idea is to send the username and salted hashed password to the database and see if they match a record in there. If the user exists, then I pass the username to SethAuthCookie. My questions are:
Should the username be encrypted?
What happens if there are multiple servers and the user is surfing the website? I believe any one of the servers can serve content to the user, so how do they know if the user has been authenticated?
What's the preferred way of authenticating users in MVC without providers? Am I on the right track or should I be looking into something else?
Should the username be encrypted?
No.
What happens if there are multiple servers and the user is surfing the
website? I believe any one of the servers can serve content to the
user, so how do they know if the user has been authenticated?
At each request the server reads the authentication cookie that is sent by the client browser and which was generated by the FormsAuthentication.SetAuthCookie call, decrypts it and retrieves the username that is stored inside. Just make sure that you have set the same machine keys for all nodes of your server farm so that no matter which node emitted the authentication cookie, all other nodes can decrypt it.
What's the preferred way of authenticating users in MVC without
providers? Am I on the right track or should I be looking into
something else?
You are on the right track. You use the FormsAuthentication.SetAuthCookie method to emit the authentication cookie once you have verified that the password hash matches the one of the user in the database and in subsequent actions you could use the User.Identity.Name property to retrieve the currently authenticated user.
I would also recommend you checking out the following article which provides a good overview of how forms authentication works in ASP.NET.

Resources