summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJay Mundrawala <jdmundrawala@gmail.com>2015-11-10 17:12:08 -0800
committerJay Mundrawala <jdmundrawala@gmail.com>2015-11-30 09:03:01 -0800
commit929231fb583816c76b5fc1c46a8436753848d981 (patch)
treeea7dcf7f8acb11796e1c0b903383e2e35c9c9c4d
parentd1a46e16129cc7139a773ec146ac31e24548e6b8 (diff)
downloadmixlib-authentication-929231fb583816c76b5fc1c46a8436753848d981.tar.gz
Pass digest to all the functions that will need it
-rw-r--r--Gemfile4
-rw-r--r--lib/mixlib/authentication/signatureverification.rb6
-rw-r--r--lib/mixlib/authentication/signedheaderauth.rb65
3 files changed, 63 insertions, 12 deletions
diff --git a/Gemfile b/Gemfile
index 3be9c3c..eee77c5 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,2 +1,6 @@
source "https://rubygems.org"
gemspec
+
+group(:development) do
+ gem 'pry'
+end
diff --git a/lib/mixlib/authentication/signatureverification.rb b/lib/mixlib/authentication/signatureverification.rb
index 45e4480..d73b16c 100644
--- a/lib/mixlib/authentication/signatureverification.rb
+++ b/lib/mixlib/authentication/signatureverification.rb
@@ -171,7 +171,7 @@ module Mixlib
# The request signature is based on any file attached, if any. Otherwise
# it's based on the body of the request.
- def hashed_body
+ def hashed_body(digest=Digest::SHA1)
unless @hashed_body
# TODO: tim: 2009-112-28: It'd be nice to remove this special case, and
# always hash the entire request body. In the file case it would just be
@@ -205,11 +205,11 @@ module Mixlib
# we hash the body.
if file_param
Mixlib::Authentication::Log.debug "Digesting file_param: '#{file_param.inspect}'"
- @hashed_body = digester.hash_file(Digest::SHA1, file_param)
+ @hashed_body = digester.hash_file(digest, file_param)
else
body = request.raw_post
Mixlib::Authentication::Log.debug "Digesting body: '#{body}'"
- @hashed_body = digester.hash_string(Digest::SHA1, body)
+ @hashed_body = digester.hash_string(digest, body)
end
end
@hashed_body
diff --git a/lib/mixlib/authentication/signedheaderauth.rb b/lib/mixlib/authentication/signedheaderauth.rb
index 3687603..98923f8 100644
--- a/lib/mixlib/authentication/signedheaderauth.rb
+++ b/lib/mixlib/authentication/signedheaderauth.rb
@@ -29,9 +29,15 @@ module Mixlib
module SignedHeaderAuth
NULL_ARG = Object.new
+
SUPPORTED_ALGORITHMS = ['sha1'].freeze
SUPPORTED_VERSIONS = ['1.0', '1.1'].freeze
+ ALGORITHMS_FOR_VERSION = {
+ '1.0' => ['sha1'],
+ '1.1' => ['sha1'],
+ }.freeze()
+
DEFAULT_SIGN_ALGORITHM = 'sha1'.freeze
DEFAULT_PROTO_VERSION = '1.0'.freeze
@@ -88,13 +94,14 @@ module Mixlib
# ====Parameters
# private_key<OpenSSL::PKey::RSA>:: user's RSA private key.
def sign(private_key, sign_algorithm=algorithm, sign_version=proto_version)
+ digest = validate_sign_version_digest!(sign_version, sign_algorithm)
# Our multiline hash for authorization will be encoded in multiple header
# lines - X-Ops-Authorization-1, ... (starts at 1, not 0!)
header_hash = {
"X-Ops-Sign" => "algorithm=#{sign_algorithm};version=#{sign_version};",
"X-Ops-Userid" => user_id,
"X-Ops-Timestamp" => canonical_time,
- "X-Ops-Content-Hash" => hashed_body,
+ "X-Ops-Content-Hash" => hashed_body(digest),
}
string_to_sign = canonicalize_request(sign_algorithm, sign_version)
@@ -110,6 +117,28 @@ module Mixlib
header_hash
end
+ def validate_sign_version_digest!(sign_version, sign_algorithm)
+ if ALGORITHMS_FOR_VERSION[sign_version].nil?
+ raise AuthenticationError,
+ "Unsupported version '#{sign_version}'"
+ end
+
+ if !ALGORITHMS_FOR_VERSION[sign_version].include?(sign_algorithm)
+ raise AuthenticationError,
+ "Unsupported version '#{sign_version}'"
+ end
+
+ case sign_algorithm
+ when 'sha1'
+ Digest::SHA1
+ when 'sha256'
+ Digest::SHA256
+ else
+ # This case should never happen
+ raise "Unknown algorithm #{sign_algorithm}"
+ end
+ end
+
# Build the canonicalized time based on utc & iso8601
#
# ====Parameters
@@ -128,13 +157,27 @@ module Mixlib
p.length > 1 ? p.chomp('/') : p
end
- def hashed_body
+ def hashed_body(digest=Digest::SHA1)
+ # This is weird. sign() is called with the digest type and signing
+ # version. These are also expected to be properties of the object.
+ # Hence, we're going to assume the one that is passed to sign is
+ # the correct one and needs to passed through all the functions
+ # that do any sort of digest.
+ if @hashed_body_digest != nil && @hashed_body_digest != digest
+ raise "hashed_body must always be called with the same digest"
+ else
+ @hashed_body_digest = digest
+ end
# Hash the file object if it was passed in, otherwise hash based on
# the body.
# TODO: tim 2009-12-28: It'd be nice to just remove this special case,
# always sign the entire request body, using the expanded multipart
# body in the case of a file being include.
- @hashed_body ||= (self.file && self.file.respond_to?(:read)) ? digester.hash_file(Digest::SHA1, self.file) : digester.hash_string(Digest::SHA1, self.body)
+ @hashed_body ||= if self.file && self.file.respond_to?(:read)
+ digester.hash_file(digest, self.file)
+ else
+ digester.hash_string(digest, self.body)
+ end
end
# Takes HTTP request method & headers and creates a canonical form
@@ -144,15 +187,19 @@ module Mixlib
#
#
def canonicalize_request(sign_algorithm=algorithm, sign_version=proto_version)
- unless SUPPORTED_ALGORITHMS.include?(sign_algorithm) && SUPPORTED_VERSIONS.include?(sign_version)
- raise AuthenticationError, "Bad algorithm '#{sign_algorithm}' (allowed: #{SUPPORTED_ALGORITHMS.inspect}) or version '#{sign_version}' (allowed: #{SUPPORTED_VERSIONS.inspect})"
- end
- canonical_x_ops_user_id = canonicalize_user_id(user_id, sign_version)
- "Method:#{http_method.to_s.upcase}\nHashed Path:#{digester.hash_string(Digest::SHA1, canonical_path)}\nX-Ops-Content-Hash:#{hashed_body}\nX-Ops-Timestamp:#{canonical_time}\nX-Ops-UserId:#{canonical_x_ops_user_id}"
+ digest = validate_sign_version_digest!(sign_version, sign_algorithm)
+ canonical_x_ops_user_id = canonicalize_user_id(user_id, sign_version, digest)
+ [
+ "Method:#{http_method.to_s.upcase}",
+ "Hashed Path:#{digester.hash_string(digest, canonical_path)}",
+ "X-Ops-Content-Hash:#{hashed_body(digest)}",
+ "X-Ops-Timestamp:#{canonical_time}",
+ "X-Ops-UserId:#{canonical_x_ops_user_id}"
+ ].join("\n")
end
- def canonicalize_user_id(user_id, proto_version)
+ def canonicalize_user_id(user_id, proto_version, digest=Digest::SHA1)
case proto_version
when "1.1"
digester.hash_string(Digest::SHA1, user_id)