Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails, Restful Authentication & RSpec - How to test new models that require authentication

I've created a learning application using Bort, which is a base app that includes Restful Authentication and RSpec. I've got it up and running and added a new object that requires users to be logged in before they can do anything(before_filter :login_required in the controller). [edit: I should also mention that the user has_many of the new class and only the user should be able to see it.]

I've created the new model/controller using Rspec's generators which have created a number of default tests. They all pass if there is no before_filter but several fail, as should be expected, once the before_filter is in place.

How do I get the generated tests to run as if there is/is not a logged in user? Do I need a whole batch of matching not logged in - redirect tests? I assume it is some sort of mocking or fixture technique but I am new to RSpec and a bit adrift. Good RSpec tutorial links would also be appreciated.

like image 880
srboisvert Avatar asked Sep 15 '08 17:09

srboisvert


People also ask

How does API authentication work in Rails?

The token-based verification method works simply. The user enters his details and sends the request to the server. If the information is correct, the server creates a unique HMACSHA256 encoded token, also known as the JSON (JWT) web token.

What is JWT authentication in Rails?

JSON Web Tokens, commonly known as JWT is an open standard for representing and verifying claims securely between a client and a server. It is one of the most popular authentication and authorization techniques employed in modern applications.


3 Answers

I have a very similar setup, and below is the code I'm currently using to test this stuff. In each of the describes I put in:

it_should_behave_like "login-required object"
def attempt_access; do_post; end

If all you need is a login, or

it_should_behave_like "ownership-required object"
def login_as_object_owner; login_as @product.user; end
def attempt_access; do_put; end
def successful_ownership_access
  response.should redirect_to(product_url(@product))
end

If you need ownership. Obviously, the helper methods change (very little) with each turn, but this does most of the work for you. This is in my spec_helper.rb

shared_examples_for "login-required object" do
  it "should not be able to access this without logging in" do
    attempt_access

    response.should_not be_success
    respond_to do |format|
      format.html { redirect_to(login_url) }
      format.xml { response.status_code.should == 401 }
    end
  end
end

shared_examples_for "ownership-required object" do
  it_should_behave_like "login-required object"

  it "should not be able to access this without owning it" do
    attempt_access

    response.should_not be_success
    respond_to do |format|
      format.html { response.should be_redirect }
      format.xml { response.status_code.should == 401 }
    end
  end

  it "should be able to access this if you own it" do
    login_as_object_owner
    attempt_access

    if respond_to?(:successful_ownership_access)
      successful_ownership_access
    else
      response.should be_success
    end
  end
end
like image 193
TALlama Avatar answered Sep 17 '22 22:09

TALlama


When not testing the authentication but testing the controllers that needs the user to be authenticated I usually stub the filter method:

before(:each) do
  controller.stub!(:authenticate).and_return(true)
end

The above example works where my before_filter is set to the authenticate method:

before_filter :authenticate

and the authenticate in my app uses HTTP Basic Authentication, but it really can be any other authentication mechanism.

private
def authenticate
  authenticate_or_request_with_http_basic do |user,password|
    user == USER_NAME && password == PASSWORD
  end
end

I think it's a pretty straightforward way to test.

like image 26
Marcos Oliveira Avatar answered Sep 19 '22 22:09

Marcos Oliveira


I found a few answers to my own question. Basically, I needed to understand how to mock out the user from restful_authentication so that the autogenerated rspec controller tests could pass even though I had added before_filter: login_required.

Here are a few of my just found resources:

RSpec: It Should Behave Like

rspec, restful_authentication, and login_required

using restful_authentication current_user inside controller specs

DRYing up your CRUD controller RSpecs

like image 36
srboisvert Avatar answered Sep 19 '22 22:09

srboisvert