78

Here's my http basic authentication in the application controller file (application_controller.rb)

before_filter :authenticate

protected

def authenticate
  authenticate_or_request_with_http_basic do |username, password|
    username == "username" && password == "password"  
  end
end

and the default test for the index action of my home controller (spec/controllers/home_controller_spec.rb)

require 'spec_helper'

describe HomeController do

describe "GET 'index'" do
  it "should be successful" do
    get 'index'
    response.should be_success
  end
end

The test doesn't run because of the authentication method. I could comment out "before_filter :authenticate" to run them but I would like to know if there is way to make them worked with the method.

Thank you!

1
  • As of Rails 6, it looks like this answer is the working one. Commented Nov 19, 2021 at 15:59

7 Answers 7

146

Update (2013): Matt Connolly has provided a GIST which also works for request and controller specs: http://gist.github.com/4158961


Another way of doing this if you have many tests to run and don't want to include it everytime (DRYer code):

Create a /spec/support/auth_helper.rb file:

module AuthHelper
  def http_login
    user = 'username'
    pw = 'password'
    request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(user,pw)
  end  
end

In your test spec file:

describe HomeController do
  render_views

  # login to http basic auth
  include AuthHelper
  before(:each) do
    http_login
  end

  describe "GET 'index'" do
    it "should be successful" do
      get 'index'
      response.should be_success
    end
  end

end

Credit here - Archived site

Sign up to request clarification or add additional context in comments.

7 Comments

it shows request is nil for me. any idea how to get a workaround?
For request specs, you can have multiple requests, so request is nil. Instead you need to create an env hash env = {}, update that in your http_login method, and then pass in the env explicitly as in get '/', {}, env.
Expanding on the above, which works for request and controller specs: gist.github.com/4158961
+1 for the gist from Matt Connolly; it solved my problem when nothing else did. BTW, I tried to use the Rack::Test authorize method - didn't work.
I get Failure/Error: @request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Token.encode_credentials("test_access1") NoMethodError: undefined method `env' for nil:NilClass when I try to use this.. why ?
|
21

Sorry I didn't search enough, the solution seems to be the following:

describe "GET 'index'" do
  it "should be successful" do
    @request.env["HTTP_AUTHORIZATION"] = "Basic " + Base64::encode64("username:password")
    get 'index'
    response.should be_success
  end
end

Comments

9

For me, with Rails 6, I need keyword arguments for rspec get method like .. get route, params: params, headers: headers

Auth Helper method

module AuthHelper
  def headers(options = {})
    user = ENV['BASIC_AUTH_USER']
    pw = ENV['BASIC_AUTH_PASSWORD']

    { HTTP_AUTHORIZATION: ActionController::HttpAuthentication::Basic.encode_credentials(user,pw) }
  end
  def auth_get(route, params = {})
    get route, params: params, headers: headers
  end
end

and the rspec request test.

describe HomeController, type: :request do    
  include AuthHelper

  describe "GET 'index'" do
    it "should be successful" do
      auth_get 'index'
      expect(response).to be_successful
    end
  end

end

Comments

8

Some answers suggest to set request.env which is unsafe, because request can be nil and you will end up with private method env' called for nil:NilClass, especially when run single tests with rspec -e

Correct approach will be:

def http_login
  user = 'user'
  password = 'passw'
  {
    HTTP_AUTHORIZATION: ActionController::HttpAuthentication::Basic.encode_credentials(user,password)
  }
end

get 'index', nil, http_login

post 'index', {data: 'post-data'}, http_login

1 Comment

Thanks, this is the only approach that worked for my system tests using Capybara.
4

When using Rspec to test Grape APIs, the following syntax works

        post :create, {:entry => valid_attributes}, valid_session

where valid_session is

{'HTTP_AUTHORIZATION' => credentials}

and

credentials = ActionController::HttpAuthentication::Token.encode_credentials("test_access1")

Comments

4

These are great solutions for controller and request specs.

For feature tests using Capybara, here is a solution to make HTTP Basic authentication work:

spec/support/when_authenticated.rb

RSpec.shared_context 'When authenticated' do
  background do
    authenticate
  end

  def authenticate
    if page.driver.browser.respond_to?(:authorize)
      # When headless
      page.driver.browser.authorize(username, password)
    else
      # When javascript test
      visit "http://#{username}:#{password}@#{host}:#{port}/"     
     end
  end

  def username
    # Your value here. Replace with string or config location
    Rails.application.secrets.http_auth_username
  end

  def password
    # Your value here. Replace with string or config location
    Rails.application.secrets.http_auth_password
  end

  def host
    Capybara.current_session.server.host
  end

  def port
    Capybara.current_session.server.port
  end
end

Then, in your spec:

feature 'User does something' do
  include_context 'When authenticated'

  # test examples
end

2 Comments

Very helpful ! :)
Doesn't work, in Chrome, IE and Safari (at least) you can't log in http auth with a url anymore
0

My solution:

stub_request(method, url).with(
  headers: { 'Authorization' => /Basic */ }
).to_return(
  status: status, body: 'stubbed response', headers: {}
)

Use gem webmock

you can tighten verification by change:

/Basic */ -> "Basic #{Base64.strict_encode64([user,pass].join(':')).chomp}"

URL - can be a regular expression

1 Comment

I think you don't need chomp in last snippet, because strict_encode64 does not add newlines as doc says

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.