Skip to content

Commit

Permalink
Add authenticate_or_request_with_http_token
Browse files Browse the repository at this point in the history
  • Loading branch information
rsamoilov committed May 7, 2024
1 parent 4f3d70a commit 8acc304
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 50 deletions.
22 changes: 22 additions & 0 deletions lib/rage/controller/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,28 @@ def authenticate_with_http_token
yield token
end
# Authenticate using an HTTP Bearer token, or otherwise render an HTTP header requesting the client to send a
# Bearer token. For the authentication to be considered successful, the block should return a non-nil value.
#
# @yield [token] token value extracted from the `Authorization` header
# @example
# before_action :authenticate
#
# def authenticate
# authenticate_or_request_with_http_token do |token|
# ApiToken.find_by(token: token)
# end
# end
def authenticate_or_request_with_http_token
authenticate_with_http_token { |token| yield(token) } || request_http_token_authentication
end
# Render an HTTP header requesting the client to send a Bearer token for authentication.
def request_http_token_authentication
headers["Www-Authenticate"] = "Token"
render plain: "HTTP Token: Access denied.", status: 401
end
if !defined?(::ActionController::Parameters)
# Get the request data. The keys inside the hash are symbols, so `params.keys` returns an array of `Symbol`.<br>
# You can also load Strong Params to have Rage automatically wrap `params` in an instance of `ActionController::Parameters`.<br>
Expand Down
142 changes: 92 additions & 50 deletions spec/controller/api/authenticate_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,9 @@
RSpec.describe RageController::API do
subject { described_class.new(env, nil) }

context "with a Bearer token" do
let(:env) { { "HTTP_AUTHORIZATION" => "Bearer my_token" } }

it "extracts the token" do
subject.authenticate_with_http_token do |token|
expect(token).to eq("my_token")
end
end

it "returns the value of the login procedure" do
value = subject.authenticate_with_http_token { :request_authenticated }
expect(value).to eq(:request_authenticated)
end

context "with a token prefix" do
let(:env) { { "HTTP_AUTHORIZATION" => "Bearer token=my_token" } }
context "#authenticate_with_http_token" do
context "with a Bearer token" do
let(:env) { { "HTTP_AUTHORIZATION" => "Bearer my_token" } }

it "extracts the token" do
subject.authenticate_with_http_token do |token|
Expand All @@ -30,25 +17,25 @@
value = subject.authenticate_with_http_token { :request_authenticated }
expect(value).to eq(:request_authenticated)
end
end
end

context "with a Token token" do
let(:env) { { "HTTP_AUTHORIZATION" => "Token my_token" } }
context "with a token prefix" do
let(:env) { { "HTTP_AUTHORIZATION" => "Bearer token=my_token" } }

it "extracts the token" do
subject.authenticate_with_http_token do |token|
expect(token).to eq("my_token")
end
end
it "extracts the token" do
subject.authenticate_with_http_token do |token|
expect(token).to eq("my_token")
end
end

it "returns the value of the login procedure" do
value = subject.authenticate_with_http_token { :request_authenticated }
expect(value).to eq(:request_authenticated)
it "returns the value of the login procedure" do
value = subject.authenticate_with_http_token { :request_authenticated }
expect(value).to eq(:request_authenticated)
end
end
end

context "with a token prefix" do
let(:env) { { "HTTP_AUTHORIZATION" => "Token token=my_token" } }
context "with a Token token" do
let(:env) { { "HTTP_AUTHORIZATION" => "Token my_token" } }

it "extracts the token" do
subject.authenticate_with_http_token do |token|
Expand All @@ -61,45 +48,100 @@
expect(value).to eq(:request_authenticated)
end

context "with quotes" do
let(:env) { { "HTTP_AUTHORIZATION" => "Token token=\"my_token\"" } }
context "with a token prefix" do
let(:env) { { "HTTP_AUTHORIZATION" => "Token token=my_token" } }

it "extracts the token" do
subject.authenticate_with_http_token do |token|
expect(token).to eq("my_token")
end
end

it "returns the value of the login procedure" do
value = subject.authenticate_with_http_token { :request_authenticated }
expect(value).to eq(:request_authenticated)
end

context "with quotes" do
let(:env) { { "HTTP_AUTHORIZATION" => "Token token=\"my_token\"" } }

it "extracts the token" do
subject.authenticate_with_http_token do |token|
expect(token).to eq("my_token")
end
end
end
end
end
end

context "with a Digest token" do
let(:env) { { "HTTP_AUTHORIZATION" => "Digest my_token" } }
context "with a Digest token" do
let(:env) { { "HTTP_AUTHORIZATION" => "Digest my_token" } }

it "doesn't extract the token" do
value = subject.authenticate_with_http_token { :request_authenticated }
expect(value).to be_nil
it "doesn't extract the token" do
value = subject.authenticate_with_http_token { :request_authenticated }
expect(value).to be_nil
end

it "doesn't call the login procedure" do
expect {
subject.authenticate_with_http_token { raise }
}.not_to raise_error
end
end

it "doesn't call the login procedure" do
expect {
subject.authenticate_with_http_token { raise }
}.not_to raise_error
context "with no token" do
let(:env) { {} }

it "returns nil" do
value = subject.authenticate_with_http_token { :request_authenticated }
expect(value).to be_nil
end

it "doesn't call the login procedure" do
expect {
subject.authenticate_with_http_token { raise }
}.not_to raise_error
end
end
end

context "with no token" do
context "#authenticate_or_request_with_http_token" do
let(:env) { {} }

it "returns nil" do
value = subject.authenticate_with_http_token { :request_authenticated }
expect(value).to be_nil
before do
expect(subject).to receive(:authenticate_with_http_token).and_yield("my_test_token")
end

it "doesn't call the login procedure" do
expect {
subject.authenticate_with_http_token { raise }
}.not_to raise_error
it "extracts the token" do
subject.authenticate_or_request_with_http_token do |token|
expect(token).to eq("my_test_token")
end
end

it "returns the value of the login procedure" do
value = subject.authenticate_or_request_with_http_token { :request_authenticated }
expect(value).to eq(:request_authenticated)
end

it "doesn't request authentication if login procedure returns non nil" do
subject.authenticate_or_request_with_http_token { :request_authenticated }
expect(subject.response.headers).not_to have_key("Www-Authenticate")
end

it "doesn't request authentication if login procedure returns nil" do
subject.authenticate_or_request_with_http_token {}
expect(subject.response.headers["Www-Authenticate"]).to eq("Token")
end
end

context "#request_http_token_authentication" do
let(:env) { {} }

it "requests token authentication" do
subject.request_http_token_authentication {}

expect(subject.response.body).to eq("HTTP Token: Access denied.")
expect(subject.response.headers["Www-Authenticate"]).to eq("Token")
end
end
end

0 comments on commit 8acc304

Please sign in to comment.