NoMethodError - undefined method `user' for nil:NilClass - ruby-on-rails

I'm using Omniauth to try to signup/login users on my web app.
This is happening inside my AuthenticationsController#Create method:
Authentications Controller:
class AuthenticationsController < InheritedResources::Base
def create
omniauth = request.env['omniauth.auth']
authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
if authentication
flash[:success] = "Signed in successfully"
sign_in_and_redirect(authentication.user)
elsif current_user
token = omniauth['credentials'].token
secret = omniauth['credentials'].secret
current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid'], :token => token, :secret => token_secret)
flash[:success] = "Authentication successful"
redirect_to authentications_url
else
user = User.new
user.apply_omniauth(omniauth)
if user.save!
flash[:success] = "Account created"
sign_in(authentication.user)
else
session[:omniauth] = omniauth.except('extra')
redirect_to '/signup'
end
end
end
I originally had sign_in(:user, authentication.user) but it gave me argument errors, so I changed it to just had sign_in(authentication.user) in the above code. However, now I'm getting a NoMethodError - undefined method 'user' for nil:NilClass.

Line 23 sign_in(authentication.user) is failing because you are in the else branch of if authentication condition (so authentication is nil).
What you probably meant to do is call sign_in(user) for user you just created a few lines above.

First you test if authentication is defined, and then in the else block, which will only trigger if it is not defined, you go and reference authentication.user for some reason. This could not possibly work.
That condition seems to apply if you haven't authenticated, and aren't logged in. Why would you be engaging the sign_in function under those circumstances?

If your using a set list of providers in your db make sure
> :provider => omniauth['provider']
Matches up with the provider in the db, for instance. If you have facebook_Oauth2 in your db and the provider response is facebook authenthication will fail.

Related

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?

Devise and Omniauth

I'm trying to integrate Devise with Omniauth and have some troubles with them both. The main problem is to bind Devise User model with Omniauth authentications. I want a simple way to associate my user, with external providers like facebook, twitter, g+ and so on.
One of the most annoying issues that arise with my application is:
If an user registered on my site with devise (I call it local user), that means, provided an email and a password, when user tries to login with twitter, the system asks for mail confirmation. If that mail already exists, then user have to provide another mail. I want instead that he can confirm with a password that it is actually his email. How to do that? How can I override that template?
This is my authentications controller:
class AuthenticationsController < ApplicationController
def index
#authentications = Authentication.all
end
def create
#authentication = Authentication.new(params[:authentication])
if #authentication.save
redirect_to authentications_url, :notice => "Successfully created authentication."
else
render :action => 'new'
end
end
def destroy
#authentication = Authentication.find(params[:id])
#authentication.destroy
redirect_to authentications_url, :notice => "Successfully destroyed authentication."
end
def twitter
omni = request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omni['provider'], omni['uid'])
if authentication
flash[:notice] = "Logged in Successfully"
sign_in_and_redirect User.find(authentication.user_id)
elsif current_user
token = omni['credentials'].token
token_secret = omni['credentials'].secret
current_user.authentications.create!(:provider => omni['provider'], :uid => omni['uid'], :token => token, :token_secret => token_secret)
flash[:notice] = "Authentication successful."
sign_in_and_redirect current_user
else
user = User.new
user.apply_omniauth(omni)
if user.save
flash[:notice] = "Logged in."
sign_in_and_redirect User.find(user.id)
else
session[:omniauth] = omni.except('extra')
p session
redirect_to new_user_registration_path
end
end
end
end
I also have no idea where new_users_registration_path is.

email access using facebook authentication rails

I am unable to access the user email through facebook authentication.
my code in authentication controller
def facebook
omni= request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omni['provider'],omni['uid'])
if authentication
flash[:notice]="Logged in successfully"
sign_in_and_redirect User.find(authentication.user_id)
elsif current_user
token=omni['credentials'].token
token_secret=omni['credentials'].secret
current_user.authentications.create!(:provider=>omni['provider'],:uid=>omni['uid'],:token=>token,:token_secret=>token_secret)
flash[:notice]="Authentication successful."
sign_in_and_redirect current_user
else
user=User.new
# user.email=omni['extra']['raw_info'].email
user.apply_omniauth(omni)
if user.save
flash[:notice]="Logged in."
sign_in_and_redirect User.find(user.id)
else
session[:omniauth]=omni.except('extra')
redirect_to new_user_registration_path
end
end
end
devise.rb
config.omniauth :facebook, 'xxxxxxxxxxxxxxx851','xxxxxxxxxxxxxxxxxxd47aae3', {:scope => ' email,publish_stream,offline_access' ,:display => 'popup'}
in user model
def apply_omniauth(omni)
authentications.build(:provider => omni['provider'],
:uid=>omni['uid'],
:token=>omni['credentials'].token,
:token_secret=>omni['credentials'].secret,
)
x=omni["info"]["name"].split # split the full name into first and last name
self.first_name=x[0]
self.last_name=x[1]
self.profile_name=omni['info']['nickname']
end
Is their something in the code?
Last, I remember, email can be found at omni.info.email.
Also, I advice you to use . notation here, instead of hash.

Omniauth Google Outh 2 Keeps Redirecting To Google?

I have Google Omniauth 2 correctly authorizing, pulling the email, creating the users and logging in.
However, each time I log out and click my "Log In With Google" link - it directs me to the Google Allow Access page and makes me approve it again and then logs me in.
Is this just how google operates? Is there a way to pass a scope to make it not ask each time?
Here is my omniauth initializer
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, '####', '####', :scope => 'email,offline_access', :display => 'popup'
provider :google_oauth2, '####.apps.googleusercontent.com', '#####', { }
end
Here is my sessions controller:
class SessionsController < ApplicationController
def create
auth = request.env["omniauth.auth"]
user = User.find_by_provider_and_uid(auth["provider"], auth["uid"]) || User.create_with_omniauth(auth)
session[:user_id] = user.id
#redirect_to root_url, :notice => "Signed in!"
redirect_back_or user
end
def destroy
session[:user_id] = nil
redirect_to root_url, :notice => "Signed out!"
end
end

Devise Omniauth "encrypted_password may not be NULL" for new user

I am using Devise with Omniauth to have users sign into my app with Facebook. I used the Railscast tutorials to get it up and running.
If a user is already a member of my site authenticating through facebook works fine. The problem comes in when authenticating a new user with facebook. When it goes to create a new user for my User model I get the "users.encrypted_password may not be NULL" error. I can't figure out how to pass over the password to the User model from Facebook information.
This is what I have:
authentations_controller.rb
class AuthenticationsController < ApplicationController
def index
#authentications = current_user.authentications if current_user
end
def create
omniauth = request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
if authentication
flash[:notice] = "Signed in successfully."
sign_in_and_redirect(:user, authentication.user)
elsif current_user
current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid'])
flash[:notice] = "Authentication successful."
redirect_to authentications_url
else
user = User.new
user.apply_omniauth(omniauth)
if user.save
flash[:notice] = "Signed in successfully."
sign_in_and_redirect(:user, user)
else
session[:omniauth] = omniauth.except('extra')
redirect_to new_user_registration_url
end
end
end
user.rb
def apply_omniauth(omniauth)
self.email = omniauth['user_info']['email'] if email.blank?
authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid'])
end
def password_required?
(authentications.empty? || !password.blank?) && super
end
Any help would be great, thanks in advance!
Add :password => Devise.friendly_token[0,20] when creating a new user from facebook omniauth.
I believe Devise is expecting something in the password field to create a User. Since there is no password when doing facebook oauth (not on your app side at least), you just need to create a dummy password as show above.
See this for more info:
https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview

Resources