Testing HTTP Authentication Implementation in Devise
This integration test suite validates HTTP authentication functionality in Devise, focusing on basic authentication, session storage, and custom authentication configurations. The tests ensure proper handling of authentication headers, response formats, and various authentication scenarios.
Test Coverage Overview
Implementation Analysis
Technical Details
Best Practices Demonstrated
heartcombo/devise
test/integration/http_authenticatable_test.rb
# frozen_string_literal: true
require 'test_helper'
class HttpAuthenticationTest < Devise::IntegrationTest
test 'sign in with HTTP should not run model validations' do
sign_in_as_new_user_with_http
assert_not User.validations_performed
end
test 'handles unverified requests gets rid of caches but continues signed in' do
swap ApplicationController, allow_forgery_protection: true do
create_user
post exhibit_user_url(1), headers: { "HTTP_AUTHORIZATION" => "Basic #{Base64.encode64("[email protected]:12345678")}" }
assert warden.authenticated?(:user)
assert_equal "User is authenticated", response.body
end
end
test 'sign in should authenticate with http' do
swap Devise, skip_session_storage: [] do
sign_in_as_new_user_with_http
assert_response 200
assert_match '"email":"[email protected]"', response.body
assert warden.authenticated?(:user)
get users_path(format: :json)
assert_response 200
end
end
test 'sign in should authenticate with http but not emit a cookie if skipping session storage' do
swap Devise, skip_session_storage: [:http_auth] do
sign_in_as_new_user_with_http
assert_response 200
assert_match '"email":"[email protected]"', response.body
assert warden.authenticated?(:user)
get users_path(format: :json)
assert_response 401
end
end
test 'returns a custom response with www-authenticate header on failures' do
sign_in_as_new_user_with_http("unknown")
assert_equal 401, status
assert_equal 'Basic realm="Application"', headers["WWW-Authenticate"]
end
test 'uses the request format as response content type' do
sign_in_as_new_user_with_http("unknown")
assert_equal 401, status
assert_equal "application/json; charset=utf-8", headers["Content-Type"]
assert_match '"error":"Invalid Email or password."', response.body
end
test 'returns a custom response with www-authenticate and chosen realm' do
swap Devise, http_authentication_realm: "MyApp" do
sign_in_as_new_user_with_http("unknown")
assert_equal 401, status
assert_equal 'Basic realm="MyApp"', headers["WWW-Authenticate"]
end
end
test 'sign in should authenticate with http even with specific authentication keys' do
swap Devise, authentication_keys: [:username] do
sign_in_as_new_user_with_http("usertest")
assert_response :success
assert_match '"email":"[email protected]"', response.body
assert warden.authenticated?(:user)
end
end
test 'it uses appropriate authentication_keys when configured with hash' do
swap Devise, authentication_keys: { username: false, email: false } do
sign_in_as_new_user_with_http("usertest")
assert_response :success
assert_match '"email":"[email protected]"', response.body
assert warden.authenticated?(:user)
end
end
test 'it uses the appropriate key when configured explicitly' do
swap Devise, authentication_keys: { email: false, username: false }, http_authentication_key: :username do
sign_in_as_new_user_with_http("usertest")
assert_response :success
assert_match '"email":"[email protected]"', response.body
assert warden.authenticated?(:user)
end
end
test 'test request with oauth2 header doesnt get mistaken for basic authentication' do
swap Devise, http_authenticatable: true do
add_oauth2_header
assert_equal 401, status
assert_equal 'Basic realm="Application"', headers["WWW-Authenticate"]
end
end
private
def sign_in_as_new_user_with_http(username = "[email protected]", password = "12345678")
user = create_user
get users_path(format: :json), headers: { "HTTP_AUTHORIZATION" => "Basic #{Base64.encode64("#{username}:#{password}")}" }
user
end
# Sign in with oauth2 token. This is just to test that it isn't misinterpreted as basic authentication
def add_oauth2_header
user = create_user
get users_path(format: :json), headers: { "HTTP_AUTHORIZATION" => "OAuth #{Base64.encode64("#{user.email}:12345678")}" }
end
end