How can I restrict access to ALL devise controllers by IP address'? - ruby-on-rails-3

How can I restrict access to ALL devise controllers by IP address'? I am trying to allow only users from a specific IP address to view the admin interface / pages.
I found this approach. Which is to include a restrict_access method in the before filter. However, its a bit repetitive if I have to copy this method on all the Devise controllers that I currently use.
Is there a better approach?
class Admin::SessionsController < Devise::SessionsController
before_filter :restrict_access
# Needed to restrict access to a set of IP's only. We don't want random users trying to access the admin interface
def restrict_access
if Rails.env == 'development' or Rails.env == 'test'
whitelist = ['59.120.201.20', '59.120.201.21'].freeze
else
whitelist = ['59.120.201.20', '59.120.201.21'].freeze
end
unless whitelist.include? request.remote_ip
redirect_to root_path, :notice => 'Access denied!'
end
end
...

Build a class like the following and place it in RAILS_ROOT/lib/blacklist_constraint.rb.
class BlacklistConstraint
def initialize
if Rails.env == 'development' or Rails.env == 'test'
#whitelist = ['59.120.201.20', '59.120.201.21'].freeze
else
#whitelist = ['59.120.201.20', '59.120.201.21'].freeze
end
end
def matches?(request)
!#whitelist.include?(request.remote_ip)
end
end
... and in your routes.rb file...
match "*", :constraints => BlacklistConstraint.new, :controller => "blacklist", :action => "my_access_denied_action"
You may need to load the class in an initializer, or modify your config.autoload_paths += %W(#{Rails.root}/lib) in config/application.rb (Rails3.x).

I believe all of the Devise Controller extend your Application controller, so you could put the method in the ApplicationController as a protected method then you only need to call the
before_filter :restrict_access
on each devise controller.

Related

Devise: Logout *without* redirecting?

Im trying to logout with devise but without redirecting! So I want to disable the redirect after logout. The reason for this is I want to render a certain template instead.
How to logout a user from devise without redirecting them for --> this method only <--? Im already overriding the devise session controller.
My method ( called from before filter in application_controller.rb)
def check_concurrent_session
if user_signed_in?
if current_user && !(session[:token] == current_user.login_token)
render :template => "users/logout_duplex", :layout => "application", :locals => { sub_layout => "left" }
# The next line always redirects to signout_path
# I want to disable the complete redirect so it just logs out and shows the rendered template
Devise.sign_out_all_scopes ? sign_out : sign_out(#user)
return
end
end
end
Inherit sessions controller from devise and have your own implementation of after_sign_out_path_for. That's the method devise uses to redirect after signout.
class SessionsController < Devise::SessionsController
protected
def after_sign_out_path_for(resource)
//your implementation
end
end
Add this to your config/routes.rb
devise_for :users, :controllers => {:sessions => 'sessions'}
Devise implementation of the method looks like below
def after_sign_out_path_for(resource_or_scope)
respond_to?(:root_path) ? root_path : "/"
end

Issue with helper_methods from views rails

I have a very frustrating issue.
I can't call any helper method from my views in rails.This is what I have:
ApplicationController.rb
class ApplicationController < ActionController::Base
protect_from_forgery
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
helper_method :all
end
/app/views/welcome/_navi_bar.haml:
%ul.nav.nav-pills.pull-right
%li.pull-right
- if current_user
%a.btn-small{"data-toggle" => "modal", :href => log_out_path, :role => "button"}
%i.icon-user.icon-white
%strong
Log Out
- else
%a.btn-small{"data-toggle" => "modal", :href => "#LoginBox", :role => "button"}
%i.icon-user.icon-white
%strong
Login
This is what I get as error:
undefined local variable or method `current_user' for #<#<Class:0x007ff0a0544668>:0x007ff0a05414b8>
I really don't get what the problem is. Please help !
You have written your code in application controller instead of application helper
That is the reason why your method is not getting called
if you want to check if current user is logged in or not
you may just use before filter in application controller and call the method
whenever you dont need to check the method add skip before filter in that place

How to authenticate single action with two devise?

I have implemented two devise(version: 1.4.8) model in my project for example User and Admin.
Is there any option to configure authentication for single action in same controller with two devise?. example for CartsControler:
index, show -> can access either admin or user
create, update, delete -> can access admin only
Currently I have authenticated by calling below method from application_controller.rb
def authenticate_user_or_admin!
unless user_signed_in? or admin_signed_in?
redirect_to root_url , :flash => {:alert => "You need to sign in as admin/user before continuing..".html_safe }
end
end
in carts_controler.rb
class CartsControler < ApplicationController
before_filter :authenticate_user_or_admin!, :only => [:index, :show]
before_filter: :authenticate_admin!, :except => [:index, :show]
Is devise providing any default options to authenticate multiple devise models?
Is this proper ways to solve this problem? or any other better solution?

Devise after login redirect - double render error

I'm working with rails 3.2 and Devise (the lastest version)
The main idea if the test some variables of the current logged user after sign in. So, for example, if the user has pending creating an address i want to redirect the new address path. But what i get is a double render error.
Here is the code
class ApplicationController < ActionController::Base
protect_from_forgery
# Devise: Where to redirect users once they have logged in
def after_sign_in_path_for(resource)
if current_user.is? :company_owner
if $redis.hget(USER_COMPANY_KEY, current_user.id).nil?
redirect_to new_owner_company_path and return
else
#addr_pending = $redis.hget(PENDING_ADDRESS_KEY,current_user.id)
unless #addr_pending.nil? || !#addr_pending
redirect_to owner_company_addresses_path and return
end
end
end
root_path
end
end
my routes definition
root :to => "home#index"
devise_for :users, :controllers => {
:omniauth_callbacks => "users/omniauth_callbacks"
}
resources :users, :only => :show
namespace :owner do
resource :company do # single resource /owner/company
get 'thanks'
get 'owner' #TODO: esto hay que sacarlo de aquĆ­ y forme parte del login
resources :addresses
end
end
So, when i login with a user with a pedding address creation i get
"render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".
what is wrong with?
redirect_to owner_company_addresses_path and return
So, i just want to redirect to the new address path. I don't understand why i get the error.
Thanks in advance.
---- edit ----
Seems that only one path must be returned (I thought with redirect_to and return was enough, but it does not)
def after_sign_in_path_for(resource)
#final_url = root_path
if current_user.is? :company_owner
if $redis.hget(USER_COMPANY_KEY, current_user.id).nil?
#final_url = new_owner_company_path
else
#addr_pending = $redis.hget(PENDING_ADDRESS_KEY,current_user.id)
unless #addr_pending.nil? || !#addr_pending
#final_url = owner_company_addresses_path
end
end
end
#final_url
end
You should remove redirect_to method call and return statement. after_sign_in_path_for should return only a path:
E.g:
def after_sign_in_path_for(resource)
new_owner_company_path
end

Call back to Application Controller error - NameError (undefined local variable or method

I'm upgrading an application from Rails 2 to 3. I use a Rights and Role approach for authentication that worked fine under Rails 2. In my Application Controller (application.rb) I have:
class ApplicationController < ActionController::Base
def check_authentication
unless session[:user]
session[:intended_resource] = request.request_uri
session[:intended_action] = action_name
session[:intended_controller] = controller_name
redirect_to :controller => "sessions", :action => "new"
return false
end
end
def check_authorization
user = User.find(session[:user])
unless user.roles.detect{|role|
role.rights.detect{|right|
right.action == action_name && right.controller == self.class.controller_path
}
}
flash[:notice] = "You are not authorized to view the page you requested"
request.env["HTTP_REFERER"] ? (redirect_to :back) : (redirect_to :controller => "sessions", :action => "new")
return false
end
end
end
In my other controllers I've included a before filter.
before_filter :check_authentication,:check_authorization
I'm getting the following error message, for example, when I go to my Dashboard Controller.
NameError (undefined local variable or method `check_authentication' for DashboardController:0x0000010291a0c0):
Is there something else I need to change or add to make this work in Rails 3?
Thanks,
Aaron
Make sure that your DashboardController is inheriting from ApplicationController i.e. DashboardController < ApplicationController.
Problem solved. Somehow during my upgrade I had a file named application.rb and application_controller.rb in my controllers folder. Both were defined as ApplicationController < ActionController::Base. The code for my "real" Application Controller was sitting in application.rb and not in application_controller.rb, which was empty. A simple copy-n-paste and things were fine. I don't know how that happened. Running the rails_upgrade plugin didn't go as smoothly as planned.