Rspec Rails 3.1 Integration test. How to send post request headers for mobile, http basic authentication and JSON? - testing

I have an RSPEC integration test for a Rails 3.1 app that needs to test an api for a mobile client by issuing a POST request with JSON params and a mobile header that needs to use http_basic authentication
As the request object is not available in an integration test I'm kinda stuck
This is the code I have so far
it "successfully posts scores" do
# request.env["HTTP_ACCEPT"] = "application/json" #This causes an error as request is nly available in controller tests
post "scores", :score => {:mobile_user_id => #mobile_user.id, :points => 50, :time_taken => 7275}.to_json,
:format => :json, :user_agent => 'Mobile', 'HTTP_AUTHORIZATION' => get_basic_auth
end
The post request does not recognise that I am using http basic authentication but unsure if the format for json is correct. Any help appreciated
get_basic_auth is a helper me4thod that looks like this
def get_basic_auth
user = 'user'
pw = 'secret'
ActionController::HttpAuthentication::Basic.encode_credentials user, pw
end
I use a before_filter in my controllers that checks for mobile and http_basic_authentication that looks like this
def authorize
logger.debug("#### Authorizing request #{request.inspect}")
if mobile_device?
authenticate_or_request_with_http_basic do |username, password|
username == Mobile::Application.config.mobile_login_name && Mobile::Application.config.mobile_password
end
else
unless current_user
redirect_to login_url, :notice => "Please log in"
end
end
end
I get a redirect to login so obviously the mobile header is not being accepted so I have no idea really if any of the other headers are working
UPDATE
Figured it out
post("scores", {:score => {:mobile_user_id => #mobile_user.id, :points => 50, :time_taken => 7275}}.to_json,
{"HTTP_USER_AGENT" => "Mobile", 'HTTP_AUTHORIZATION' => get_basic_auth, 'HTTP_CONTENT_TYPE' => "application/json"})
Does the trick nicely

I figured out what I needed to do
post("scores", {:score => {:mobile_user_id => #mobile_user.id, :points => 50, :time_taken => 7275}}.to_json,
{"HTTP_USER_AGENT" => "Mobile", 'HTTP_AUTHORIZATION' => get_basic_auth, 'HTTP_CONTENT_TYPE' => "application/json"}
Obviously the "mobile" user agent is not needed to test normal json requests.
Hope that helps someone

Related

Ruby Motion, Rails 3.x, Devise login through custom api/v1/sessions_controller.rb

I'm using this lucatironi tutorial to do my RM/rails/devise native authentication. I got everything working except one piece where I authenticate in the sessions_controller.rb
I'm sending in
{ session : { email: "test#five.com", password: "password" } } (bubblewrap is forcing a 'sessions' node onto my JSON!)
resource_name is :api_v1_user
controller_path is "api/v1/sessions"
class Api::V1::SessionsController < Devise::SessionsController
def create
warden.authenticate!(:scope => resource_name, :store => false, :recall => "#{controller_path}#failure")
render :status => 200,
:json => { :success => true,
:info => "Logged in",
:data => { :auth_token => current_user.authentication_token } }
end
end
All I get is an alert in the app "Login Failed"
Thanks for any help
Did you remember to call skip_before_filter :verify_authenticity_token? Given that the request is not coming from a rails-generated form, the token wouldn't be there.
So I figured this out.
authenticate! doesn't return annything
has to be "authenticate" with no "!"
that was it!

From Rails devise auth to backbone & api?

i want to rebuild an app which is a typical rails 3.2 mvc app into a API + Frontend (Backbone) only. As I have no experience in building APIs in rails including authenticatin:
What's the best way to authenticate with devise using backbone? Using auth_tokens?
How should I make he API? Just printing out JSON or use a gem like Grape?
thanks in advance!
I can explain you the way i do this :
First, i install a standard rails application with devise. After that, i create my own session controller :
class SessionsController < ApplicationController
def authenticate
# this method logs you in and returns you a single_access_token token for authentication.
#user = User.find_for_authentication(:email => params[:user][:email])
if #user && #user.valid_password?(params[:user][:password])
render :json => {:user => {:email => #user.email, :id => #user.id, :firsname => #user.firstname, :lastname => #user.lastname, :team_id => #user.team_id, :singleAccessToken => #user.generate_access_token}}
else
render :json => {:errors => ["Nom d'utilisateur ou mot de passe invalide"]}, :status => 401
end
end
end
As you can see, i send a request to this url with the json looking like :
{
user => {
email => "myemail#toto.com",
password => "monpass"
}
}
And my controller return me the json with user data if every thing is fine, or an error. On json with user, i return an access_token used on next requests to check that the user is allowed to request. I made this filters in my application controller :
class ApplicationController < ActionController::Base
protect_from_forgery
protected
def user_access_token
request.headers["HTTP_X_USER_ACCESS_TOKEN"] || request.headers["HTTP_USER_ACCESS_TOKEN"]
end
def current_user
if token = user_access_token
#user ||= User.find_by_access_token(token)
end
end
def require_user
unless current_user
render :json => {:error => "Invalid Access Token"}, :status => 401
end
end
def require_owner
unless current_user && current_user == object.user
render :json => {:error => "Unauthorized"}
end
end
end
As you can see, on each next request, i will add the access_token in html header on key : HTTP_USER_ACCESS_TOKEN
So, i can check if the user is allowed to make the request.
To make an API, you can use the Rails API gem as see here :
http://railscasts.com/episodes/348-the-rails-api-gem
Good luck.

Rails rspec and omniauth (integration testing)

My Rails 3.2 app uses OmniAuth and Devise to sign in with Twitter. The authentication system works fine. I would like to write an integration test in rspec to make sure everything works. Using the information in the wiki, I've written the following, but I know I'm missing things.
Under test.rb in config/environments, I have the following lines
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:twitter] = {:provider => 'twitter', :uid => '123545'}
My rspec test looks like this:
describe "Authentications" do
context "without signing into app" do
it "twitter sign in button should lead to twitter authentication page" do
visit root_path
click_link "Sign in with Twitter"
Authentication.last.uid.should == '123545'
end
end
end
Authentication is the name of my model and calling .uid in rails console returns the string fine.
I'm getting the following error when I run this test:
Failure/Error: Authentication.last.uid.should == '123545'
NoMethodError:
undefined method `uid' for nil:NilClass
Can anyone help me figure out how to use the OmniAuth mocks that are provided? An explanation for why and how it works would be appreciated as well.
I run into something similar.
After changing my mock object from using symbol keys:
OmniAuth.config.mock_auth[:twitter] = {
:uid => '1337',
:provider => 'twitter',
:info => {
:name => 'JonnieHallman'
}
}
to using string keys:
OmniAuth.config.mock_auth[:twitter] = {
'uid' => '1337',
'provider' => 'twitter',
'info' => {
'name' => 'JonnieHallman'
}
}
it worked.
And do you have
request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:twitter]
somewhere in your testcase?
Did you try moving these two lines to spec_helper.rb?
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:twitter] = {:provider => 'twitter', :uid => '123545'}
Also add the following before block in your test file:
before do
request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:twitter]
end
You can find more info on this link: https://github.com/intridea/omniauth/wiki/Integration-Testing
I highly suggest this answer
In short...
Set up the mock
Make the request
Test whatever code is attached to the callback
For example: test the session['uid'] was set (although, I opt to test only what the user sees, or, rather, does not see)
My code...
config/environments/test.rb
Rails.application.configure do
...
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:linkedin] = {
'provider' => 'linkedin',
'uid' => '123545',
'info'=>
{ 'email'=>'infinite#jest.com',
'first_name'=>'Dave',
'last_name'=>'Wallace' }
}
end
spec/features/sign_in_feature_spec.rb
require 'rails_helper'
feature 'Sign in with LinkedIn' do
before do
OmniAuth.config.add_mock(:linkedin, {:uid => '12345'})
end
let(:user) { create(:user) }
scenario 'with valid email and password' do
visit '/'
expect(page).to have_no_content 'Sign Out'
click_link 'nav-sign-in' # image/button: Sign in with LinkedIn
expect(page).to have_content 'Sign Out'
end
end
Let me know if/how I may improve this solution (and my code!)
Selected solution does not work for me.
My solution i get from https://gist.github.com/kinopyo/1338738
and official doc https://github.com/intridea/omniauth/wiki/Integration-Testing
here:
# in spec/support/omniauth_macros.rb
module OmniauthMacros
def mock_auth_hash
# The mock_auth configuration allows you to set per-provider (or default)
# authentication hashes to return during integration testing.
OmniAuth.config.mock_auth[:odnoklassniki] = OmniAuth::AuthHash.new({
:provider => 'odnoklassniki',
:uid => '123545',
:info => OmniAuth::AuthHash::InfoHash.new({
:name => 'mockuser'
})
})
end
end
# in spec/spec_helper.rb
RSpec.configure do |config|
# email spec
config.include(EmailSpec::Helpers)
config.include(EmailSpec::Matchers)
end
OmniAuth.config.test_mode = true
# in spec example:
visit new_user_registration_path
mock_auth_hash
find('#btn-odnoklassniki').click # here is link generated as omniauth_authorize_path(resource_name, provider)

How to test this code with RSpec?

I have the following simple class and HTTParty method:
class Token
require 'httparty'
include HTTParty
base_uri 'https://<some url>'
headers 'auth_user' => 'user'
headers 'auth_pass' => 'password'
headers 'auth_appkey' => 'app_key'
def self.getToken
response = get('/auth/token')
#token = response['auth']['token']
end
end
I know it works because I can call the method in the Rails console and successfully get a token back.
How can I test the above code in RSpec?
My initial stab at it doesn't work:
describe Token do
before do
HTTParty.base_uri 'https://<some url>'
HTTParty.headers 'auth_user' => 'user'
HTTParty.headers 'auth_pass' => 'password'
HTTParty.headers 'auth_appkey' => 'app_key'
end
it "gets a token" do
HTTParty.get('auth/authenticate')
response['auth']['token'].should_not be_nil
end
end
It says: NoMethodError: undefined method 'base_uri' for HTTParty:Module...
Thanks!
Since you are testing a module you might try something like this:
describe Token do
before do
#a_class = Class.new do
include HTTParty
base_uri 'https://<some url>'
headers 'auth_user' => 'user'
headers 'auth_pass' => 'password'
headers 'auth_appkey' => 'app_key'
end
end
it "gets a token" do
response = #a_class.get('auth/authenticate')
response['auth']['token'].should_not be_nil
end
end
This creates an anonymous class and extends it with HTTPparty's class methods. However, I am not sure the response will return as you have it.

Authentication between applications using OAuth

I have two rails application running at different ports. First at 3000 and the second at 4000. Both of them use Devise gem for auth.
First application plays the role of OAuth provider and the second on OAuth consumer.
I've followed this and that tutorials to build my environment.
Almost all works fine. I've successfully generated key and secret for consumer application. And successfully authorize at provider application.
There are two methods at my client application:
def auth
#consumer = OAuth::Consumer.new 'KEY', 'SECRET', :site => "http://localhost:3000"
#request_token = #consumer.get_request_token
session[:request_token] = #request_token
redirect_to #request_token.authorize_url
end
def auth_callback
#request_token ||= session[:request_token]
#access_token = #request_token.get_access_token :oauth_verifier => params[:oauth_verifier]
#request = #access_token.get '/user_info.json'
render :text => #request.body.inspect
end
And API method at provider application:
class UsersController < InheritedResources::Base
before_filter :login_or_oauth_required
load_and_authorize_resource
def info
logger.info current_user.present? # => false
#info = { } # here I've collect user info for current_user
respond_to do |format|
format.json { render :json => #info }
end
end
end
Shit happens when I try getting user info at line: #request = #access_token.get '/user_info.json'
When I call it in consumer application user already unauthorized at provider application.
How I can stay authorized at provider's resource?
upd: I've got current_user.present? # => false in case I pass authorization for info action (before_filter :login_or_oauth_required, :except => [:info]) otherwise I've got redirected to login page.
You don't stay authorized in the provider.
On every request to your API, you'll receive the access token (either in parameters or header), and from this token you'll be able to determine who is the current_user. There is no session among requests.
This gem may help if you need an OAuth provider.
The load_and_authorize_resource will deny access to info action.
just add :except attribute
load_and_authorize_resource :except => [:info]