Devise is logging out users after a password change - ruby-on-rails

I am using devise and when a user changes a password the site logs them out. I read online that adding the sign_in will do the trick but not working and the user gets logged out when a password change. Here is my code
if #user.errors[:base].empty? and #user.update_attributes(params[:user])
sign_in(current_user, :bypass => true)
flash[:success] = "User account has been successfully updated"
redirect_to edit_user_path(params[:site_id], #user)
else
render :action => :edit, :status => :unprocessable_entity
end
I was assuming that this would work but regardless of what i do i still get logged out....anything missing or maybe one devise setting is off...any help would be appreciated

I usually folow these instructions and it works. Maybe you should do
sign_in(#user, :bypass => true)
instead of
sign_in(current_user, :bypass => true)

Related

Changing user password in devise

I'm trying to change a users password and it successfully changes but it doesn't let me do anything afterwards because the user becomes unauthorized... I'm probably missing a piece that reauthenticates them.
This is my code to update their password
def password
if current_user.valid_password?(params[:current_password])
current_user.password = params[:new_password]
if current_user.save
#sign them in
#tried doing this to sign them in again but didn't work
sign_in(:user, current_user)
response.headers['X-CSRF-Token'] = form_authenticity_token
response.headers['X-Pyne-Auth'] = current_user.authentication_token
render :json => {:success => true} and return
else
render :json => {:success => false, error: "Unexpected error while trying to save user. Please try again."} and return
end
else
render :json => {:success => false, error: "Your current password is incorrect. Please try again"} and return
end
end
I can update the password but have trouble accessing the app again because the user becomes unauthorized.
Thank you
Try bypass_sign_in(#user) as suggested in the Devise wiki.

Using same email adress to login Rails app through Oauth and Sorcery

I use Sorcery gem in my Rails app. Oauth authentication is working on Google and Github services. But if user has same emails to login to Google and Github, my application ignores other attempt to login, because the used email already stored in database.
So, I need multiple login in my app through Oauth, even if emails in different services is equal. What should I do?
You can do it like this:
put it in ./app/controller/oauths_controller.rb
def callback
provider = auth_params[:provider]
if #user = login_from(provider)
redirect_to root_path, :notice => "Logged in from #{provider.titleize}!"
else
begin
#user = create_from(provider)
reset_session # protect from session fixation attack
auto_login(#user)
redirect_to root_path, :notice => "Logged in from #{provider.titleize}!"
rescue
provider_hash = sorcery_fetch_user_hash(provider)
user_email = provider_hash[:user_info]['email']
#user = User.find_by_email(user_email)
#user.authentications.create!(:provider => provider, :uid => provider_hash[:uid])
reset_session
auto_login(#user)
redirect_to root_path, :notice => "Logged in from #{provider.titleize}!"
rescue
redirect_to root_path, :alert => "Failed to login from #{provider.titleize}!"
end
end
end

rails gives wrong session cookie to user

We are using omniauth with facebook login in a Rails 3.2.13 app. It has pretty standard boilerplate code in the sessions_controller to manage user sessions. It uses the CookieStore for sessions. Here is the sessions_controller:
class SessionsController < ApplicationController
skip_authorization_check
def new
redirect_to '/auth/facebook'
end
def create
auth = request.env["omniauth.auth"]
user = User.where(:provider => auth['provider'],
:uid => auth['uid'].to_s).first || User.create_with_omniauth(auth)
# Reset the session after successful login, per
# 2.8 Session Fixation – Countermeasures:
# http://guides.rubyonrails.org/security.html#session-fixation-countermeasures
reset_session
session[:user_id] = user.id
user.add_role :admin if User.count == 1 # make the first user an admin
if user.email.blank?
redirect_to edit_user_path(user), :alert => "Please enter your email address."
else
redirect_to root_url, :notice => 'Signed in!'
end
end
def destroy
reset_session
redirect_to root_url, :notice => 'Signed out!'
end
def failure
redirect_to root_url, :alert => "Authentication error: #{params[:message].humanize}"
end
end
The other day a member of our team was testing our production version and went to go sign in to the app. When she browsed to the app she found she was already signed in as another user who had never used that computer or in fact ever been in our building. Based on what she experienced and our subsequent analysis it seems that she was given a session cookie for that user by the app. After much research I don't understand how that could happen i.e. the rack/rails framework could give a session cookie to the wrong user. Has anyone seen this before or heard of it happening? Any suggestions on how to debug this or where to put logging to get more insight into what could be going wrong?

How to separate change password from devise form

I am trying to do two things:
1) Change the default "edit user form" - provided with devise - to remove "password" and allow the other fields to be updated without having to enter a password ie remove the default validation for password.
2) Create a separate form for changing password
I have got everything to work, there is only one problem, in the separate form for updating password, I have included a field for current password. When using the form, no validation is made for current password, so I changed
#user.update_attributes(params[:user])
to
#user.update_with_password(params[:user])
This worked, however it raised another issue. Back in the main form with all the other details except password, the form now asks for a "current password". How can I achieve this without a validation for current password being called on the main form?
here is my registrations controller:
def update
#user = User.find(current_user.id)
if #user.update_attributes(params[:user])
set_flash_message :notice, :updated
# Sign in the user bypassing validation in case his password changed
sign_in #user, :bypass => true
redirect_to after_update_path_for(#user)
else
clean_up_passwords(resource)
respond_with_navigational(resource) do
if params[:change_password] # or flash[:change_password]
render :change_password
else
render :edit
end
end
end
end
Thanks!
Solution 1
I have found a solution to the problem (albeit a very messy one):
def update
#user = User.find(current_user.id)
if params[:user][:password].blank?
if #user.update_attributes(params[:user])
set_flash_message :notice, :updated
# Sign in the user bypassing validation in case his password changed
sign_in #user, :bypass => true
redirect_to after_update_path_for(#user)
else
respond_with_navigational(resource) do
render :edit
end
end
else
if #user.update_with_password(params[:user])
set_flash_message :notice, :updated
# Sign in the user bypassing validation in case his password changed
sign_in #user, :bypass => true
redirect_to after_update_path_for(#user)
else
clean_up_passwords(resource)
respond_with_navigational(resource) do
render :change_password
end
end
end
Solution 2
Can you suggest a better solution?
Did you bother to check out Devise wiki? There are examples for both this cases
https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-account-without-providing-a-password
https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-password
You should be looking at #user.update_with_password(params[:user]) vs #user.update_attributes(params[:user])
The accepted answer does not fully address the question. Which, I believe is to have a separate form for user profile attributes (like email, first name, etc) vs. the password. Here's what you need to do for that:
First, leverage the Devise::RegistrationsController for your profile updates.
Customize the view and remove the password and password_confirmation fields. Devise ignores these if they are not present in the put.
If you don't want to require the current password to make profile changes, read this. Not recommended; not secure.
Second, create your own controller to manage the password updates and your own helper to require current_password, password, and password_confirmation on update.
class PasswordsController < ApplicationController
before_filter :authenticate_user!
def edit
#user = current_user
end
def update
#user = User.find(current_user.id)
if #user.update_password_with_password(user_params)
# Sign in the user by passing validation in case their password changed
sign_in #user, :bypass => true
redirect_to edit_password_path, flash: { success: "Successfully updated password" }
else
render "edit"
end
end
private
def user_params
params.require(:user).permit(:current_password, :password, :password_confirmation)
end
end
Here's the helper, update_password_with_password that will require the new password fields.
class User < ActiveRecord::Base
def update_password_with_password(params, *options)
current_password = params.delete(:current_password)
result = if valid_password?(current_password)
update_attributes(params, *options)
else
self.assign_attributes(params, *options)
self.valid?
self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
false
end
clean_up_passwords
result
end
end

How to authenticate users in Authlogic with usernames that are unique to an account only

For the life of me, I can't get this to work. I have an application where each account has a unique subdomain. Within that account, users have a unique username but the username may not be unique across the application as a whole.
def create
#user_session = #current_account.user_sessions.new(params[:user_session])
#user = #current_account.users.find_by_username_or_email(params[:user_session][:username])
if #user_session.save
flash[:notice] = "Welcome back #{current_user.first_name}"
if #user_session.user.account.is_new? && !#current_account.stop_wizard?
redirect_to :controller => "site", :action => "welcome", :id => "one"
else
redirect_to dashboard_url
end
else
render :action => :new
end
end
This seems to fail on the if #user_session.save line because it validates against the first instance of the username within the database and not against the username that is scoped to the current account.
Any advice would be appreciated.
Thanks
Robin
The with scope option when creating my session was the answer.

Resources