added tests for aws sigv4

This commit is contained in:
HoneyryderChuck 2021-01-19 10:00:40 +00:00
parent a1942d5a6a
commit f415d1b66b
3 changed files with 152 additions and 0 deletions

View File

@ -0,0 +1,51 @@
# frozen_string_literal: true
module HTTPX
module Plugins
#
# This plugin adds AWS Sigv4 authentication.
#
# https://gitlab.com/honeyryderchuck/httpx/wikis/AWS-SigV4
#
module AWSSigV4
class Signer
def initialize(options = {})
@unsigned_headers = options.fetch(:unsigned_headers, [])
end
def sign!(request); end
end
class << self
def extra_options(options)
Class.new(options.class) do
def_option(:sigv4_signer) do |signer|
if signer.is_a?(Signer)
signer
else
Jar.new(signer)
end
end
end.new(options)
end
def load_dependencies(klass)
klass.plugin(:authentication)
end
end
module InstanceMethods
def build_request(*, _)
request = super
return request unless @options.sigv4_signer && !request.headers.key?("authorization")
@options.sigv4_signer.sign!(request)
request
end
end
end
register_plugin :aws_sigv4, AWSSigV4
end
end

97
test/aws_sigv4_test.rb Normal file
View File

@ -0,0 +1,97 @@
# frozen_string_literal: true
require_relative "support/http_helpers"
class HTTPXAwsSigv4Test < Minitest::Test
include ResponseHelpers
def test_plugin_aws_sigv4_canonical_query
r1 = sigv4_session.build_request(:get, "http://domain.com?b=c&a=b")
assert r1.canonical_query == "a=b&b=c"
r2 = sigv4_session.build_request(:get, "http://domain.com?a=c&a=b")
assert r2.canonical_query == "a=b&a=c"
r3 = sigv4_session.build_request(:get, "http://domain.com?a=b&a=b")
assert r3.canonical_query == "a=b&a=b"
r4 = sigv4_session.build_request(:get, "http://domain.com?b&a=b")
assert r4.canonical_query == "a=b&b"
end
def test_plugin_aws_sigv4_x_amz_date
request = sigv4_session.build_request(:get, "http://domain.com")
# x-amz-date
assert request.headers.key?("x-amz-date")
amz_date = Time.parse(request.headers["x-amz-date"])
assert_in_delta(amz_date, Time.now.utc, 3)
# date already set
date = Time.now.utc - 60 * 60 * 24
date_amz = date.strftime("%Y%m%dT%H%M%SZ")
x_date_request = sigv4_session.build_request(:get, "http://domain.com", headers: { "x-amz-date" => date_amz })
verify_header(x_date_request.headers, "x-amz-date", date_amz)
end
def test_plugin_aws_sigv4_x_amz_security_token
request = sigv4_session.build_request(:get, "http://domain.com")
assert !request.headers.key?("x-amz-security-token")
tk_request = sigv4_session(security_token: "token").build_request(:get, "http://domain.com")
assert tk_request.headers.key?("x-amz-security-token")
verify_header(tk_request.headers, "x-amz-security-token", "token")
# already set
token_request = sigv4_session(security_token: "token").build_request(:get, "http://domain.com",
headers: { "x-amz-security-token" => "TOKEN" })
verify_header(token_request.headers, "x-amz-security-token", "TOKEN")
end
def test_plugin_aws_sigv4_x_amz_content_sha256
request = sigv4_session.build_request(:get, "http://domain.com", body: "abcd")
assert request.headers["x-amz-content-sha256"] == Digest::SHA256.hexdigest("abcd")
# already set
hashed_request = sigv4_session.build_request(:get, "http://domain.com", headers: { "x-amz-content-sha256" => "HASH" })
verify_header(hashed_request.headers, "x-amz-content-sha256", "HASH")
end
def test_plugin_aws_sigv4_x_amz_content_sha256_stringio
request = sigv4_session.build_request(:get, "http://domain.com", body: StringIO.new("abcd"))
assert request.headers["x-amz-content-sha256"] == Digest::SHA256.hexdigest("abcd")
end
def test_plugin_aws_sigv4_x_amz_content_sha256_file
body = Tempfile.new("httpx")
body.write("abcd")
body.flush
request = sigv4_session.build_request(:get, "http://domain.com", body: body)
assert request.headers["x-amz-content-sha256"] == Digest::SHA256.hexdigest("abcd")
ensure
if body
body.close
body.unlink
end
end
def test_plugin_aws_sigv4_authorization_unsigned_headers
request = sigv4_session(service: "SERVICE", region: "REGION", unsigned_headers: ["content-length"])
.build_request(:put, "http://domain.com", headers: {
"Host" => "domain.com",
"Foo" => "foo",
"Bar" => "bar bar",
"Bar2" => '"bar bar"',
"Content-Length" => 9,
"X-Amz-Date" => "20120101T112233Z",
},
body: StringIO.new("http-body"))
assert request.headers["authorization"] == "" \
"AWS4-HMAC-SHA256 Credential=akid/20120101/REGION/SERVICE/aws4_request, " \
"SignedHeaders=bar;bar2;foo;host;x-amz-content-sha256;x-amz-date, " \
"Signature=4a7d3e06d1950eb64a3daa1becaa8ba030d9099858516cb2fa4533fab4e8937d"
end
private
def sigv4_session(**options)
HTTPX.plugin(:aws_sigv4).aws_sigv4_authentication(service: "s3", region: "eu-west-1", username: "akid", password: "secret", **options)
end
end

View File

@ -3,6 +3,8 @@
module Requests
module Plugins
module Authentication
# Basic Auth
def test_plugin_basic_authentication
no_auth_response = HTTPX.get(basic_auth_uri)
verify_status(no_auth_response, 401)
@ -20,6 +22,8 @@ module Requests
verify_status(invalid_response, 401)
end
# Digest
def test_plugin_digest_authentication
session = HTTPX.plugin(:digest_authentication).with_headers("cookie" => "fake=fake_value")
response = session.digest_authentication(user, pass).get(digest_auth_uri)