Authlogic Facebook Connect Snafu - ruby-on-rails

I have an application configured with authlogic and authlogic_facebook_connect, but every time I click to "Connect" button, my UserSession fails validation, saying "You did not provide any details for authentication"
Isn't the authlogic_facebook_connect supposed to bypass login/password authentication? Am I missing some configuration step?
Any help would be appreciated!

Hey, maybe I can help on this one, just had this problem not very long time ago...
Facebook connect is outdated. All the cool kids are now using Facebook Graph with OAuth. Facebook team have even closed the documentation for Facebook Connect.
Anyway, that goes for Authlogic Facebook connect, it simply does not work anymore.
In the end, I kept using Authlogic for normal login and account management, but for Facebook connect I wrote my own code.
Chances are you may have used facebooker gem. Uninstall that gem, but keep the config/facebooker.yml file.
Try this:
Keep using config/facebooker.yml by adding this code inside config/initializers/load_config.rb (you need to create this file)
config = YAML.load_file("#{Rails.root}/config/facebooker.yml") || {}
facebook_config = config['common'] || {}
facebook_config.update(config[Rails.env] || {})
FB_CONFIG = facebook_config.symbolize_keys
Add this code inside your user_controller.rb:
def facebook_oauth_callback
if not params[:code].nil?
callback = url_for(:host => APP_CONFIG[:host], :controller => 'gallery/user', :action => 'facebook_oauth_callback')
url = URI.parse("https://graph.facebook.com/oauth/access_token?client_id=#{FB_CONFIG[:application_id]}&redirect_uri=#{callback}&client_secret=#{FB_CONFIG[:secret_key]}&code=#{CGI::escape(params[:code])}")
http = Net::HTTP.new(url.host, url.port) http.use_ssl = (url.scheme == 'https') tmp_url = url.path + "?" + url.query
request = Net::HTTP::Get.new(tmp_url)
response = http.request(request)
data = response.body
access_token = data.split("=")[1]
if access_token.blank?
flash[:notice] = 'An error occurred while connecting through Facebook, please try again later.'
else
url = URI.parse("https://graph.facebook.com/me?access_token=#{CGI::escape(access_token)}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = (url.scheme == 'https')
tmp_url = url.path + "?" + url.query
request = Net::HTTP::Get.new(tmp_url)
response = http.request(request)
user_data = response.body
user_data_obj = JSON.parse(user_data)
#user = User.new_or_find_by_facebook_oauth_access_token(access_token, {:user_data => user_data_obj})
if #user.new_record?
session[:user] = #user
session[:external_app] = "Facebook"
redirect_to(:action => 'new_details')
else
user_session = UserSession.create(#user)
flash[:notice] = "Successfully logged in."
redirect_back_or_default root_url
end
end
end
end
def create_facebook
redirect_to("https://graph.facebook.com/oauth/authorize?client_id=#{FB_CONFIG[:application_id]}&redirect_uri=" +
url_for(:host => APP_CONFIG[:host], :controller => 'gallery/user', :action => 'facebook_oauth_callback') +
"&scope=email,offline_access")
end
Add the find method inside your User model (app/models/user.rb):
def self.new_or_find_by_facebook_oauth_access_token(access_token, options = {})
user = User.find_by_facebook_oauth_access_token(access_token)
if user.blank?
#code to create new user here
end
user
end
Add link to action create_facebook in the view, something like
<%= link_to image_tag('gallery/button-facebook.png', :title => "register with Facebook", :alt => "register with Facebook"), {:action => 'create_facebook'}, {:target => '_parent'} %>
Explanation
In the first step you created a file to get config data from facebooker.yml
In second step, you basically created two functions, one for sending user to facebook site (create_facebook) and another to capture the callback data (facebook_oauth_callback) the idea was from this page: http://www.wisejive.com/2010/05/facebook-oauth-on-rails.html
In third step, you just added a method inside User model to find, or create new if not found, a user based on the information returned from facebook.
The code only works on my project, do not just copy-paste it but learn it line-by-line. Over time I realised it is better to use simple code you can understand rather than using other's complicated plugin you cannot fix when things go awry...

I had this problem, I think my problem was in my call to
<%= authlogic_facebook_login_button :controller => 'account', :js => :jquery %>
note I had to pass in controller. I think this was my solution anyway, hit another problem further down the line now where I'm authenticating OK with facebook, but it's creating a new user on my site every time.

Related

Sign in with Google Oauth2.0: Authorization failed. Server message: { "error" : "redirect_uri_mismatch" }

I am getting Signet::AuthorizationError in LoginController#callback and Authorization failed. Server message: { "error" : "redirect_uri_mismatch" } on the line auth_client.fetch_access_token! when I click "Allow" on the OAuth screen and execute my callback method during the OAuth process.
I have checked out this: Google OAuth 2 authorization - Error: redirect_uri_mismatch, but I still can't figure it out.
I am trying to get a login with Google set up like this:
User goes to /login and clicks on the "sign in with google" button.
The Google login prompt comes up, user signs in with Gmail, and then gets redirected to /home.
I have the following uris in my web application credentials in Google consoles:
http://localhost:3000
http://localhost:3000/login/callback
http://localhost/login/callback
http://localhost
routes.rb
get '/home' => 'home#index'
get '/login' => 'login#prompt'
get '/login/callback' => 'login#callback'
login_controller.rb
require 'google/api_client/client_secrets'
class LoginController < ApplicationController
GOOGLE_CLIENT_SECRET_FILE = Rails.root.join('config/google_oauth2_secret.json')
def prompt
if session[:credentials]
redirect_to '/home'
else
auth_client = get_auth_client
auth_client.update!(
:scope => ['profile', 'email'],
:redirect_uri => 'http://localhost:3000/login/callback'
)
#auth_uri = auth_client.authorization_uri.to_s
render layout: false
end
end
def callback
auth_client = get_auth_client
auth_client.code = request['code']
auth_client.fetch_access_token!
auth_client.client_secret = nil
session[:credentials] = auth_client.to_json
redirect_to '/home'
end
private
def get_auth_client
Google::APIClient::ClientSecrets.load(GOOGLE_CLIENT_SECRET_FILE).to_authorization
end
end
I also have a concern. In my prompt method, how do I verify that session[:credentials] is the correct session code? Couldn't anyone just put some bogus string into the credentials session and gain access?
I have been following this guide: https://developers.google.com/api-client-library/ruby/auth/web-app
This happens because localhost is not a valid domain name. Instead of using localhost, you need to use lvh.me
In Google consoles the url will become
http://lvh.me:3000
http://lvh.me:3000/login/callback
Trying accessing your application in the browser using http://lvh.me:3000 instead of http://localhost:3000
lvh.me is a valid domain name with is pointing to 127.0.0.1
I realize the issue is I am setting the scope in the prompt function when I am generating the auth uri but in my callback function, I am not setting the scope.
It should be like this:
def callback
auth_client = get_auth_client
auth_client.update!(
:scope => ['profile', 'email'],
:redirect_uri => 'http://localhost:3000/login/callback'
)
auth_client.code = request['code']
auth_client.fetch_access_token!
auth_client.client_secret = nil
session[:credentials] = auth_client.to_json
redirect_to '/home'
end

Use API to authenticate in Rails

I currently have a Rails application that is connected to an existing SQL database. I am using Devise for my user management, however the pre-existing User table in the database uses a very customized password encryption method.
There is a web service I can connect to that passes a JSON object with the login information to authenticate whether it is valid or not, and I have to manage my own session and everything after that.
I attempted to follow "Railscast #250", and combine it with Devise and some Stack Overflow searches, but things are not going very well.
This is what I have now, but it isn't doing anything, and I just don't feel like I am on the right track with this.
class SessionsController < Devise::SessionsController
def new
super
end
def create
post_params = {
"RuntimeEnvironment" => 1,
"Email" => params[:session][:email],
"Password" => params[:session][:password]
}.to_json
user_params = RestClient.post 'http://some.ip/WebServices', post_params, :content_type => "json"
user = User.authenticate(user_params)
if user
session[:user_id] = user.user_id
redirect_to root_path
else
flash.now.alert = "Invalid Username or Password"
render "new"
end
end
end
This is the JSON Object returned if there is a successful login:
{"Success":true,"ErrorMessage":"","ResponseString":"","LoginResultData":{"FailMessage":"","ResultCode":0,"User":{"AccountCompleteFlag":1,"CreationDtime":"\/Date(1430848539000-0400)\/","DeleteFlag":0,"Email":"john#doe.com","FailedPasswordCount":1,"HistoricalFlag":0,"IsDirty":false,"IsAdminFlag":0,"IsSiteAdminFlag":0,"LastLoginDtime":"\/Date(1447789258000-0500)\/","NameFirst":"Ttest","NameLast":"test","Password":"TRQt3d2Z7caDsSKL0ARVRd8nInks+pIyTSqp3BLxUgg=","PasswordLockDtime":"\/Date(-62135578800000-0500)\/","PasswordLockFlag":0,"PasswordResetCode":"","PasswordResetStatus":0,"Phone":"1-X-5555555555-","RegistrationSource":"Registration","UserId":100029,"UserType":1,"PhoneInfo":{"AreaCode":"555","CountryCode":"X","Extension":"","FirstThree":"555","InternationalPhoneNumber":"","IsDirty":false,"IsInternational":false,"LastFour":"5555"}}}}
And what is returned for a failed one:
{"Success":true,"ErrorMessage":"","ResponseString":"","LoginResultData":{"FailMessage":"Invalid email address","ResultCode":1,"User":null}}
Is there a way where I can use Devise's session management while connecting to the API?
You can still authenticate through Devise using the email and password that the user provided. The RestClient would just be like a double check: just make sure that there are no routes that the user can authenticate through besides going through the RestClient. You can check this by doing rake routes.
For checking whether the result code was valid, you can do some JSON parsing as follows:
authentication_response = RestClient.post 'http://some.ip/WebServices', post_params, :content_type => "json"
json_authentication_response = JSON.parse(authentication_response)
result_code = json_authentication_response["LoginResultData"]["ResultCode"]
if result_code == 0
# Authenticate
else
# Don't authenticate
end

request.url incorrect after ajax calls?

I login to my Rails application using a login page which is reached either directly through a login link that uses the route
match 'ladmin/login' => 'ladmin#login'
or if I try to edit content.
In either case I get taken to the login page, which allows me to login and then returns me to the page I was trying to use or the app index page, but now as a logged in user.
Most of the time this works totally ok, I get logged in and returns to my content edit page or to the links index page as expected (if I had just use the 'login' link iself).
However I have been able to track down a bug whereby
if I use either of my ajax links the request.url is remembered incorrectly going forward
(to either toggle group shading or to toggle Summary/Details, then the next time (even if several clicks) that I try to login (assuming I am logged out initially) results in the blank page - though I am actually now logged in. Interestingly I notice that when this happens, the url that I end up at in the browser address bar is always localhost:3000/toggle_row_shading which seems like a clue to the problem - it seems like the request.url is remembered incorrectly .
I require digest/sha1 for authentication in the User model with various methods for authentication and password.
The relevant code would seem to be in my LadminController:
def login
session[:user_id] = nil
if request.post?
user = User.authenticate(params[:username], params[:password])
if user
session[:user_id] = user.id
session[:username] = user.username
uri = session[:original_uri]
session[:original_uri] = nil
redirect_to(uri || {:action => "index", :controller => :links})
else
flash.now[:notice] = "Invalid username/password combination"
end
end
end
I can temporarily got around it with
def login
session[:user_id] = nil
if request.post?
user = User.authenticate(params[:username], params[:password])
if user
session[:user_id] = user.id
session[:username] = user.username
redirect_to({:action => "index", :controller => :links})
else
flash.now[:notice] = "Invalid username/password combination"
end
end
end
However this 'forgets' the page I have come from, e.g. an 'edit' link and just uses links#index to put me on after login which is not ideal. It does get around the blank page problem though, as the steps to reproduce it now longer make it happen.
How can I have the login return me to the intended edit page and not give me the blank page?
btw my code for the ajax links is:
%a{href: '#', :data => {toggle_group_row_shading: 'toggle'}}
click to toggle
Do I need an extra route perhaps as the app started at rails 2.3.8 ?
My routes include
match 'toggle_full_details' => 'links#toggle_full_details'
match 'toggle_row_shading' => 'links#toggle_row_shading'
get 'verify_link/:id', to: 'links#verify_link', as: :verify_link
get 'unverify_link/:id', to: 'links#unverify_link', as: :unverify_link
should I have them all as gets perhaps?
My application controller includes:
before_filter :authorize, :except => :login
and
def authorize
unless User.find_by_id(session[:user_id])
session[:original_uri] = request.url #request.request_uri
flash[:notice] = "Please Log In!"
redirect_to :controller => 'ladmin', :action => 'login'
end
end
I have had this happen to me before. The problem I found was that for AJAX requests, the session[:original_uri] is still getting stored and... is bad. Basically, it's storing a uri for an ajax request which doesn't display very well after logging in. The code I ended up with is something like:
if request.get? && !request.xhr?
session[:original_uri] = request.url
end
This way we're not storing into the session[:original_uri] things that shouldn't be redirected to after logging in. You may find other things in your app to add to this conditional. For example, I had some download links that would render a send_file, but those were no good for storing for next login either.

Rubymotion: GET Request using JSON

I am new to iOS programming and using Rubymotion to build my first application. In my Rubymotion app I POST to a webserver (an app built using RoR) to authenticate a user wanting to Login and am using the BubbleWrap gem for RubyMotion https://github.com/rubymotion/BubbleWrap/blob/master/motion/http.rb
def login(sender)
payload = {email: #email, password: #password}
BubbleWrap::HTTP.post("http://example.com/sessions", {payload: payload}) do |response|
#authCookie = response.headers['Set-Cookie']
end
end
Now once I receive successful authentication I move onto to receive JSON data from the web application using the following code:
BubbleWrap::HTTP.get("http://example.com/events.json", {cookie: #authCookie, :headers=>{"Content-Type"=>'json'} }) do |response|
puts response.body #testing the response
end
For some reason, the authentication token received from the POST request is not being correctly passed on by the GET request. I know this because in the web app if authentification fails it redirects to the login page and that's the response (HTML code of the Login page) am receiving from the GET request.
Authentication check on the Web App:
def session_check
if session[:bizid].nil?
redirect_to login_url
flash[:notice] = "Please login to view your account!"
end
end
Additionally, on the web app this authentication token is set by the following method:
def create
current_biz = Bizname.find_by_email(params[:email])
if current_biz && current_biz.authenticate(params[:password])
session[:bizid] = current_biz.id
flash[:notice] = 'Login Successful!'
if current_biz.events.empty?
redirect_to getsetup_url
else
redirect_to account_summary_url
end
else
flash[:notice] = 'Incorrect Email or Password.'
redirect_to login_url
end
end
Any ideas of what I might be doing wrong here?
Thanks in advance!
You just need to pass the cookie in as a header too. For example:
BubbleWrap::HTTP.get("http://example.com/events.json", :headers=> {"Content-Type"=>'json', "Cookie" => #authCookie}) do |response|
puts response.body #testing the response
end

LDAP authentication always returning true

Im following a tutorial online (http://my.opera.com/learnror/blog/ldap-binding-and-authentication-ror) to setup authentication against an LDAp active directory (have a pretty tough time with it too). Anyway, i got the login form and everything setup but for some reason, no matter what i type into the form, (even wrong/nonexistent credentials), it comes back as true! Can anyone help?
OR can anyone provide away to have some sort of debugger run the code line by line (like done with jaavscript debugger). Heres the code that authenticates the login form: (the LDAP module is in a separate lib file):
def authenticate
if session[:person] = LDAP.authenticate(params[:login][:name], params[:login][:p
assword])
session[:username] = params[:login][:name]
if session[:return_to]
redirect_to(session[:return_to])
session[:return_to] = nil
else
redirect_to :controller => 'login' , :action => 'index'
end
else
flash[:notice] = "Login failed!"
redirect_to :action => "index"
end
It looks to me like you used = instead of == in if session[:person] = LDAP… == means equals, = means assignment.

Resources