summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJay Mundrawala <jdmundrawala@gmail.com>2015-11-16 14:03:19 -0800
committerJay Mundrawala <jdmundrawala@gmail.com>2015-11-30 09:03:01 -0800
commita19e5cbb85b591ce3289b06c467b8ab21cbba85e (patch)
tree3682d8f0ae6272d830c47ee7cf509b921dea929f
parent6ebe6bbdabd0c4da634b26deb00cafb7fa636bcc (diff)
downloadmixlib-authentication-a19e5cbb85b591ce3289b06c467b8ab21cbba85e.tar.gz
Added signature verification for signing version 1.3
-rw-r--r--lib/mixlib/authentication/signatureverification.rb11
-rw-r--r--spec/mixlib/authentication/mixlib_authentication_spec.rb109
2 files changed, 116 insertions, 4 deletions
diff --git a/lib/mixlib/authentication/signatureverification.rb b/lib/mixlib/authentication/signatureverification.rb
index d73b16c..ff43664 100644
--- a/lib/mixlib/authentication/signatureverification.rb
+++ b/lib/mixlib/authentication/signatureverification.rb
@@ -138,8 +138,15 @@ module Mixlib
def verify_signature(algorithm, version)
candidate_block = canonicalize_request(algorithm, version)
- request_decrypted_block = @user_secret.public_decrypt(Base64.decode64(request_signature))
- @valid_signature = (request_decrypted_block == candidate_block)
+ signature = Base64.decode64(request_signature)
+ @valid_signature = case version
+ when '1.3'
+ digest = validate_sign_version_digest!(version, algorithm)
+ @user_secret.verify(digest.new, signature, candidate_block)
+ else
+ request_decrypted_block = @user_secret.public_decrypt(signature)
+ (request_decrypted_block == candidate_block)
+ end
# Keep the debug messages lined up so it's easy to scan them
Mixlib::Authentication::Log.debug("Verifying request signature:")
diff --git a/spec/mixlib/authentication/mixlib_authentication_spec.rb b/spec/mixlib/authentication/mixlib_authentication_spec.rb
index 1a18faa..abc5503 100644
--- a/spec/mixlib/authentication/mixlib_authentication_spec.rb
+++ b/spec/mixlib/authentication/mixlib_authentication_spec.rb
@@ -150,7 +150,7 @@ describe "Mixlib::Authentication::SignatureVerification" do
@user_private_key = PRIVATE_KEY
end
- it "should authenticate a File-containing request - Merb" do
+ it "should authenticate a File-containing request V1.1 - Merb" do
request_params = MERB_REQUEST_PARAMS.clone
request_params["file"] =
{ "size"=>MockFile.length, "content_type"=>"application/octet-stream", "filename"=>"zsh.tar.gz", "tempfile"=>MockFile.new }
@@ -163,6 +163,32 @@ describe "Mixlib::Authentication::SignatureVerification" do
expect(res).not_to be_nil
end
+ it "should authenticate a File-containing request V1.3 SHA1 - Merb" do
+ request_params = MERB_REQUEST_PARAMS.clone
+ request_params["file"] =
+ { "size"=>MockFile.length, "content_type"=>"application/octet-stream", "filename"=>"zsh.tar.gz", "tempfile"=>MockFile.new }
+
+ mock_request = MockRequest.new(PATH, request_params, MERB_HEADERS_V1_3_SHA1, "")
+ expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
+
+ service = Mixlib::Authentication::SignatureVerification.new
+ res = service.authenticate_user_request(mock_request, @user_private_key)
+ expect(res).not_to be_nil
+ end
+
+ it "should authenticate a File-containing request V1.3 SHA256 - Merb" do
+ request_params = MERB_REQUEST_PARAMS.clone
+ request_params["file"] =
+ { "size"=>MockFile.length, "content_type"=>"application/octet-stream", "filename"=>"zsh.tar.gz", "tempfile"=>MockFile.new }
+
+ mock_request = MockRequest.new(PATH, request_params, MERB_HEADERS_V1_3_SHA256, "")
+ expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
+
+ service = Mixlib::Authentication::SignatureVerification.new
+ res = service.authenticate_user_request(mock_request, @user_private_key)
+ expect(res).not_to be_nil
+ end
+
it "should authenticate a File-containing request from a v1.0 client - Passenger" do
request_params = PASSENGER_REQUEST_PARAMS.clone
request_params["tarball"] = MockFile.new
@@ -175,7 +201,25 @@ describe "Mixlib::Authentication::SignatureVerification" do
expect(res).not_to be_nil
end
- it "should authenticate a normal (post body) request - Merb" do
+ it "should authenticate a normal (post body) request v1.3 SHA1 - Merb" do
+ mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, MERB_HEADERS_V1_3_SHA1, BODY)
+ expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
+
+ service = Mixlib::Authentication::SignatureVerification.new
+ res = service.authenticate_user_request(mock_request, @user_private_key)
+ expect(res).not_to be_nil
+ end
+
+ it "should authenticate a normal (post body) request v1.3 SHA256 - Merb" do
+ mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, MERB_HEADERS_V1_3_SHA1, BODY)
+ expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
+
+ service = Mixlib::Authentication::SignatureVerification.new
+ res = service.authenticate_user_request(mock_request, @user_private_key)
+ expect(res).not_to be_nil
+ end
+
+ it "should authenticate a normal (post body) request v1.1 - Merb" do
mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, MERB_HEADERS_V1_1, BODY)
expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
@@ -256,6 +300,35 @@ describe "Mixlib::Authentication::SignatureVerification" do
expect(auth_req).to be_a_valid_content_hash
end
+ it "shouldn't authenticate if the signature is wrong for v1.3 SHA1" do
+ headers = MERB_HEADERS_V1_3_SHA1.dup
+ headers["HTTP_X_OPS_AUTHORIZATION_1"] = "epicfail"
+ mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, headers, BODY)
+ expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
+
+ auth_req = Mixlib::Authentication::SignatureVerification.new
+ res = auth_req.authenticate_user_request(mock_request, @user_private_key)
+ expect(res).to be_nil
+ expect(auth_req).not_to be_a_valid_request
+ expect(auth_req).not_to be_a_valid_signature
+ expect(auth_req).to be_a_valid_timestamp
+ expect(auth_req).to be_a_valid_content_hash
+ end
+
+ it "shouldn't authenticate if the signature is wrong for v1.3 SHA256" do
+ headers = MERB_HEADERS_V1_3_SHA256.dup
+ headers["HTTP_X_OPS_AUTHORIZATION_1"] = "epicfail"
+ mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, headers, BODY)
+ expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
+
+ auth_req = Mixlib::Authentication::SignatureVerification.new
+ res = auth_req.authenticate_user_request(mock_request, @user_private_key)
+ expect(res).to be_nil
+ expect(auth_req).not_to be_a_valid_request
+ expect(auth_req).not_to be_a_valid_signature
+ expect(auth_req).to be_a_valid_timestamp
+ expect(auth_req).to be_a_valid_content_hash
+ end
end
USER_ID = "spec-user"
@@ -432,6 +505,38 @@ MERB_REQUEST_PARAMS = {
"organization_id"=>"local-test-org", "requesting_actor_id"=>REQUESTING_ACTOR_ID,
}
+MERB_HEADERS_V1_3_SHA1 = {
+ # These are used by signatureverification.
+ "HTTP_HOST"=>"127.0.0.1",
+ "HTTP_X_OPS_SIGN"=>"algorithm=sha1;version=1.3;",
+ "HTTP_X_OPS_REQUESTID"=>"127.0.0.1 1258566194.85386",
+ "HTTP_X_OPS_TIMESTAMP"=>TIMESTAMP_ISO8601,
+ "HTTP_X_OPS_CONTENT_HASH"=>X_OPS_CONTENT_HASH,
+ "HTTP_X_OPS_USERID"=>USER_ID,
+ "HTTP_X_OPS_AUTHORIZATION_1"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA1[0],
+ "HTTP_X_OPS_AUTHORIZATION_2"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA1[1],
+ "HTTP_X_OPS_AUTHORIZATION_3"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA1[2],
+ "HTTP_X_OPS_AUTHORIZATION_4"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA1[3],
+ "HTTP_X_OPS_AUTHORIZATION_5"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA1[4],
+ "HTTP_X_OPS_AUTHORIZATION_6"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA1[5],
+}.merge(OTHER_HEADERS)
+
+MERB_HEADERS_V1_3_SHA256 = {
+ # These are used by signatureverification.
+ "HTTP_HOST"=>"127.0.0.1",
+ "HTTP_X_OPS_SIGN"=>"algorithm=sha256;version=1.3;",
+ "HTTP_X_OPS_REQUESTID"=>"127.0.0.1 1258566194.85386",
+ "HTTP_X_OPS_TIMESTAMP"=>TIMESTAMP_ISO8601,
+ "HTTP_X_OPS_CONTENT_HASH"=>X_OPS_CONTENT_HASH_SHA256,
+ "HTTP_X_OPS_USERID"=>USER_ID,
+ "HTTP_X_OPS_AUTHORIZATION_1"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[0],
+ "HTTP_X_OPS_AUTHORIZATION_2"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[1],
+ "HTTP_X_OPS_AUTHORIZATION_3"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[2],
+ "HTTP_X_OPS_AUTHORIZATION_4"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[3],
+ "HTTP_X_OPS_AUTHORIZATION_5"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[4],
+ "HTTP_X_OPS_AUTHORIZATION_6"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[5],
+}.merge(OTHER_HEADERS)
+
# Tis is what will be in request.env for the Merb case.
MERB_HEADERS_V1_1 = {
# These are used by signatureverification.