Integrating ActiveAdmin and adauth - ruby-on-rails-3

I have a running Rails application, using ActiveAdmin and its models to autenticate users. Now I'm interested in moving to an ActiveDirectory authentication, so my users can validate wiht the domain's users.
I've been trying adauth and it looks like a great gem, but I'm a little bit lost when trying to "mix" this gem with my ActiveAdmin authentication. I'm pretty sure I'm not the first one in doing it, so any help would be appreciated.
Thanks!

I finally was able to manage to integrate AD in ActiveAdmin.
Here's what I did, in case someone is interested:
Include gem 'adauth' in your gems
Execute bundle install
Execute rails g adauth:config
Configure the config/initializers/adauth.rb for your AD connection. For example, if your domain is example.com, you must include:
c.domain = "example.com"
c.server = "IP address of your domain controller"
c.base = "dc=example, dc=com"
Execute rails g adauth:sessions
Modify your application_controller.rb. Mine was:
class ApplicationController< ActionController::Base
protect_from_forgery
helper_method :current_user
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def authenticate_user!
if current_user.nil?
redirect_to '/sessions/new', :error => "Invalid Login"
end
end
end
Execute rails g adauth:user_model user install_adauth.
This creates the migration install_adauth, but for some reason it was empty. I had to fill it myself with:
class InstallAdauth < ActiveRecord::Migration
def up
create_table :users do |u|
u.string 'login'
u.text 'group_strings'
u.string 'name'
u.string 'ou_strings'
end
end
def down
drop_table :users
end
end
Execute rake db:migrate
Modify your sessions_controller.rb. Mine was:
class SessionsController < ApplicationController
def new
redirect_to '/admin' if current_user
end
def create
ldap_user = Adauth.authenticate(params[:username], params[:password])
if ldap_user
user = User.return_and_create_with_adauth(ldap_user)
session[:user_id] = user.id
redirect_to '/admin'
else
redirect_to '/sessions/new', :error => "Invalid Login"
end
end
def destroy
session[:user_id] = nil
redirect_to '/sessions/new'
end
end
So far the validation through ActiveAdmin still works. To switch to ActiveDirectory we must change the file initializers/active_admin.rb
# config.authentication_method = :authenticate_admin_user!
config.authentication_method = :authenticate_user!
#config.current_user_method = :current_admin_user
config.current_user_method = :current_user
In my case, I needed to restart Apache too.
If anytime we want to switch back to ActiveAdmin, we just need to undo the last change

Related

Ruby on Rails : Redirect path after sign_up devise

I am using gem devise. And I overrided devise registrations controller and everything went great, but the problem is redirect path after it is saved. What I want to do is after user saved, it redirects to profile_path, but what I have now is user need to sign in before it redirect to profile path. How can I solve that?
Here is my register controller:
class RegistrationsController < Devise::RegistrationsController
def new
super
end
def create
#user= User.new(params[:user])
if #user.save
redirect_to profile_path, notice: 'User was successfully created.'
else
render action: "new"
end
end
def update
super
end
end
And this is my application controller which control the path after sign up and sign in:
class ApplicationController < ActionController::Base
protect_from_forgery
def after_sign_in_path_for(resource)
if request.path !~ /^\/admins\//i
resource.sign_in_count <= 1 ? '/profile' : root_path
end
end
end
Before I override the register controller, redirect after sign up went great. Would be really glad if anyone could help. Thanks.
You have to sign the user in in your create method:
if #user.save
sign_in(resource_name, resource)
current_user = #user # !! now logged in
redirect_to profile_path, notice: 'User was successfully created.'
else
You can look at the original create method in Devise::RegistrationsController to see how this works.

Sign in to Devise using omniauth-facebook

Ryan Bates gives great screencast http://railscasts.com/episodes/360-facebook-authentication how to use "omniauth-facebook" gem. But there is some issues with:
#application_controller.rb
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
It sets #current_user too late for standart Devise auth protection for actions in controllers:
before_filter :authenticate_user!, :except => [:index, :show]
So it redirects to sign in page, even #current_user is aviable in views...
Maybe anyone knows how to fix it?
PS I saw few tricks with redirects handler, but I think there should be better decision...
I have found the simple way to sign in using standart Devise method. Based on this tutorial, just set code in sessions_controller:
#sessions_controller.rb
class SessionsController < ApplicationController
def create
user = User.from_omniauth(env["omniauth.auth"])
sign_in user
redirect_to root_url
end
end
And you can delete this from application controller:
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user

How do I emulate logging in for controller tests?

