Devise: Sign user in if duplicate sign up - ruby-on-rails

I would like to sign a user in if he attempts to sign up a second time ie. email and password in params is exactly the same.
I added this line to my RegistrationsController (if a duplicate email is detected)
resource = warden.authenticate!(auth_options)
however I can get it to successfully authenticate even though the correct email and password is provided in the params. am I missing something?
I'm on Rails 3.2 and Devise 2.2.7

#user = User.find_by_email(email)
if #user and #user.confirmed? and #user.valid_password?(password)
sign_in #user, :bypass => true
end

Related

Rails Devise Send confirmation email after Facebook signup

Problem: How do I send the user an email after they sign up for the first time with Facebook? I'm using device and omniauth.
I have confirmation emails working for regular signup with devise. I need to send an email when the user gets added to my database for the first time after signing in with Facebook. Where in the code is this happening?
I tried adding a line of code sending the email in my omniauth_callbacks_controller.
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
# omniauth_callbacks_controller
def facebook
#user = User.from_omniauth(request.env["omniauth.auth"])
facebook = "www.facebook.com"
if #user.persisted?
print "User persisted"
sign_in #user, :event => :authentication
set_flash_message(:notice,:success,:kind => "Facebook") if is_navigational_format?
# I SENT THE EMAIL HERE
else
session["device.facebook_data"] = request.env["omniauth.auth"]
redirect_to root_path
end
end
However, this just sends the user a confirmation email EVERY time they log in with Facebook, which is not what I want. I want to simply send the email the first time they log in.
The email should be sent in the registrations_controller. However, when users are signing up with Facebook, this controller is never used.
class RegistrationsController < Devise::RegistrationsController
def create
build_resource(sign_up_params)
if resource.save
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_navigational_format?
sign_up(resource_name, resource)
# Tell the UserMailer to send a welcome email after save
UserMailer.welcome_email(current_user).deliver_later
return render :json => {:success => true}
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
expire_session_data_after_sign_in!
return render :json => {:success => true}
end
else
clean_up_passwords resource
invalid_signin_attempt
end
end
Would like to know the right way to send a confirmation to the user after signing up with Facebook.
Problem
It looks like your User.from_omniauth function behaves like a find_or_create call. That means that the controller has no knowledge of whether the user was just created or is being fetched from an existing identity in the database.
If the user is created as part of this from_omniauth call, then you should be able to just rely on the Devise :confirmable module. Otherwise, the user is created before you get back the OAuth credentials, so you need to handle it manually.
The code in the from_omniauth function likely looks something like this:
def self.from_omniauth(token)
user = User.find(token: token)
if user.nil?
user = User.create(token: token, ...)
# ...
end
# ...
end
There might be an intermediary Token, Identity, or other such class, but the logic should be the same.
Fix
There are two easy ways to fix this:
Include a created boolean as part of the from_omniauth return value, which the controller can then use to gate the confirmation email on.
Move the "create" part of the "find or create" logic out into the controller, so that the email can be sent as part of the "create" path.
Aside
Also, I'd suggest using the Devise resource.send_confirmation_instructions function and piggybacking your email off that. That way, all welcome emails share the same code and you're not maintaining a separate module just for Facebook/OAuth login.

Omniauth Callback

Im using devise with my rails 4 app. I authenticate with Facebook, LinkedIn and email.
I've just started to use Figaro and the only change I have made to my code is to swap the password that I use for my email account out of the production.rb into my application.yml file.
Now, when I test the LinkedIn registration link, I get an error saying that something went wrong (after pressing "Register with LinkedIn"). I get the same error when I try to authenticate with the other options.
I have a callback error in my omniauth callback controller for linkedin. The line with the problem is the '#user.send_admin_email' below:
def linkedin
#user = User.find_for_linkedin_oauth(request.env["omniauth.auth"])
if #user.persisted?
#user.send_admin_mail
redirect_to root_path, :event => :authentication
# sign_in_and_redirect #user, :event => :authentication #this will throw if #user is not activated
# set_flash_message(:notice, :success, :kind => "LinkedIn") if is_navigational_format?
else
session["devise.linkedin_data"] = request.env["omniauth.auth"]
redirect_to root_path
end
end
I have a mailer set up which sends me an email to tell me when there is a new registration. It uses the email address for which I moved the password from production.rb to application.yml
Does anyone know how to resolve this error?
Thank you very much
It is possible that the problem is the text-encoding of your application.yml file, especially if your email password has non-standard characters in it. Try firing up the console, and just output your password as it looks with to_s
p ENV['your_figaro_key'].to_s
See if this returns what you would expect
Hmm, it seems a "strong parameter" problem to me. Check your "send_admin_mail" to see if there is a "update_atributes" (or a "save").
My guess is that your user.rb is something like:
class User < ActiveRecord::Base
...
attr_accessor :extras
def self.find_for_linkedin_oauth(access_token, signed_in_resource=nil)
...
user = User.where(...)
...
user.extras = access_token.extras
...
end
def send_admin_mail
...
self.update_attributes(some_attribute: extras["some_attribute"])
...
end
If you are doing this, "save" will try to do an UPDATE with a non-permitted parameter. The correct version must be something this:
self.update_attributes(some_attribute: extras.permit(:some_attribute))
If I'm not wrong, the first implementation worked in the previous versions of strong parameters, but not anymore.

