how to secure the server ip, controllers and actions in rails? - ruby-on-rails-3

I want to protect the ip address and url of rails app
xxx.xxx.xxx.xxx/controller/action
are accessible, i want to protect these urls and controller actions.

You can always add a before filter like mentioned below
class CommentsController < ApplicationController
http_basic_authenticate_with name: "foo", password: "secret", only: :name_of_action_you_want_to_restrict
def some method
...
end
end
In this manner you will have a basic authentication for your pages you want to have.
Also if you want to restrict access at a higher level, you will have to go with rails authentication using users and sessions controller.
Hope this helps
Cheers !

Related

Rails route namespaced in omniauth

I have this in routes.rb:
namespace :api do
namespace :v1 do
...
devise_for :users, constraints: { format: :json },
:controllers => { :omniauth_callbacks => "auths" }
...
end
end
And produces among others, these routes:
new_api_v1_user_confirmation GET /api/v1/users/confirmation/new(.:format) api/v1/confirmations#new {:format=>:json}
GET /api/v1/users/confirmation(.:format) api/v1/confirmations#show {:format=>:json}
api_v1_user_omniauth_authorize /users/auth/:provider(.:format) auths#passthru {:provider=>/facebook|twitter|linkedin/, :format=>:json}
api_v1_user_omniauth_callback /users/auth/:action/callback(.:format) auths#(?-mix:facebook|twitter|linkedin) {:format=>:json}
How could a get last two routes namespaced, something like:
/api/v1/auth/:provider(.:format)
/api/v1/auth/:provider/callback(.:format)
Guess I should convert my comments into an answer:
For our app we are doing the pure json api thing, with backbone/marionette. To get oAuth working with devise - I removed it from devise. :) Removed the omniauthable property I had set up and removed the omniauth settings from my initializers/devise.rb. Then reading on the omniauth page I implemented it by itself.
My api lives under "/api/v1"
Created the initializers/omniauth.rb file listing my providers and keys. For each provider I also gave it a :path_prefix=>"/api/v1/auth" property.
Create a callback controller within my api called api/v1/oauth_controller.rb This was properly namespaced with modules and contains my callback path from the services.
Updated my routes to setup the callback route for omni. See here: gist.github.com/DaveSanders/5835642
Within OAuthController.create I consumed the details from the provider and go through the basic flow of "does the social network user exist and have a mapped account?" if so, log them in via devise's user.sign_in? If not, create the user and then sign them in.
Redirect back to my app, which then boots up backbone again, which can then go get the logged in user details and use them as needed.
Your implementation may vary, but the way I handle my oAuth accounts is put them in their own tables (Twitters, Facebooks, etc) and then link them into my devise user. This way I can have multiple accounts associated and the user can log in with any of them.
Also, be sure to set your twitter/facebook callback to something like:
http://127.0.0.1:3000/api/v1/auth/twitter/callback
to match your route in dev.
Hope this helps others. If I forgot a step or you get lost, please ask.

Cancan + Devise, best way to have admin manage users

I am working on an app where a company admin should be able to create and update users in his company. (Users can also create and update their accounts independently).
I used Devise and Cancan for registration and permission management. I configured Devise to get the required signup and user update processes. I created a namespace for the admin views.
My admin controller (/app/controllers/admin/base_controller.rb) looks like this:
class Admin::BaseController < ApplicationController
authorize_resource :class => false
layout 'admin'
def dashboard
end
end
In addition to my "regular" users_controller, I have a controller (/app/controllers/admin/users_controller.rb) and associated views dedicated to Admin user management.
class Admin::UsersController < Admin::BaseController
...
end
Now, what's the cleanest way to implement Devise-related user admin features (at this point, create and update users)?
Have a conditional (based on user permissions) in my "regular" registrations_controller and confirmations_controller to render and redirect different views? (cf. Devise form within a different controller)
Or create new controllers in my admin namespace? If the latest is better, what are the main steps to follow?
Herein lies your issue, once you namespace or move any user management to another controller, you leave the scope of Devise. So at the point where you are in Admin::UsersController, Devise doesn't care about what you do, there are no 'devise-related' admin features as you stated. You can implement your Admin::UsersController as a standard RESTful controller if you wish.
In this manner, creating users through a namespaced controller, Devise will still perform actions such as confirmations. There is one small thing to keep in mind when creating and updating users this way. If you do not set a password as the admin, you will have to delete the password and password_confirmation from the params hash. To do so, the start of your create and update actions would look like so:
if params[:user][:password].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
I employ this same method in many of my applications, and have yet to have it fail.
EDIT
namespace :admin do
resources :users
end

