How to effectively test unauthenticated user flows? - ruby-on-rails

Given a non-trivial Rails application with significant numbers of controllers and routes only accessible to authenticated users and even then, only by users with the authorisation, what is the most sensible way to test unauthenticated users and unauthorised users are denied access?
Currently I generally test authenticated user flows through features, and fall back to controller tests to test that routes are not accessible to unauthorised or unauthenticated users.
Obviously ensuring that unauthenticated users get a 401 is easy enough to test, but testing authorisation is another matter. It makes sense to have granular tests for access permissions - I want to know if something I've done has inadvertently given a guest the ability to destroy users - but adding such tests for every root balloons the number of tests drastically.
How should I approach this?

It depends on how you do the authorization. You only need to write as many tests as you write blocks of code that authorize.
If you write specific code to check authorization every place a resource is used, there's no alternative but to write a test, probably a controller spec, for each check. I'd also write one Cucumber scenario to specify what the user sees when authorization is denied and to integration-test the entire stack.
If you move your authorization into a framework, whether something like Cancan or a framework of your own, that only requires each controller to call the framework in one place (e.g. CanCan's load_and_authorize_resource), then you only need to write one more spec per controller (one that shows that some authenticated but unauthorized user can't access a resource) to establish that the authorization framework is being called. If the framework moves authorization logic to a new set of classes (e.g. CanCan::Ability subclasses), you'll need to unit-test those classes, but you'll probably be able to use each such class in more than one place, so the number of tests they need won't increase multiplicatively, and their tests will be simpler than controller specs.
Similarly, if your authorization framework were entirely configuration-driven and you had to call it only in one place in your application, you'd only need to write that one Cucumber scenario.
You can probably think of different architectures which would lead to different testing requirements, but I think these examples show the general idea.

Related

Using Google Authenticator with Symfony Security

I'm looking to add 2 factor login to my Silex app.
However, I'm having some road blocks on how to get this working correctly.
my biggest sticking point is having the firewall not fully log the user in and instead direct them to a page to confirm their identity.
I've thought about using Symfony Guard, but looking at the documentation, I didn't see anything that would let me prevent the user from being logged in.
I don't have any code yet, at this point, I'm just tying to design the flow and after I have a concrete execution plan, I was going to then begin writing code.
I remember reading a blog post about doing this in Sf2, but I cannot find it now. Here's the gist:
the login part is the usual one
create a listener for the controller event, and redirect to the 2FA controller unless the user has a role (ROLE_GOOGLE_AUTHENTICATED or similar) and unless the user is requesting that route
on that url render a form and check if it's a post, and if the code verifies add that role to the user
I'm sure you can adapt it for silex. You can also check the bundles that exist for Sf2 on how they work exactly.

Authorization strategy on a per-client basis

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.

Two tier sign in with Devise (Amazon style)

