clearing session after destroy a user - ruby-on-rails

I'm working with an admin user in Chrome and a regular user in another browser. After I as admin destroy one of the regular users, I tried to reopen the application in the browser the destroyed user was using. However, I got this error message
Couldn't find Twitteruser with id=2
So the session's living on in the browser after the user's destroyed
The session's created like this
def create
twitteruser = Twitteruser.from_omniauth(env["omniauth.auth"])
session[:twitteruser_id] = twitteruser.id
redirect_to twitterquestions_url, notice: "Signed in!"
end
In the application_controller, it current user's created like this
def current_user
#current_user ||= Twitteruser.find(session[:twitteruser_id]) if session[:twitteruser_id]
end
This is the destroy action
def destroy
Twitteruser.find(params[:id]).destroy
flash[:success] = "User destroyed."
redirect_to users_url
end
Based on other SO answers I found, I tried to reset the session two different ways, but they both reset the session of the admin user, not the user who was destroyed
def destroy
Twitteruser.find(params[:id]).destroy
#1. session[:twitteruser_id] = nil destroys my own session, not deleted users
#2. reset_session #reset admin's session
flash[:success] = "User destroyed."
redirect_to twitterusers_url
end
I also tried to pass an argument to reset_session but it doesn't accept them.
Can anyone tell me how to clear the destroyed user's session? Thanks

It depends on what your using for backing your sessions. If the session is in the Cookie then there's nothing your Admin can do with it as there's nothing server side to work with. Irregardless, messing with someone else's session may not be possible as you won't know the session ID.
What you want to do is either catch the ActiveRecord::RecordNotFound that is thrown by find or use find_by_id which will return nil. When the user tries to access the site with the session referencing a deleted user, you can then kill the session.
def current_user
#current_user ||= Twitteruser.find(session[:twitteruser_id]) if session[:twitteruser_id]
rescue ActiveRecord::RecordNotFound
session[:twitteruser_id] = nil # or reset_session
end
or
def current_user
#current_user ||= fetch_user(session[:twitteruser_id])
end
def fetch_user(id)
Twitteruser.find_by_id(id) || reset_session unless id.nil?
end
This will work regardless of how a Twitteruser gets deleted. For example, imagine if you deleted the user from the rails console where there is no session.

Related

Rescue exception thrown by a redirect_to :back

Little background information: I have a project with authenticated users which can have multiple 'scopes' of data. A scope determines which records can and can't be accessed by a user. A logged in user is always subsribed to a single scope stored in the session.
A user can at any time switch between the scopes he has access to, regardless of which page he is on.
After a scope switch I would like to try to reload the same page by using redirect_to :back. This is not always possible, since the current scope might not allow access to the page that was previously being viewed.
In those cases, the controller in question will throw an ActiveRecord::RecordNotFound exception in the respective controller on the .find(params[:id]) call, which is very ugly. I would very much like to gracefully fallback to a redirect_to :root with an accompanying alert message.
Currently I have this, but this does not work:
def switch_scope
s = current_client.scopes.find(params[:scope_id])
set_scope(s.id)
begin
flash[:notice] = 'Scope switched succesfully.'
redirect_to :back # <= This might throw NotFoundException
rescue
flash[:alert] = 'Scope switched. Page could not be reloaded'
redirect_to :root
end
end
EDIT
For example, the redirect_to :back might go back to this show Product function:
def show
#product = Product.where(scope_id: session[:scope_id]).find(params[:id])
end
As you can see, it first filters all propducts based on the selected scope in the session. Then it does a find(ID) on that subset. It is very possible that after a scope switch the Product with said ID is no longer accessible, giving a RecordNotFoundException.
Now again, this is an example and many of these constructions exists in my application, so preferably I do not want to edit it on this side manually.
Add This in the application_controller.rb
rescue_from ActiveRecord::RecordNotFound do |exception|
if (params[:controller]=="your_controller_name" && params[:action] == "Your method")
flash[:alert] = "Access denied. You are not authorized to access the requested page."
redirect_to root_path
end
end
OR
def switch_scope
s = current_client.scopes.find(params[:scope_id])
set_scope(s.id)
begin
flash[:notice] = 'Scope switched succesfully.'
redirect_to :back # <= This might throw NotFoundException
rescue ActiveRecord::RecordNotFound => e
flash[:alert] = 'Scope switched. Page could not be reloaded'
redirect_to :root
end
end

Session destroy not working in rails app?

I have used omniauth-salesforce in my sessions controller I have following code, even when I logout the session is still present, I have tried session.clear and reset_session in destroy method but nothing works, sign in works only after clearing browser cache
class SessionsController < ApplicationController
def create
user = User.from_omniauth(env["omniauth.auth"])
session[:user_id] = user.id
redirect_to root_url
end
def destroy
session[:user_id] = nil
redirect_to root_url
end
end
How to delete session on signout?
Session is similar to a normal hash so below thing should work.
session.delete(:user_id)
Use this
session[:user_id] = nil if session[:user_id]

