I am trying to use Omniauth for login with Facebook in my Rails app, it seems to be working when i view the response in the console view, but I am not getting any information back in env['omniauth.auth'], when I try to inspect it returns NIL.
But in console, I can see the response as:
Object { accessToken="EAAHQ5CgynEoBAFfoTk5kSs7...WxZCw1fDHLQ4CBEspCgBAZD", userID="1268814806542277", expiresIn=7198, more...}
I use Rails 5.0.0.1 and Ruby 2.3.0p0
Gemfile
gem 'omniauth'
gem 'omniauth-facebook', '1.4.0'
omniauth.rb
OmniAuth.config.logger = Rails.logger
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, 'APP ID', 'APP SECRET', scope: 'email', display: 'popup', :info_fields => 'name,email', :include_granted_scopes => true
end
sessions_controller
class SessionsController < ApplicationController
def create
abort(env["omniauth.auth"].inspect) // here I am getting the NIL response
user = User.from_omniauth(env["omniauth.auth"])
session[:user_id] = user.id
return redirect_to new_user_session_path
end
def destroy
session[:user_id] = nil
return redirect_to root_url
end
end
Why might this be happening?
So finally I found the issue. The problem was with the devise.rb, I was using the following code in my devise.rb, I just removed those lines, and it started working.
config.omniauth :facebook, app_id, app_secret, scope: 'email, public_profile'
Related
Currently I am writing some controller test with rspec. The controller requires user to sign in before being usable.
if #current_user.nil?
do something
else
redirect
I currently have issues on how to stub the local variable current_user.
Why not have rspec login to your test system rather than stubbing current_user. You could do something like the following:
describe "Req #5 - login" do
it 'loads the login page' do
get '/login'
expect(last_response.status).to eq(200)
end
it 'loads the user index after login' do
user = User.create(:username => "Raptor", :password => "Raptor")
params = {
:username => "Raptor",
:password => "Raptor"
}
post '/login', params
follow_redirect!
expect(last_response.body).to include("Home Page for: Raptor")
end
end
You can stub the controller's current_user method like this:
let(:current_user) { User.create(...) }
before do
allow(#controller).to receive(:current_user).and_return(current_user)
end
I am writing backend of an app in Rails. As I work on the backend, I need to give the frontend developer a REST API to start building the frontend. Eventually, the frontend and backend will reside together in a single app, but for now they are separate.
For time being I have enabled Cross-origin resource sharing in my app, by adding following to ApplicationController:
config.action_dispatch.default_headers.merge!({
'Access-Control-Allow-Origin' => '*',
'Access-Control-Request-Method' => '*'
});
For now, I have also turned off CSRF tokens by adding following to application.rb:
skip_before_filter :verify_authenticity_token
I am using Devise for authenticating users. To make Devise work with JSON requests, I have done following:
In devise.rb
config.navigational_formats = ['*/*', :html, :json]
In routes.rb
devise_for :users, :controllers => {:omniauth_callbacks => "omniauth_callbacks", :sessions => 'sessions', :registrations => 'registrations' }
My SessionsController
class SessionsController < Devise::SessionsController
#todo had to do following to support logging in through ajax. need to add logic to send back error response when login fails.
#todo see http://stackoverflow.com/questions/5973327/using-devise-1-3-to-authenticate-json-login-requests/8402035#8402035 and
#todo https://web.archive.org/web/20130928040249/http://jessehowarth.com/devise
#todo see http://stackoverflow.com/questions/11277300/devise-failure-authentication-via-json-sends-back-html-instead-of-json
def create
respond_to do |format|
format.html { super }
format.json {
resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#failure")
sign_in(resource_name, resource)
return render :json => {:success => true, :user => resource}
}
end
end
def destroy
respond_to do |format|
format.html { super }
format.json {
Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
render :json => {}
}
end
end
def failure
render :json => {:success => false, :errors => ["Login Failed"]}, :status => 422
end
end
I have a extended Devise's RegistrationsController as well as indicated in routes.rb, but am not posting its content here, as I don't think it is relevant to this question.
With the above setup I am able to send an ajax request to '/users/sign_in' with user[email] and user[password] parameters and have the user signed in. The response looks something like this:
{
success: true
user: {
authentication_token: "SNa2kPqkm5ENsZMx7yEi"
created_at: "2014-12-16T02:40:39.179Z"
email: "xyz#xyz.com"
id: 99999
name: null
provider: null
uid: null
updated_at: "2014-12-17T02:29:31.537Z"
}
}
Now how do I use the authentication_token I received in the sign_in response to send requests to other controller actions that require user to be authenticated? Do I need to set this token in a request header? I am not able to find information on how to use this token. Please help.
It seems following as described in the gist here, the answer is that you send the suer's email and authetication_token with every request to the backend. You may choose to send it in request header or simply as parameters. You simply modify the method that checks the email and token and signs in the user in ApplicationController accordingly. This is my ApplicationController (I am now sending the email and token as parameters in the request):
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
#todo remove this once ui is integrated. following turns off the csrf token:
skip_before_filter :verify_authenticity_token
#todo begin code to support authentication using token
# This is our new function that comes before Devise's one
before_filter :authenticate_user_from_token!
# This is Devise's authentication
before_filter :authenticate_user!
private
def authenticate_user_from_token!
user_email = params[:user_email].presence
user = user_email && User.find_by_email(user_email)
# Notice how we use Devise.secure_compare to compare the token
# in the database with the token given in the params, mitigating
# timing attacks.
if user && Devise.secure_compare(user.authentication_token, params[:user_token])
sign_in user, store: false
end
end
#todo end code to support authentication using token
end
I forgot to mention in my post that I had already added the migration to add a authentication_token column to User model. Also, I had to add following in the User model (as described in the gist), so that an authentication token is generated each time a user is created/updated:
#todo begin code to support ajax authentication of users
#todo see https://gist.github.com/josevalim/fb706b1e933ef01e4fb6
# You likely have this before callback set up for the token.
before_save :ensure_authentication_token
def ensure_authentication_token
if authentication_token.blank?
self.authentication_token = generate_authentication_token
end
end
private
def generate_authentication_token
loop do
token = Devise.friendly_token
break token unless User.where(authentication_token: token).first
end
end
#todo end code to support ajax authentication of users
I'm creating an application, which has authentication based on external API with login/register methods. I have a simple controller called RegistrationsController which fires a request using Curb.
This is the controller:
class RegistrationsController < ApplicationController
def new
end
def create
if params[:user][:email].present? && params[:user][:password].present? && params[:user][:phone].present? && params[:user][:login].present?
# API request
password = params[:user][:password]
body = {
"register" => {
"password" => password,
"email" => params[:user][:email],
"phone" => params[:user][:phone],
"login" => params[:user][:login]
}
}
c = Curl::Easy.http_post("http://domain.com/register", body.to_json
) do |curl|
curl.headers['Content-Type'] = 'application/json'
curl.headers['application'] = 'appname'
curl.headers['device'] = 'www'
end
c.perform
response_body = JSON.parse(c.body_str)
throw response_body # This line ALLWAYS gives me 'login taken' error
return
else
#user = User.new(params[:user])
render action: "new", notice: 'Error'
end
end
end
(I also have a views/registrations/new.html.slim view with a simple form but it's not important right now.)
My routes look like this:
match 'users/sign_up' => 'registrations#new', :via => :get, :as => :user_register
match 'users/sign_up' => 'registrations#create', :via => :post, :as => :user_create
My application, after I click the "Register" button on the registrations#new page, is triggering the Curb request two times. As a result, I'm always getting a 'login taken' error. The user is registered successfully but I'm not getting any result from the first request, just from the second one.
It's somehow caused by Rails and I'm 100% sure about it because it can be seen in the API server logs that the request is triggered twice. Also, I have exactly the same script written in PHP and, in there, the registration works fine.
In my Rails dev console, the request is triggered just one time so it's really strange.
Does anyone have any idea what is going on here?
I found the answer.
If anyone struggles with something similar, it was caused by the c.perform line. Just remove it and it will work fine.
I should study the docs better in the future.
I have the following spec...
describe "successful POST on /user/create" do
it "should redirect to dashboard" do
post '/user/create', {
:name => "dave",
:email => "dave#dave.com",
:password => "another_pass"
}
last_response.should be_redirect
follow_redirect!
last_request.url.should == 'http://example.org/dave/dashboard'
end
end
The post method on the Sinatra application makes a call to an external service using rest-client. I need to somehow stub the rest client call to send back canned responses so I don't have to invoke an actual HTTP call.
My application code is...
post '/user/create' do
user_name = params[:name]
response = RestClient.post('http://localhost:1885/api/users/', params.to_json, :content_type => :json, :accept => :json)
if response.code == 200
redirect to "/#{user_name}/dashboard"
else
raise response.to_s
end
end
Can someone tell me how I do this with RSpec? I've Googled around and come across many blog posts which scratch the surface but I can't actually find the answer. I'm pretty new to RSpec period.
Thanks
Using a mock for the response you can do this. I'm still pretty new to rspec and test in general, but this worked for me.
describe "successful POST on /user/create" do
it "should redirect to dashboard" do
RestClient = double
response = double
response.stub(:code) { 200 }
RestClient.stub(:post) { response }
post '/user/create', {
:name => "dave",
:email => "dave#dave.com",
:password => "another_pass"
}
last_response.should be_redirect
follow_redirect!
last_request.url.should == 'http://example.org/dave/dashboard'
end
end
Instance doubles are the way to go. If you stub a method that doesn't exist you get an error, which prevents you from calling an un-existing method in production code.
response = instance_double(RestClient::Response,
body: {
'isAvailable' => true,
'imageAvailable' => false,
}.to_json)
# or :get, :post, :etc
allow(RestClient::Request).to receive(:execute).and_return(response)
I would consider using a gem for a task like this.
Two of the most popular are WebMock and VCR.
I am trying to log in with HTTParty.
I followed the instruction and still can't get it to work.
require 'rubygems'
require 'httparty'
class LAShowRoom
include HTTParty
base_uri 'www.lashowroom.com'
#debug_output
def initialize email, password
#email = email
response = self.class.get('/login.php')
response = self.class.post(
'/login.php',
:body => { :login_id => email, :login_key => password, :submit_login => 'Log In' },
:headers => {'Cookie' => response.headers['Set-Cookie']}
)
#response = response
#cookie = response.request.options[:headers]['Cookie']
end
def login_response
#response
end
def welcome_page
self.class.get("/announce.php", :headers => {'Cookie' => #cookie})
end
def logged_in?
welcome_page.include? "Kevin"
end
end
la_show_room = LAShowRoom.new('my_email', 'my_password')
puts "Logged in: #{la_show_room.logged_in?}"
As far as I know, HTTParty handles https automatically.
Am I missing something?
Thanks.
Sam
Yes, HTTParty handles HTTPS automatically, but you still need to declare HTTPS. Try
base_uri 'https://…'
How else is HTTParty supposed to know? ;-)