Let's imagine I have following scenario
User receives an email that there is a new item waiting for her
Clicks on a link and is able to either confirm or reject item (details skipped)
Can then access a list of all her items
The trick is that I would like to allow all this happen without user signing in but then limit access to other parts of the website (like sending an item to another user)
How I see it is that:
when user clicks a link she is signed in but only on tier 1 - with access only to confirm/reject action and read only to index of items (that's when Devise session is created)
when user wants to access other part of the website the sign in page is presented
when user comes to the website just by typing in the url http://example.com and wants to access own account she is asked to sign in.
after sign in session is "promoted" to tier which allows full access
after some time of inactivity session is downgraded to tier 1 for security reasons
My inspiration comes from how Amazon works - you can access in read-only most parts of the account but before performing any destructible actions you need to sign in.
Does anyone have any experience with such approach or can share some blog posts, etc?
I didn's find anything on SO and Google mostly returned things about two-factor auth which is not the case here.
I also understand that there are security concerns with links in email.
I have implemented a very similar behavior few months ago. I don't have very interesting resources to show you but I can explain a bit how you could organize or think about the problem to solve.
Description
For the problem you state, it looks like once you have identified a user, you have two different states you can give him:
limited access (perform certain actions, read most of the resources, etc)
full access (allows them to do anything they would normally do).
Having stated that, what you need to do is figure out in which cases you will give a user each access state (for example):
signing in with email token -> limited access
password -> full access
authentication_token -> full access
omniauth -> full access
After that, you will need to save this information in the user session. This should be done anytime the user is authenticated, as you will know what strategy was used to authenticate the user.
To know if a user can or cannot perform an action you will need two things, know what the user can do, and the current "access state". Depending on those you will decide wether the user is allowed or not to perform a certain action.
Whenever a user can't perform an action and is logged in with limited access you should bring him to the flow for verifying his crendetials. This flow is pretty simple, almost like a sign in but just with the password. Once you verify his crendetials you can upgrade his authorization to a full access one.
Implementation details
I recommend you to create a Authorization model which will represent the "access states" that I mentioned. This model will have to be serialized in the session so you should be able to build it from a simple structure and serialize it again into that structure. The simplest the better (a boolean flag, an array or maybe a hash). For the case mentioned, it looks like a boolean would do the job.
Regarding implementation details, I recommend you implementing this with a Warden after_atuhentication callback.
You could implement this with CanCan by creating you own Ability that would be built with an Authorization instance and a User instance.
I think you're confusing authorization and authentication. Devise is an authentication solution, meaning it handles the "proof me you are who you say you are" part. Authorization is the "Ok, I know who you are, now let's see what can you do". Devise doesn't provide an authorization system beyond the simple "logged/not logged". If you need a more complex authorization system, use an authorization gem. CanCan is very popular.

how to limit visitors to an api end point to those that are visiting my site

My website does not require login. And actions that the user takes end in calling ASP.NET MVC Controller Action Methods. Any other company can call those endpoints at this time and use my APIs in this way. I want to make sure that only users who are on my site can access these APIs.
How do I achieve that?
Adding clarification:
Say my site is consoto.com. I want my methods to work only if the end user is on consoto.com. Now if another company or hacker builds a site say hackland.com and in their javascript calls my methods, I want it to fail because their users are not on consoto.com and instead are on hackLand.com.
Many sites these days offer paid official API access to their core functionality. If they don't implement a mechanism like this, others will have the option to call the methods the actual site uses instead of going through the paid API. What would prevent a hackland.com to just use the methods used by consoto.com and end up not paying for the service?
I'm not %100 sure I understand you but, it seems like you only want to give active users on your website the ability to call certain action methods. If that is the case you can decorate the action methods with [ChildActionOnly]. This will force ASP to only allow actions that are called with HTML.Action() in the view code.
controller code
[ChildActionOnly]
public ActionResult someAction()
{
//return whatever you need
}
view code
Html.Action("someAction")
That should prevent people that aren't actively viewing the site from calling an action on the server.
There's no reliable way to achieve that if you don't require authentication on your site a then allow only authenticated users to call server side actions.
One way to do it would be to use some sort of time sensitive token that the client must supply to your Controller.
Implement a web service that takes some credentials from the user, and if the credentials are valid, return a time sensitive token that is hashed based on your server clock. This service should be called through SSL so the credentials are protected in transit.
Each of your protected controllers will expect this token in addition to whatever other inputs they currently expect. You will then validate the token by de-hashing it to obtain the time stored within. Here you can decide how long you want the token to be valid for and choose a time interval to accept. For tokens that do not de-hash property or are expired, return some error result. For tokens that are valid, return the correct result. Rather than the tokens being time sensitive, you can also implement a use count scenario, but the time sensitive approach is easier.
This way, your API controllers will not require login or SSL. Your valid users will just need to obtain the token from you before hand and then use it to call your services. Anyone else can intercept these tokens but they won't be any good after a possibly very short period of time.

Protect deeplink to unauthorized company

I have a multi-tenant application with Companies which have many Users and many Clients.
I have protected the views and controllers with before_filters, so that the current_user can only view clients belonging to the user's company. This works fine, an unauthorized user receives a "you do not have sufficient rights for this action" message. But when a user changes the URL from e.g. "/clients/1/edit" to "clients/2/edit", then he can edit a client from another company. What's the best way to protect this?
Expand your strategy to protect the clients controller as well - you need to be checking ownership of a client record on every action, since only some people should be able to access some clients.
You should be able to continue with whatever solution you've got. Another way to go about it is to use something like CanCan, which centralizes access, and can make it much easier and more straight forward to debug (and more importantly, confirm via your test suite) that users only have access to what they should have access to.
Here is a list of common/popular authorizations gems for Rails that address problems of user access to resources.
Whatever approach you ultimately choose, I can't stress enough how important it is to cover things like security access with test coverage. It's never perfect (because you might forget to test something), but it will mitigate the possibility that you break security access restrictions that are already in place, by keeping your security-related tests as up-to-date as humanly possible.

Resources