Heroku sign in doesn't persist

So on my local host, the sign in persists and the user is signed in. However, on Heroku, after signing in, it doesn't even recognize that the user is still signed in.
In the heroku logs, it starts
-A get request for log in
-SessionsController renders a new session
-A user is committed
-A POST request to start sessions occurs
-redirect occurs
-user sign in apparently isn't saved
-This seems like an issue with the cookie?
This is my Sessions Controller
class SessionsController < ApplicationController
def new
end
def create
user = User.authenticate(params[:email], params[:password])
if user
session[:user_id] = user.id
sign_in user
redirect_to root_url, :notice => "Logged in!"
else
flash.now.alert = "Invalid email or password"
render "new"
end
end
def destroy
sign_out
redirect_to posts_url, :notice => "Logged out!"
end
end
This is my SessionsHelper
module SessionsHelper
def sign_in(user)
cookies.permanent[:remember_token] = user.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
#current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
def current_user?(user)
user == current_user
end
def is_admin?
signed_in? ? current_user.admin : false
end
def sign_out
current_user.update_attribute(:remember_token,
User.encrypt(User.new_remember_token))
cookies.delete(:remember_token)
self.current_user = nil
end
end
In my user model I do save a remember_token before saving
before_save :create_remember_token
def create_remember_token self.remember_token = User.encrypt(User.new_remember_token)
Any ideas would be much appreciated!
Following your code step by step:
A User is created with no remember token.
The sign_in method is being called. Nil is saved to cookies as User has no remember token yet.
Your current_user method sets #current_user to nil because User.find_by(nil) returns nil, and doesn't raise an exception as User.find(nil) would.
While I'm not 100% sure this is the reason why your code is breaking (as I can't see what callbacks you've written), it certainly makes sense. If in your local environment you create a new user from scratch I assume that it'll break as well. The only place I see you defining a remember token for the user is in the sign_out method - if you were signed in while implementing the feature, signed out to test it, and signed back in, the code would seemingly work.
This issue can be fixed by using a callback to set the remember_token of the User on create via callback, or in the sign_in method.
As a side note, if you're following Hartl's implementation of sessions, I'd definitely revisit that as you made a fairly large error in how you handle the remember tokens. The encrypted token should be stored on your database, and the unencrypted one should be stored on the cookie. Then when using find_by, you should be encrypting that cookie to find the user in the database. As it currently stands you're saving the naked remember token in both the db and cookie, which poses security issues.

cookie persistence with omniauth and linkedin gem

I'm running a rails application that lets users successfully authenticate with LinkedIn and import their LinkedIn profile data. The (big) problem I'm having is that the cookie data associated with one user that signs in first persists even after they sign out, and is pulled in for another separate user after they authenticate through LinkedIn. The first user's data overwrites the second user's data...big problem.
Help is very much appreciated!
Here is my sessions_controller:
class SessionsController < ApplicationController
def new
end
def create
if env['omniauth.auth']
user = User.from_omniauth(env['omniauth.auth'])
session[:user_id] = user.id
redirect_to auth_path
flash[:success] = 'Signed in with LinkedIn.'
else
user = User.find_by_email(params[:session][:email])
if user && user.authenticate(params[:session][:password])
sign_in user
redirect_back_or user
flash[:success] = 'Signed in the old-fashioned way.'
else
flash.now[:error] = 'Invalid email/password combination'
render 'new'
end
end
end
def destroy
cookies.delete(:remember_token)
session[:user_id] = nil
redirect_to root_path
end
end
I was having the exact same issue. Somewhere in your omniauth configurations there should be a path configuration for where the user is redirected to.
Before
https://api.linkedin.com/uas/oauth/authenticate
After - This fixed everything for me and made the controller action always require an authorization when executed so that new users on the same computer would not automatically use last user's LinkedIn cookie.
https://www.linkedin.com/uas/oauth/authorize

rails specify method for redirect_to

During a post for a new model, I am checking for authentication via Authlogic. There is a before_filter on the create request. It is calling require_user. After the user session has been successfully created, the redirect_back_or_default(default) method is called. The problem is, The request needs to be posted to the stored uri. I have tried to store the method and input it into the redirect_to however it isn't working. Any ideas?
# called before successful authentication with before_filter
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 store_location
session[:return_to] = request.request_uri
session[:return_to_method] = request.request_method
end
# called after successful authentication
def redirect_back_or_default(default)
redirect_to((session[:return_to] ? session[:return_to] : default), :method => session[:return_to_method])
session[:return_to] = nil
session[:return_to_method] = nil
end
You can't redirect to a post action, only get actions.
You could store the post object for later processing after authentication, but you really don't want to do that.
Why not simply ask for authentication on the #new method, rather than (or in addition to) the #create? That way the user is authenticated before they fill in the form.

Resources