I have a SearchesController that requires a user to be logged in before it will do its thing.
I'd like to write an rspec helper function login to emulate logging in for controller tests. (NB: I will handle integration / requests specs separately.) My attempts so haven't worked: the logged_in? method in ApplicationController returns false.
The question: how do I write the 'login' helper?
Here's the RSpec controller test:
# file: spec/controllers/searches_controller_spec.rb
require 'spec_helper'
require 'controllers_helper'
describe SearchesController do
include ControllersHelper
describe "GET index" do
it 'without login renders login page' do
get :index
response.should redirect_to(login_path)
end
it 'with login finds searches belonging to user' do
me = FactoryGirl.create(:user)
my_searches = FactoryGirl.create_list(:search, 2, :user => me)
not_me = FactoryGirl.create(:user)
not_my_searches = FactoryGirl.create_list(:search, 2, :user => not_me)
login(me) # want to define this in spec/controllers_helper.rb
get :index
assigns(:searches).should =~ my_searches
end
end
end
Here's the Controller:
# file: app/controllers/searches_controller.rb
class SearchesController < ApplicationController
def index
unless logged_in?
redirect_to login_path, :alert => "You must be logged in to access this page."
else
#searches = Search.where(:user_id => current_user.id)
respond_to do |format|
format.html
format.json { render json: #searches }
end
end
end
end
And here's the ApplicationController code. Note that current_user = x has the effect of logging x in, and it's rather simple: it sets #current_user and session[:user_id].
# file: app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
force_ssl
protected
def current_user
#current_user ||= User.find_by_id(session[:user_id])
end
def current_user=(user)
#current_user = user
session[:user_id] = user && user.id
end
def logged_in?
!!#current_user
end
def require_login
unless logged_in?
redirect_to login_path, :alert => "You must be logged in to access this page."
end
end
helper_method :current_user, :logged_in?, :require_login
end
I may have said this before, but if Stack Overflow gave badges answering one's own questions, I'd have a LOT of badges! :)
Okay, to answer this question you need to look at the documentation for ActionController::TestCase. When you do so, you'll find that it sets up bindings for:
#controller
#request
#response
So for the specific controller given in the OP, writing the login method is trivial:
# file: spec/controllers_helper.rb
module ControllersHelper
def login(user)
#controller.send(:current_user=, user)
end
end
(Did I hear someone say RTFM again? I thought so...)

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

Rails 3 error in Safari only - ActiveRecord::RecordNotFound (Couldn't find User with auth_token = ):

In following Railscast #274 to get reset password working in my Rails 3 app, I am experiencing a weird issue in Safari. If I run my app in Heroku I get the following error when I go to my root:
ActiveRecord::RecordNotFound (Couldn't find User with auth_token = ):
app/controllers/application_controller.rb:39:in `lookup_user'
app/controllers/application_controller.rb:32:in `current_user'
app/controllers/application_controller.rb:54:in `logged_in?'
app/controllers/users_controller.rb:8:in `new'
If use Firefox and Chrome (in incognito mode) it works. In Safari, I found that if I get the error, I can make it go away by navigating to /logout. Then the page renders perfectly.
Here's my route for /logout and root:
match "/logout" => "sessions#destroy", :as => "logout"
root :to => "users#new"
Here's my destroy action in sessions_controller:
def destroy
reset_session
cookies.delete(:auth_token)
redirect_to root_path, :notice => "You successfully logged out"
end
My application_controller:
protected
def current_user
#current_user ||= lookup_user
end
def lookup_user
if session[:user_id]
User.find_by_id(session[:user_id])
elsif cookies[:auth_token]
User.find_by_auth_token!(cookies[:auth_token])
end
end
And lastly, here's my new action in users_controller:
def new
#user = User.new
#user.profile = Profile.new
if logged_in?
redirect_to profile_path(current_user)
end
end
What I've tried:
To alter the new action to delete cookies with the following:
def new
#user = User.new
#user.profile = Profile.new
if logged_in?
redirect_to profile_path(current_user)
elsif
cookies.delete(:auth_token)
end
end
The rake task below, as suggested in the Railscast comments:
namespace :user do
desc "Rebuild Auth-Tokens"
task :rebuild_auth_token => :environment do
User.transaction do
User.all.each { |u|
u.generate_token(:auth_token)
u.save!
}
end
end
end
(I ran this with `heroku run rake user:rebuild_auth_token`)
Neither seems to have worked. Can anyone help me figure this out?
Anytime you regenerate the user :auth_code's you will need to delete your cookies for that domain. In a production, you should not regenerate :auth_codes and you will never have this issue, unless users edit their cookies.
In addition I have posted a response on the railscast.com authentication (revised) solution so Ryan can take a look at it.
Good luck!