Log in existent user when they try to register - Devise

I'm using Devise
If an existing user enters correct email / password combo on registration, I'm trying to sign him in instead of displaying an error message e.g. 'email is already in use'.
The Registration form has 4 fields:
Firstname
Lastname
Email
Password
How can i lookup if the user exists and then log him in?
Where i am stuck:
# Finding the user and if the entered password is valid
user = User.find_by_email(params[:user][:email])
user.valid_password?(params[:user][:password])
Just use sign_in method in controller.
if user.valid_password?(params[:user][:password])
sign_in(user, :bypass => true)
redirect root_path
else
# do something else.
end

How to do automatic-sign-in for users who register and get transferred to their account subdomain

I'm building a multi-tenant app where accounts are scoped under subdomains. Assuming acme.com is my app and Elmer is my user, when Elmer registers at acme.com he is transferred to elmer.acme.com. I want to sign Elmer in after he registers, but I'm having a hard time. I'm using cookies. Here's my sign in method:
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
current_user = user
end
Here's part of my Users#create method where users get signed in.
if #user.save
sign_in(#user)
redirect_to root_url(subdomain: #user.subdomain)
end
The cookie is getting set when Elmer is still at acme.com. When Elmer is redirected to elmer.acme.com the cookie is not valid.
I can set domain: :all in my session_store, but this breaks a requirement. It would mean Elmer will be signed into elmer.acme.com, buggs.acme.com, and essentially *.acme.com. Elmer's session cookie should only be valid for elmer.acme.com and/or acme.com.
Any idea how to achieve this? I'm running Rails 3.2 with Ruby 1.9.3.
If you were to create/allow a token login for your user, then you could:
Have a token on the user model
Login with that token (either redirect to a specific URL, or add to your authentication system to login when :token is present)
Sample redirect code:
if #user.save
sign_in(#user)
redirect_to root_url(user_id: #user.id, subdomain: #user.subdomain, token: #user.token)
end

Ruby on Rails User Confirmation not updating a parameter

In my application I have a user confirmation process. When a user signs up four things happen:
An account_status_id is set to 1 (unconfirmed)
The user is signed in (now current_user exists)
A new_account_confirmation_token is generated
A confirmation email is sent to the new user with a link that includes the new_account_confirmation_token
I initially tried to handle the confirmation link with this method. It finds the user without issue and the code flows through the update_attributes! method, however it wasn't updating the account_status. From what I can tell it is due to the fact that the current_user object exists, therefore the user Im trying to update is already "in memory". Is that correct?
def new_account_confirmation
#title = "Account Confirmation"
logger.info("User is not logged in")
#user = User.find_by_new_account_confirmation_token(params[:confirm_id])
if #user
#user.update_attributes!(:account_status_id => 2)
else
redirect_to root_path
end
end
My work around is as follows. The code below works but I'd like to know why the code above doesn't work. Why won't it update the account_status?
def new_account_confirmation
#title = "Account Confirmation"
if current_user
logger.info("User is logged in")
current_user.update_attributes!(:account_status_id => 2)
else
logger.info("User is not logged in")
#user = User.find_by_new_account_confirmation_token(params[:confirm_id])
if #user
#user.update_attributes!(:account_status_id => 2)
else
redirect_to root_path
end
end
end
Even if your user is "in memory" as you say, that's no reason for it not to update. I believe your update IS happening but you're just not seeing it because current_user is not in sync with #user.
I don't know how you're verifying that #user is not being updated but if update_attributes! is not throwing an error then it's being saved.

Resources