Rails 3: How Does One Restrict Access to IDs

This might be very simple; I don't know Rails very well.
I have a match myController/myAction/myID in my routes.rb that will direct hyperlinks to the proper page (using link_to). But here's the problem: I don't want people to be able to freely modify the id parameter, passing in via the URL whatever they like.
Is there a way to perhaps restrict access to routes to the link_to method only? Or maybe there's another way to go about this, using a passed in hidden variable param or something?
Users access you site via urls like: /controller/action/:id right? A user can change an id and must not view another non authorized resource. How to achieve this?, on your controller, return only those resources that user is allowed to access.
For example, suppose that you are using devise:
class AController < ApplicationController
def index
#resouces = current_user.find_all_by_id params[:id]
end
end
This way if the user tries to access something he does not have access to, he will get an error.
Hope this helps, if not please let me know and I'll try to elaborate.
About current_user, yes it is supposed to be the current logged in user, it doesn't have to be devise, you can implement your own session handling logic and then create a helper method to retrieve the currently logged in user.
About using devise, if you don't want to implement your own session handling logic, plus if you want features like:
remember me
already created views that you can fully customize
authentication
authorization
password encryption
many more (please look at the docs for further information)
Then devise is a good way to go.
Also, it is always a great idea, if possible and as a learning exercise, implement your own authentication and authorization layers, you won't regret.
Best regards
Emmanuel Delgado

Testing access control with cucumber & capybara

I'm using rails_admin and devise in my rails 3 application and writing tests for access control in cucumber.
I want to test that someone not admin cannot access all the routes of rails_admin (for example)
If I explicitly test like so:
Scenario: An authenticated user cannot access site administration
Given I am an authenticated user "kate", "kate#example.com"
When I visit the administration page
Then I should see access denied
I can match the string "the administration page" to the route "rails_admin_dashboard_path" and make my test pass just fine. But this seems to be testing the application the wrong way around. I want to test ALL the routes (loop through them somehow) rather than imply them and maybe miss one or two.
Something like this:
Scenario: An authenticated user cannot access site administration
Given I am an authenticated user "kate", "kate#example.com"
When I visit ANY administration page
Then I should see access denied
Could anyone advise me on how to effectively test this? Am I taking the right approach? Should I be doing this in rspec instead?
As you might be able to tell, I am a bit of a n00b.
I don't think you should be aiming to test every possible route in your Cucumber scenarios. As Andrea S. suggests, if all your admin controllers have a common base, then it should be sufficient to check the admin home page.
One approach would be to create a base controller in your admin namespace that all other admin/controllers inherit from. You can put a before filter in that base controller to check for admin authentication. Like so:
#app/controllers/admin/base.rb
class Admin::Base < ApplicationController
before_filter :ensure_admin_logged_in
end
And have all your other controllers in the admin namespace inherit from this one:
#app/controllers/admin/Pages.rb
class Admin::PagesController < Admin::Base
layout "admin"
end

OmniAuth dynamic callback url to authenticate particular objects instead of current_user

Say I have the models User and Project. Users and projects are HABTM-associated. My setup is actually a bit more complicated than this, but I think for the purposes of my question this will do.
Now, I want to use omniauth to authenticate a particular project with Twitter, Facebook, what have you. I've figured out how to define my omniauth path_prefix, but I don't know how I could pass in a variable like so: config.path_prefix = 'projects/:project_id/auth', much less make a custom callback url like project/:project_id/auth/twitter/callback.
This will break in production. In development you can get away with a session variable. But in production you need to have the callback url contain your project_id as it could be 2 or more register with different auth_project_id's and then you have no way of knowing which one is called afterwards (the callback is asynchronous).
https://github.com/mkdynamic/omniauth-facebook#custom-callback-urlpath
something like config.path_prefix = "projects/#{#project.id}/auth" might work. I'm testing a similar situation right now.
For posterity's sake, I solved it this way:
I added an auth method to my projects controller, which set a session variable session[:auth_project_id] and then redirectes to auth/ + params[:provider].
In my callback controller authentications, I got my project with #project = Project.find(session[:auth_project_id]), created the authentication, and then session[:auth_project_id] = nil to unset the session variable.
I have done similar thing with devise omniauthable, You can pas any parameter with link. like
<%= link_to "Add twitter Account", user_omniauth_authorize_path(:twitter, params: { project_id: #project.id }) %>
Then in your callback controller
before_action :set_project, only: [:twitter]
def set_project
#project = Project.find(request.env['omniauth.params']['project_id'])
end
Note: Do NOT use request.env['omniauth.auth']