I have the standard current_user methods in my application_controller.
def current_user_session
return #current_user_session if defined?
(#current_user_session)
#current_user_session = UserSession.find
end
def current_user
return #current_user if defined?(#current_user)
#current_user = current_user_session &&
current_user_session.record
end
In my UserSessionController create method, I checked for
registration_complete? (simply a check on a value of a column, which
works fine) and then redirect the user to the user edit page if the
registration is not complete. When I debug this, I can see that the
attempted_record for the #user_session object exists and it's pointing
to the correct user, but the current_user method in
the redirect_to edit_user_path(current_user),
always returns nil.
What's going wrong here?
def create
#user_session = UserSession.new(params[:user_session])
# uses a block to prevent double render error...
# because oauth and openid use redirects
#user_session.save do |result|
if result
flash[:notice] = "Login successful!"
if #user_session.new_registration?
logger.info "Session controller : new
registration"
logger.info "Complete -
#{#user_session.registration_complete?}"
flash[:notice] = "Please review profile"
redirect_to edit_user_path(current_user)
else
if #user_session.registration_complete?
logger.info "Session Controller - registration
complete"
else
flash[:notice] = "Please complete profile"
logger.info "Session Controller - registration
not complete"
redirect_to edit_user_path(current_user)
#current_user nil here
end
end
redirect_to current_user ? profile_url(current_user) :
login_url
else
if #user_session.errors.on(:user)
# if we set error on the base object, likely it's
because we didn't find a user
render :action => :confirm
else
render :action => :new
end
end
end
end
I have seen this and used that very same authentication system on one of my applications. You don't mention it and that's why I'm proposing this to you if you do have then I'd need to see more of your application_controller, so anyway try and add this before the methods.
helper_method :current_user
I just had a duh moment, try doing this instead of passing a block to the save method.
if #user_session.save
# rest of your logic here
end
"if result" might not do what you expect it to do.
Else inspect this #user_session.record instead of current_user, if it's still nul your problem is not current_user.
I need to get home, I'll check back later tonight.
I had similar issue with authlogic and rails 3, and the problem that i figured out was
the apache http authentication that was enabled in my production server,
here is the solution to get that fixed, check Rails + Authlogic #current_user problem - "Show" method no longer works
Try to use this to rails2:
class ApplicationController < ActionController::Base
helper :all # include all helpers, all the time
protect_from_forgery # See ActionController::RequestForgeryProtection for details
#Authlogic
filter_parameter_logging :password
helper_method :current_user
private
def current_user_session
return #current_user_session if defined?(#current_user_session)
#current_user_session = UserSession.find
end
def current_user
return #current_user if defined?(#current_user)
#current_user = current_user_session && current_user_session.record
end
end
and this to rails3:
class ApplicationController < ActionController::Base
helper :all # include all helpers, all the time
protect_from_forgery # See ActionController::RequestForgeryProtection for details
helper_method :current_user
private
def current_user_session
return #current_user_session if defined?(#current_user_session)
#current_user_session = UserSession.find
end
def current_user
return #current_user if defined?(#current_user)
#current_user = current_user_session && current_user_session.record
end
end
/config/application.rb
# Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters += [:password]
Related
I'm new to Rails, and am working on a practice app that involves a simple login function. I've been following a tutorial from CodeAcademy by the books, however the code is not working in quite a few ways. First of all, the sessions do not set, even though Rails is executing the rest of the code inside the "if" block shared with the session declaration (btw, no errors are returned).
The session controller:
class SessionsController < ApplicationController
def new
end
def create
#user = User.find_by_username(params[:session][:name])
if #user && #user.authenticate(params[:session][:password])
session[:user_id] = #user.id
redirect_to '/posts'
else
session[:user_id] = nil
flash[:warning] = "Failed login- try again"
redirect_to '/login'
end
end
def destroy
session[:session_id] = nil
redirect_to login_path
end
end
Extrapolating from that issue, my "current_user" function is not working, which is most likely because the session is not being set.
The application controller:
class ApplicationController < ActionController::Base
def current_user
return unless session[:user_id]
#current_user ||= User.find(session[:user_id])
end
def require_user
redirect_to '/login' unless current_user
end
end
Any help is much appreciated. Let me know if you need to see anything else.
NOTE: I know I should use Devise, and I am planning to in my future, more serious projects. However, like I said, this is a practice/test app to help develop my coding skills, and before using a "magical" gem like Devise I want to get hands-on experience with making a login system myself.
I think the error is that session_controller is not able to find the current_user.
Write the following code in application_controller:
class ApplicationController < ActionController::Base
helper_method :current_user
def current_user
return unless session[:user_id]
#current_user ||= User.find(session[:user_id])
end
def require_user
redirect_to '/login' unless current_user
end
end
Letme know if it works
There are a few possible problems.
First, #current_user is not set until the current_user method is called. And as #Neha pointed out, you'll need to add a helper method to your ApplicationController so that all your views will have access to the current_user method. Add this line to your ApplicationController:
helper_method :current_user
Now, to diagnose the problem, let's set something up that lets you get some visibility into your session and current_user.
First, in views/layouts/application.html.erb, just after the line that says <= yield %>, add this:
<%= render 'layouts/footer' %>
Then add a new file views/layouts/_footer.html.erb:
<hr/>
Session:<br/>
<% session.keys.each do |key| %>
<%= "#{key}: #{session[key]}" %><br/>
<% end %>
<br/>
User:<br/>
<%= current_user&.username || '[None]' %>
Now at the bottom of every view you can see the details of your session.
In your sessions#create action, you have a potential problem with finding your User. You are using params[:session][:name] where you probably should be using params[:session][:username].
Also, tangentially, the proper way to destroy a session is not by setting session[:id] to nil, but instead to use reset_session. So your SessionsController should look like this:
class SessionsController < ApplicationController
def new
end
def create
#user = User.find_by_username(params[:session][:username])
if #user && #user.authenticate(params[:session][:password])
session[:user_id] = #user.id
redirect_to '/posts'
else
session[:user_id] = nil
flash[:warning] = "Failed login- try again"
redirect_to '/login'
end
end
def destroy
reset_session
redirect_to login_path
end
end
I'm getting the following error after upgrading from 'rails', '2.3.15' to 'rails', '3.2.17'
Processing by HomeController#index as HTML
Completed 500 Internal Server Error in 320.9ms
SystemStackError (stack level too deep):
.bundle/ruby/1.9.1/gems/actionpack-3.2.17/lib/action_dispatch/middleware/reloader.rb:70
I know the error is somewhere in following method:
def current_user
return #current_user if defined?(#current_user)
#current_user = current_user_session && current_user_session.record
Authorization.current_user = #current_user
end
Would be awesome if someone that has implemented authlogic with rails 3 can give me some hints.
Thanks a lot!
Here is my full application controller:
class ApplicationController < ActionController::Base
helper :all # include all helpers, all the time
helper_method :current_user_session, :current_user
helper_method :current_user
helper_method :current_division
rescue_from Authorization::AttributeAuthorizationError, :with => :rescue_auth_error
protect_from_forgery # See ActionController::RequestForgeryProtection for details
# Scrub sensitive parameters from your log
around_filter :clear_current_user
before_filter :require_user
before_filter :configure_mailers
private
def rescue_auth_error(exception)
if current_user.present?
UserSession.find(current_user.id).destroy
flash[:error] = "Your session has expired. Please log in again."
redirect_to root_url
end
end
def clear_current_user
remove_instance_variable :#current_user if defined?(#current_user)
remove_instance_variable :#current_user_session if defined?(#current_user_session)
yield
remove_instance_variable :#current_user if defined?(#current_user)
remove_instance_variable :#current_user_session if defined?(#current_user_session)
Authorization.current_user = nil
end
def current_user_session
return #current_user_session if defined?(#current_user_session) && !#current_user_session.nil?
#current_user_session = UserSession.find
# #current_user_session = current_division.user_sessions.find
end
def current_user
return #current_user if defined?(#current_user)
#current_user = current_user_session && current_user_session.record
Authorization.current_user = #current_user
end
def require_user
unless current_user
store_location
# flash[:notice] = "You must be logged in to access this page"
redirect_to new_user_session_url
return false
end
end
def require_no_user
if current_user
store_location
# flash[:notice] = "You must be logged out to access this page"
redirect_to account_url
return false
end
end
def store_location
session[:return_to] = request.request_uri
end
def redirect_back_or_default(default)
redirect_to(session[:return_to] || default)
session[:return_to] = nil
end
def current_division
#current_division ||= Division.find_by_code('prd')
end
def configure_mailers
Notifier.configure(request)
end
def permission_denied
flash[:error] = "You do not have permission to access that page."
redirect_to root_url
end
end
This gem was causing the error:
gem 'rd_searchlogic', :require => 'searchlogic', :git => 'git://github.com/railsdog/searchlogic.git'
Replaced with:
gem 'ransack'
All is good now.
So I am building an application that I am trying to never need a database as the application will just be a portal to an API. I have a sessions controller and I am trying to use a cookie based session but the setter method is never being hit. Here is what I have at this point.
sessions_controller.rb
class SessionsController < ApplicationController
def new
if current_user
redirect_to snapshots_path
end
end
def create
api = API.new
response = api.authenticate_user(params[:session][:username].downcase, params[:session][:password])
if response["Message"] == "success"
current_user = response["User"]
binding.pry
redirect_to snapshots_path, notice: "Signed in successfully."
else
flash.now[:error] = "Invalid username/password combination."
render :new
end
end
def destroy
current_user = nil
redirect_to sign_in_path
end
end
sessions_helper.rb
module SessionsHelper
def current_user=(user)
binding.pry
if user
#current_user = user
cookies[:userdata] = { :value => user, :expires => 8.hours.from_now.utc }
else
#current_user = nil
cookies.delete(:userdata)
end
end
def current_user
binding.pry
#current_user ||= (cookies[:userdata] ? cookies[:userdata] : nil)
end
end
The getter method is hit correctly every time but the setter is never getting hit. Any ideas as how to fix this thanks.
When you are assigning to current_user it's treating it as a local variable. To solve that simply assign to self.current_user instead. The getter doesn't need that because there is no local variable named that so ruby looks for a method and uses that. If you reference the getter as self.current_user that would also work.
For example change:
current_user = response["User"]
to:
self.current_user = response["User"]
Include SessionsHelper in your SessionsController in order to access SessionHelper methods within SessionsController.
Code will work fine without any modification i.e., you would be able to access current_user and current_user= directly.
class SessionsController < ApplicationController
include SessionsHelper ## Just add this
..
end
I have 2 models, users and common_app.
Users has_one common_app.
In the common_app controller, I define almost everything using the current_user helper. This essentially makes it so that the edit forms ignore the id that the user POSTs via the web browser.
It looks like so -->
class CommonAppsController < ApplicationController
before_action :signed_in_user
def new
if current_user.common_app.present?
redirect_to current_user
else
#common_app = current_user.build_common_app
end
end
def create
#common_app = current_user.build_common_app(common_app_params)
if #common_app.save
flash[:success] = "Common App Created!"
redirect_to root_url
else
redirect_to 'common_apps/new'
end
end
def update
if current_user.common_app.update_attributes(common_app_params)
flash[:success] = "Common App Updated"
redirect_to root_url
else
render 'common_apps/edit'
end
end
def show
#common_app = current_user.common_app
end
def edit
#common_app = current_user.common_app
end
private
def common_app_params
params.require(:common_app).permit(:current_city,:grad_year,:read_type,
:listen_speak,:time_in_china,
:cover_letter,:resume) ####fill in the correct ones here
end
# is correct_user necessary?
end
What makes me wary though is that I am not using a correct_user before action. If I were to not use it, would there be a security hole here? I.e could someone POST through a shell or something?
If yes, how would you change the controller, to include the before filter?
PS: I'm also a bit confused about the correct use of # variables. If I am overusing them, or doing something wacky with them, please let me know and help me become a better noob :)
PPS: This is my SessionsHelper Module, for the signed_in_user before filter to work -- >
module SessionsHelper
def sign_in(user)
remember_token = User.new_remember_token
cookies.permanent[:remember_token] = remember_token
user.update_attribute(:remember_token, User.encrypt(remember_token))
self.current_user = user
end
def signed_in?
!current_user.nil?
end
def current_user=(user)
#current_user = user
end
def current_user
remember_token = User.encrypt(cookies[:remember_token])
#current_user ||= User.find_by(remember_token: remember_token)
end
def current_user?(user)
user == current_user
end
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
def redirect_back_or(default) # this creates friendly forwarding for the app
redirect_to(session[:return_to] || default)
session.delete(:return_to)
end
def store_location
session[:return_to] = request.url if request.get?
end
def signed_in_user
unless signed_in?
store_location
redirect_to signin_url, notice: "Please sign in."
end
end
end
I don't see any security problem here. Even without the before_action :signed_in_user, since you always go through the current_user.common_app association, if a user where not signed in, the action would simply fail.
So the controller is sound. As long as your authentication system has no flaws, the controller itself exposes no weakness.
In Ruby, variables prefixed with '#' are instance variables. In the context of a Rails controller, the distinction is simple:
Use instance variables for values you want to make available to your view, and normal variables for everything else.
I am working on a basic authentication system for a rails app. The authentication is verifying account information from Active Directory using a net-ldap class (this part is working fine).
Something seems to be wrong with my session_helper however. Even though ActiveDirectoryUser.authenticate is successful, the signed_in helper always returns false. After signing in, the script redirects to root_path (default_controller's home) and then immediately redirects back to signin_path again-- as a result of the signed_in helper returning false.
See the code below. What am I missing?
Thanks
application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
include SessionsHelper
end
default_controller.rb
class DefaultController < ApplicationController
before_filter :signed_in_user
def home
end
private
def signed_in_user
redirect_to signin_path, notice: "Please sign in." unless signed_in?
end
end
sessions_helper.rb
module SessionsHelper
def sign_in(user)
#current_user = user
end
def current_user
#current_user ||= nil
end
def signed_in?
!#current_user.nil?
end
def sign_out
#current_user = nil
end
end
sessions_controller.rb
class SessionsController < ApplicationController
def new
end
def create
user = ActiveDirectoryUser.authenticate(params[:session][:username],params[:session][:password])
if user.nil?
# authentication failed
flash.now[:error] = 'Invalid email/password combination'
render 'new'
else
# authentication succeeded
sign_in #user
flash[:error] = 'Great success'
redirect_to root_path
end
end
def destroy
sign_out
redirect_to root_path
end
end
You should use session for to persist that kind of data (will be assessable for every request), it's user data. But I highly recommend you to use something like the devise gem that do all that authentication things and more for you. Why reinvent the weel right?
I believe this would work for you.
module SessionsHelper
def sign_in(user)
session[:user_id] = user.id
end
def current_user
ActiveDirectoryUser.find(session[:user_id]) ||= nil
end
def signed_in?
!session[:user_id].nil?
end
def sign_out
session[:user_id] = nil
end
end