Hello community,

here is the log from the commit of package rubygem-mixlib-authentication for 
openSUSE:Factory checked in at 2016-04-28 16:52:40
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rubygem-mixlib-authentication (Old)
 and      /work/SRC/openSUSE:Factory/.rubygem-mixlib-authentication.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "rubygem-mixlib-authentication"

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/rubygem-mixlib-authentication/rubygem-mixlib-authentication.changes
      2014-10-23 14:20:53.000000000 +0200
+++ 
/work/SRC/openSUSE:Factory/.rubygem-mixlib-authentication.new/rubygem-mixlib-authentication.changes
 2016-04-28 16:52:55.000000000 +0200
@@ -1,0 +2,6 @@
+Wed Jan 20 05:48:02 UTC 2016 - [email protected]
+
+- updated to version 1.4.0
+  no changelog found
+
+-------------------------------------------------------------------

Old:
----
  mixlib-authentication-1.3.0.gem

New:
----
  gem2rpm.yml
  mixlib-authentication-1.4.0.gem

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ rubygem-mixlib-authentication.spec ++++++
--- /var/tmp/diff_new_pack.QyIRuS/_old  2016-04-28 16:52:56.000000000 +0200
+++ /var/tmp/diff_new_pack.QyIRuS/_new  2016-04-28 16:52:56.000000000 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package rubygem-mixlib-authentication
 #
-# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
+# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -16,8 +16,15 @@
 #
 
 
+#
+# This file was generated with a gem2rpm.yml and not just plain gem2rpm.
+# All sections marked as MANUAL, license headers, summaries and descriptions
+# can be maintained in that file. Please consult this file before editing any
+# of those fields
+#
+
 Name:           rubygem-mixlib-authentication
-Version:        1.3.0
+Version:        1.4.0
 Release:        0
 %define mod_name mixlib-authentication
 %define mod_full_name %{mod_name}-%{version}
@@ -27,6 +34,7 @@
 BuildRequires:  ruby-macros >= 5
 Url:            http://www.opscode.com
 Source:         http://rubygems.org/gems/%{mod_full_name}.gem
+Source1:        gem2rpm.yml
 Summary:        Mixes in simple per-request authentication
 License:        Apache-2.0
 Group:          Development/Languages/Ruby

++++++ gem2rpm.yml ++++++
# ---
# ## used by gem2rpm
# :summary: this is a custom summary
# ## used by gem2rpm
# :description: |-
#   this is a custom description
#
#   it can be multiline
# ## used by gem2rpm
# :license: MIT or Ruby
# ## used by gem2rpm and gem_packages
# :version_suffix: -x_y
# ## used by gem2rpm and gem_packages
# :disable_docs: true
# ## used by gem2rpm
# :disable_automatic_rdoc_dep: true
# ## used by gem2rpm
# :preamble: |-
#   BuildRequires: foobar
#   Requires: foobar
# ## used by gem2rpm
# :patches:
#   foo.patch: -p1
#   bar.patch: 
# ## used by gem2rpm
:sources:
# - foo.desktop
# - bar.desktop
# :gem_install_args: '....'
# ## used by gem2rpm
# :pre_install: |-
#   %if 0%{?use_system_libev}
#   export USE_VENDORED_LIBEV="no"
#   %endif
# ## used by gem2rpm
# :post_install: |-
#   # delete custom files here or do other fancy stuff
#   install -D -m 0644 %{S:1} %{buildroot}%{_bindir}/gem2rpm-opensuse
# ## used by gem2rpm
# :testsuite_command: |-
#   (pushd %{buildroot}%{gem_base}/gems/%{mod_full_name} && rake test)
# ## used by gem2rpm
# :filelist: |-
#   /usr/bin/gem2rpm-opensuse
# ## used by gem2rpm
# :scripts:
#   :post: |-
#     /bin/echo foo
# ## used by gem_packages
# :main:
#   :preamble: |-
#     Requires: util-linux
#     Recommends: pwgen
#   :filelist: |-
#     /usr/bin/gem2rpm-opensuse
# ## used by gem_packages
# :custom:
#   apache:
#     :preamble: |-
#       Requires: .....
#     :filelist: |-
#       /etc/apache2/conf.d/passenger.conf
#     :summary: Custom summary is optional
#     :description: |-
#       Custom description is optional
#
#       bar
#     :post: |-
#       /bin/echo foo
#
++++++ mixlib-authentication-1.3.0.gem -> mixlib-authentication-1.4.0.gem ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Gemfile new/Gemfile
--- old/Gemfile 1970-01-01 01:00:00.000000000 +0100
+++ new/Gemfile 2016-01-19 18:37:56.000000000 +0100
@@ -0,0 +1,6 @@
+source "https://rubygems.org";
+gemspec
+
+group(:development) do
+  gem 'pry'
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Rakefile new/Rakefile
--- old/Rakefile        1970-01-01 01:00:00.000000000 +0100
+++ new/Rakefile        2016-01-19 18:37:56.000000000 +0100
@@ -1,5 +1,5 @@
 require 'rubygems'
-require 'rake/gempackagetask'
+require 'rubygems/package_task'
 require 'rubygems/specification'
 require 'date'
 require 'rspec/core/rake_task'
@@ -16,12 +16,12 @@
 desc "Run specs"
 RSpec::Core::RakeTask.new do |t|
   t.pattern = 'spec/**/*_spec.rb'
-  t.rspec_opts = %w(-fs --color)
+  t.rspec_opts = %w(--format documentation --color)
 end
 
 gem_spec = eval(File.read("mixlib-authentication.gemspec"))
 
-Rake::GemPackageTask.new(gem_spec) do |pkg|
+Gem::PackageTask.new(gem_spec) do |pkg|
   pkg.gem_spec = gem_spec
 end
 
Files old/checksums.yaml.gz and new/checksums.yaml.gz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/mixlib/authentication/digester.rb 
new/lib/mixlib/authentication/digester.rb
--- old/lib/mixlib/authentication/digester.rb   1970-01-01 01:00:00.000000000 
+0100
+++ new/lib/mixlib/authentication/digester.rb   2016-01-19 18:37:56.000000000 
+0100
@@ -17,15 +17,15 @@
 #
 
 require 'mixlib/authentication'
+require 'openssl'
 
 module Mixlib
   module Authentication
     class Digester
-      
       class << self
-        
-        def hash_file(f)
-          digester = Digest::SHA1.new
+
+        def hash_file(f, digest=OpenSSL::Digest::SHA1)
+          digester = digest.new
           buf = ""
           while f.read(16384, buf)
             digester.update buf
@@ -34,15 +34,15 @@
         end
 
         # Digests a string, base64's and chomps the end
-        # 
+        #
         # ====Parameters
-        # 
-        def hash_string(str)
-          ::Base64.encode64(Digest::SHA1.digest(str)).chomp
+        #
+        def hash_string(str, digest=OpenSSL::Digest::SHA1)
+          ::Base64.encode64(digest.digest(str)).chomp
         end
-        
+
       end
-      
+
     end
   end
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/lib/mixlib/authentication/http_authentication_request.rb 
new/lib/mixlib/authentication/http_authentication_request.rb
--- old/lib/mixlib/authentication/http_authentication_request.rb        
1970-01-01 01:00:00.000000000 +0100
+++ new/lib/mixlib/authentication/http_authentication_request.rb        
2016-01-19 18:37:56.000000000 +0100
@@ -64,6 +64,10 @@
         headers[:x_ops_content_hash].chomp
       end
 
+      def server_api_version
+        (headers[:x_ops_server_api_version] || 
DEFAULT_SERVER_API_VERSION).chomp
+      end
+
       def request_signature
         unless @request_signature
           @request_signature = headers.find_all { |h| h[0].to_s =~ 
/^x_ops_authorization_/ }.sort { |x,y| x.to_s <=> y.to_s}.map { |i| i[1] 
}.join("\n")
@@ -80,8 +84,6 @@
           raise MissingAuthenticationHeader, "missing required authentication 
header(s) '#{missing_headers.join("', '")}'"
         end
       end
-
-
     end
   end
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/mixlib/authentication/signatureverification.rb 
new/lib/mixlib/authentication/signatureverification.rb
--- old/lib/mixlib/authentication/signatureverification.rb      1970-01-01 
01:00:00.000000000 +0100
+++ new/lib/mixlib/authentication/signatureverification.rb      2016-01-19 
18:37:56.000000000 +0100
@@ -48,6 +48,8 @@
 
       def_delegator :@auth_request, :request
 
+      def_delegator :@auth_request, :server_api_version
+
       include Mixlib::Authentication::SignedHeaderAuth
 
       def initialize(request=nil)
@@ -138,8 +140,15 @@
 
       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!(algorithm, 
version)
+                             @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:")
@@ -171,7 +180,7 @@
 
       # 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 +214,11 @@
           # we hash the body.
           if file_param
             Mixlib::Authentication::Log.debug "Digesting file_param: 
'#{file_param.inspect}'"
-            @hashed_body = digester.hash_file(file_param)
+            @hashed_body = digester.hash_file(file_param, digest)
           else
             body = request.raw_post
             Mixlib::Authentication::Log.debug "Digesting body: '#{body}'"
-            @hashed_body = digester.hash_string(body)
+            @hashed_body = digester.hash_string(body, digest)
           end
         end
         @hashed_body
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/mixlib/authentication/signedheaderauth.rb 
new/lib/mixlib/authentication/signedheaderauth.rb
--- old/lib/mixlib/authentication/signedheaderauth.rb   1970-01-01 
01:00:00.000000000 +0100
+++ new/lib/mixlib/authentication/signedheaderauth.rb   2016-01-19 
18:37:56.000000000 +0100
@@ -19,7 +19,7 @@
 
 require 'time'
 require 'base64'
-require 'digest/sha1'
+require 'openssl/digest'
 require 'mixlib/authentication'
 require 'mixlib/authentication/digester'
 
@@ -29,13 +29,21 @@
     module SignedHeaderAuth
 
       NULL_ARG = Object.new
+
+      ALGORITHM_FOR_VERSION = {
+        '1.0' => 'sha1',
+        '1.1' => 'sha1',
+        '1.3' => 'sha256',
+      }.freeze()
+
+      # Use of SUPPORTED_ALGORITHMS and SUPPORTED_VERSIONS is deprecated. Use
+      # ALGORITHM_FOR_VERSION instead
       SUPPORTED_ALGORITHMS = ['sha1'].freeze
       SUPPORTED_VERSIONS = ['1.0', '1.1'].freeze
 
       DEFAULT_SIGN_ALGORITHM = 'sha1'.freeze
       DEFAULT_PROTO_VERSION = '1.0'.freeze
 
-
       # === signing_object
       # This is the intended interface for signing requests with the
       # Opscode/Chef signed header protocol. This wraps the constructor for a
@@ -65,11 +73,20 @@
       # These parameters are accepted but not used in the computation of the 
signature.
       # * `:host`: The host part of the URI
       def self.signing_object(args={ })
-        SigningObject.new(args[:http_method], args[:path], args[:body], 
args[:host], args[:timestamp], args[:user_id], args[:file], 
args[:proto_version])
+        SigningObject.new(args[:http_method],
+                          args[:path],
+                          args[:body],
+                          args[:host],
+                          args[:timestamp],
+                          args[:user_id],
+                          args[:file],
+                          args[:proto_version],
+                          args[:headers]
+                         )
       end
 
       def algorithm
-        DEFAULT_SIGN_ALGORITHM
+        ALGORITHM_FOR_VERSION[proto_version] || DEFAULT_SIGN_ALGORITHM
       end
 
       def proto_version
@@ -81,28 +98,50 @@
       # ====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_algorithm, sign_version)
         # 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)
-        signature = 
Base64.encode64(private_key.private_encrypt(string_to_sign)).chomp
+        signature = Base64.encode64(do_sign(private_key, digest, 
sign_algorithm, sign_version)).chomp
         signature_lines = signature.split(/\n/)
         signature_lines.each_index do |idx|
           key = "X-Ops-Authorization-#{idx + 1}"
           header_hash[key] = signature_lines[idx]
         end
 
-        Mixlib::Authentication::Log.debug "String to sign: 
'#{string_to_sign}'\nHeader hash: #{header_hash.inspect}"
+        Mixlib::Authentication::Log.debug "Header hash: #{header_hash.inspect}"
 
         header_hash
       end
 
+      def validate_sign_version_digest!(sign_algorithm, sign_version)
+        if ALGORITHM_FOR_VERSION[sign_version].nil?
+          raise AuthenticationError,
+            "Unsupported version '#{sign_version}'"
+        end
+
+        if ALGORITHM_FOR_VERSION[sign_version] != sign_algorithm
+          raise AuthenticationError,
+            "Unsupported algorithm #{sign_algorithm} for version 
'#{sign_version}'"
+        end
+
+        case sign_algorithm
+        when 'sha1'
+          OpenSSL::Digest::SHA1
+        when 'sha256'
+          OpenSSL::Digest::SHA256
+        else
+          # This case should never happen
+          raise "Unknown algorithm #{sign_algorithm}"
+        end
+      end
+
       # Build the canonicalized time based on utc & iso8601
       #
       # ====Parameters
@@ -121,13 +160,27 @@
         p.length > 1 ? p.chomp('/') : p
       end
 
-      def hashed_body
+      def hashed_body(digest=OpenSSL::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(self.file) : digester.hash_string(self.body)
+        @hashed_body ||= if self.file && self.file.respond_to?(:read)
+                           digester.hash_file(self.file, digest)
+                         else
+                           digester.hash_string(self.body, digest)
+                         end
       end
 
       # Takes HTTP request method & headers and creates a canonical form
@@ -137,21 +190,37 @@
       #
       #
       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})"
+        digest = validate_sign_version_digest!(sign_algorithm, sign_version)
+        canonical_x_ops_user_id = canonicalize_user_id(user_id, sign_version, 
digest)
+        case sign_version
+        when "1.3"
+          [
+            "Method:#{http_method.to_s.upcase}",
+            "Path:#{canonical_path}",
+            "X-Ops-Content-Hash:#{hashed_body(digest)}",
+            "X-Ops-Sign:version=#{sign_version}",
+            "X-Ops-Timestamp:#{canonical_time}",
+            "X-Ops-UserId:#{canonical_x_ops_user_id}",
+            "X-Ops-Server-API-Version:#{server_api_version}",
+          ].join("\n")
+        else
+          [
+            "Method:#{http_method.to_s.upcase}",
+            "Hashed Path:#{digester.hash_string(canonical_path, digest)}",
+            "X-Ops-Content-Hash:#{hashed_body(digest)}",
+            "X-Ops-Timestamp:#{canonical_time}",
+            "X-Ops-UserId:#{canonical_x_ops_user_id}"
+          ].join("\n")
         end
-
-        canonical_x_ops_user_id = canonicalize_user_id(user_id, sign_version)
-        "Method:#{http_method.to_s.upcase}\nHashed 
Path:#{digester.hash_string(canonical_path)}\nX-Ops-Content-Hash:#{hashed_body}\nX-Ops-Timestamp:#{canonical_time}\nX-Ops-UserId:#{canonical_x_ops_user_id}"
       end
 
-      def canonicalize_user_id(user_id, proto_version)
+      def canonicalize_user_id(user_id, proto_version, 
digest=OpenSSL::Digest::SHA1)
         case proto_version
         when "1.1"
-          digester.hash_string(user_id)
-        when "1.0"
-          user_id
+          # and 1.2 if that ever gets implemented
+          digester.hash_string(user_id, digest)
         else
+          # versions 1.0 and 1.3
           user_id
         end
       end
@@ -174,6 +243,18 @@
         Mixlib::Authentication::Digester
       end
 
+      # private
+      def do_sign(private_key, digest, sign_algorithm, sign_version)
+        string_to_sign = canonicalize_request(sign_algorithm, sign_version)
+        Mixlib::Authentication::Log.debug "String to sign: '#{string_to_sign}'"
+        case sign_version
+        when '1.3'
+          private_key.sign(digest.new, string_to_sign)
+        else
+          private_key.private_encrypt(string_to_sign)
+        end
+      end
+
       private :canonical_time, :canonical_path, :parse_signing_description, 
:digester, :canonicalize_user_id
 
     end
@@ -182,13 +263,25 @@
     # A Struct-based value object that contains the necessary information to
     # generate a request signature. `SignedHeaderAuth.signing_object()`
     # provides a more convenient interface to the constructor.
-    class SigningObject < Struct.new(:http_method, :path, :body, :host, 
:timestamp, :user_id, :file, :proto_version)
+    class SigningObject < Struct.new(:http_method, :path, :body, :host,
+                                     :timestamp, :user_id, :file, 
:proto_version,
+                                     :headers)
       include SignedHeaderAuth
 
       def proto_version
         (self[:proto_version] or DEFAULT_PROTO_VERSION).to_s
       end
-    end
 
+      def server_api_version
+        key = (self[:headers] || {}).keys.select do |k|
+          k.downcase == 'x-ops-server-api-version'
+        end.first
+        if key
+          self[:headers][key]
+        else
+          DEFAULT_SERVER_API_VERSION
+        end
+      end
+    end
   end
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/mixlib/authentication/version.rb 
new/lib/mixlib/authentication/version.rb
--- old/lib/mixlib/authentication/version.rb    1970-01-01 01:00:00.000000000 
+0100
+++ new/lib/mixlib/authentication/version.rb    2016-01-19 18:37:56.000000000 
+0100
@@ -0,0 +1,21 @@
+# Copyright:: Copyright (c) 2010-2015 Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+module Mixlib
+  module Authentication
+    VERSION = '1.4.0'
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/mixlib/authentication.rb 
new/lib/mixlib/authentication.rb
--- old/lib/mixlib/authentication.rb    1970-01-01 01:00:00.000000000 +0100
+++ new/lib/mixlib/authentication.rb    2016-01-19 18:37:56.000000000 +0100
@@ -20,6 +20,8 @@
 
 module Mixlib
   module Authentication
+    DEFAULT_SERVER_API_VERSION = '0'
+
     class AuthenticationError < StandardError
     end
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/metadata new/metadata
--- old/metadata        1970-01-01 01:00:00.000000000 +0100
+++ new/metadata        2016-01-19 18:37:56.000000000 +0100
@@ -1,91 +1,131 @@
---- !ruby/object:Gem::Specification 
+--- !ruby/object:Gem::Specification
 name: mixlib-authentication
-version: !ruby/object:Gem::Version 
-  hash: 27
-  prerelease: 
-  segments: 
-  - 1
-  - 3
-  - 0
-  version: 1.3.0
+version: !ruby/object:Gem::Version
+  version: 1.4.0
 platform: ruby
-authors: 
+authors:
 - Opscode, Inc.
 autorequire: 
 bindir: bin
 cert_chain: []
-
-date: 2012-08-06 00:00:00 Z
-dependencies: 
-- !ruby/object:Gem::Dependency 
+date: 2016-01-19 00:00:00.000000000 Z
+dependencies:
+- !ruby/object:Gem::Dependency
   name: mixlib-log
+  requirement: !ruby/object:Gem::Requirement
+    requirements:
+    - - ">="
+      - !ruby/object:Gem::Version
+        version: '0'
+  type: :runtime
   prerelease: false
-  requirement: &id001 !ruby/object:Gem::Requirement 
-    none: false
-    requirements: 
+  version_requirements: !ruby/object:Gem::Requirement
+    requirements:
     - - ">="
-      - !ruby/object:Gem::Version 
-        hash: 3
-        segments: 
-        - 0
-        version: "0"
+      - !ruby/object:Gem::Version
+        version: '0'
+- !ruby/object:Gem::Dependency
+  name: rspec-core
+  requirement: !ruby/object:Gem::Requirement
+    requirements:
+    - - "~>"
+      - !ruby/object:Gem::Version
+        version: '3.2'
   type: :runtime
-  version_requirements: *id001
+  prerelease: false
+  version_requirements: !ruby/object:Gem::Requirement
+    requirements:
+    - - "~>"
+      - !ruby/object:Gem::Version
+        version: '3.2'
+- !ruby/object:Gem::Dependency
+  name: rspec-expectations
+  requirement: !ruby/object:Gem::Requirement
+    requirements:
+    - - "~>"
+      - !ruby/object:Gem::Version
+        version: '3.2'
+  type: :runtime
+  prerelease: false
+  version_requirements: !ruby/object:Gem::Requirement
+    requirements:
+    - - "~>"
+      - !ruby/object:Gem::Version
+        version: '3.2'
+- !ruby/object:Gem::Dependency
+  name: rspec-mocks
+  requirement: !ruby/object:Gem::Requirement
+    requirements:
+    - - "~>"
+      - !ruby/object:Gem::Version
+        version: '3.2'
+  type: :runtime
+  prerelease: false
+  version_requirements: !ruby/object:Gem::Requirement
+    requirements:
+    - - "~>"
+      - !ruby/object:Gem::Version
+        version: '3.2'
+- !ruby/object:Gem::Dependency
+  name: rake
+  requirement: !ruby/object:Gem::Requirement
+    requirements:
+    - - "~>"
+      - !ruby/object:Gem::Version
+        version: '10.4'
+  type: :development
+  prerelease: false
+  version_requirements: !ruby/object:Gem::Requirement
+    requirements:
+    - - "~>"
+      - !ruby/object:Gem::Version
+        version: '10.4'
 description: Mixes in simple per-request authentication
 email: [email protected]
 executables: []
-
 extensions: []
-
-extra_rdoc_files: 
+extra_rdoc_files:
 - README.rdoc
 - LICENSE
 - NOTICE
-files: 
+files:
+- Gemfile
 - LICENSE
+- NOTICE
 - README.rdoc
 - Rakefile
-- NOTICE
-- lib/mixlib/authentication/signedheaderauth.rb
+- lib/mixlib/authentication.rb
 - lib/mixlib/authentication/digester.rb
 - lib/mixlib/authentication/http_authentication_request.rb
 - lib/mixlib/authentication/signatureverification.rb
-- lib/mixlib/authentication.rb
-- spec/spec_helper.rb
-- spec/mixlib/authentication/mixlib_authentication_spec.rb
+- lib/mixlib/authentication/signedheaderauth.rb
+- lib/mixlib/authentication/version.rb
+- mixlib-authentication.gemspec
+- spec/mixlib/authentication/digester_spec.rb
 - spec/mixlib/authentication/http_authentication_request_spec.rb
+- spec/mixlib/authentication/mixlib_authentication_spec.rb
+- spec/spec_helper.rb
 homepage: http://www.opscode.com
 licenses: []
-
+metadata: {}
 post_install_message: 
 rdoc_options: []
-
-require_paths: 
+require_paths:
 - lib
-required_ruby_version: !ruby/object:Gem::Requirement 
-  none: false
-  requirements: 
+required_ruby_version: !ruby/object:Gem::Requirement
+  requirements:
   - - ">="
-    - !ruby/object:Gem::Version 
-      hash: 3
-      segments: 
-      - 0
-      version: "0"
-required_rubygems_version: !ruby/object:Gem::Requirement 
-  none: false
-  requirements: 
+    - !ruby/object:Gem::Version
+      version: '0'
+required_rubygems_version: !ruby/object:Gem::Requirement
+  requirements:
   - - ">="
-    - !ruby/object:Gem::Version 
-      hash: 3
-      segments: 
-      - 0
-      version: "0"
+    - !ruby/object:Gem::Version
+      version: '0'
 requirements: []
-
 rubyforge_project: 
-rubygems_version: 1.8.15
+rubygems_version: 2.5.0
 signing_key: 
-specification_version: 3
+specification_version: 4
 summary: Mixes in simple per-request authentication
 test_files: []
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mixlib-authentication.gemspec 
new/mixlib-authentication.gemspec
--- old/mixlib-authentication.gemspec   1970-01-01 01:00:00.000000000 +0100
+++ new/mixlib-authentication.gemspec   2016-01-19 18:37:56.000000000 +0100
@@ -0,0 +1,25 @@
+$:.unshift(File.dirname(__FILE__) + '/lib')
+require 'mixlib/authentication/version'
+
+Gem::Specification.new do |s|
+  s.name = "mixlib-authentication"
+  s.version = Mixlib::Authentication::VERSION
+  s.platform = Gem::Platform::RUBY
+  s.has_rdoc = true
+  s.extra_rdoc_files = ["README.rdoc", "LICENSE", 'NOTICE']
+  s.summary = "Mixes in simple per-request authentication"
+  s.description = s.summary
+  s.author = "Opscode, Inc."
+  s.email = "[email protected]"
+  s.homepage = "http://www.opscode.com";
+
+  # Uncomment this to add a dependency
+  s.add_dependency "mixlib-log"
+
+  s.require_path = 'lib'
+  s.files = %w(LICENSE README.rdoc Gemfile Rakefile NOTICE) + 
Dir.glob("*.gemspec") +
+      Dir.glob("{lib,spec}/**/*", File::FNM_DOTMATCH).reject {|f| 
File.directory?(f) }
+
+  %w(rspec-core rspec-expectations rspec-mocks).each { |gem| s.add_dependency 
gem, "~> 3.2" }
+  s.add_development_dependency "rake", "~> 10.4"
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spec/mixlib/authentication/digester_spec.rb 
new/spec/mixlib/authentication/digester_spec.rb
--- old/spec/mixlib/authentication/digester_spec.rb     1970-01-01 
01:00:00.000000000 +0100
+++ new/spec/mixlib/authentication/digester_spec.rb     2016-01-19 
18:37:56.000000000 +0100
@@ -0,0 +1,24 @@
+require 'mixlib/authentication/digester'
+
+describe Mixlib::Authentication::Digester do
+  context 'backcompat' do
+    # The digester API should really have been private,
+    # however oc-chef-pedant uses it.
+    let(:test_string) { 'hello' }
+    let(:test_string_checksum) { 'qvTGHdzF6KLavt4PO0gs2a6pQ00=' }
+
+    describe '#hash_file' do
+      it 'should default to use SHA1' do
+        expect(described_class.hash_file(StringIO.new(test_string))).to(
+          eq(test_string_checksum))
+      end
+    end
+
+    describe '#hash_string' do
+      it 'should default to use SHA1' do
+        expect(described_class.hash_string(test_string)).to(
+          eq(test_string_checksum))
+      end
+    end
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/spec/mixlib/authentication/http_authentication_request_spec.rb 
new/spec/mixlib/authentication/http_authentication_request_spec.rb
--- old/spec/mixlib/authentication/http_authentication_request_spec.rb  
1970-01-01 01:00:00.000000000 +0100
+++ new/spec/mixlib/authentication/http_authentication_request_spec.rb  
2016-01-19 18:37:56.000000000 +0100
@@ -76,41 +76,41 @@
                 
:x_ops_authorization_4=>"IWPZDHSiPcw//AYNgW1CCDptt+UFuaFYbtqZegcBd2n/jzcWODA7zL4KWEUy",
                 
:x_ops_authorization_5=>"9q4rlh/+1tBReg60QdsmDRsw/cdO1GZrKtuCwbuD4+nbRdVBKv72rqHX9cu0",
                 
:x_ops_authorization_6=>"utju9jzczCyB+sSAQWrxSsXB/b8vV2qs0l4VD2ML+w=="}
-    @http_authentication_request.headers.should == expected
+    expect(@http_authentication_request.headers).to eq(expected)
   end
 
   it "raises an error when not all required headers are given" do
     @merb_headers.delete("HTTP_X_OPS_SIGN")
     exception = Mixlib::Authentication::MissingAuthenticationHeader
-    lambda{ Mixlib::Authentication::HTTPAuthenticationRequest.new(@request) 
}.should raise_error(exception)
+    expect{ Mixlib::Authentication::HTTPAuthenticationRequest.new(@request) 
}.to raise_error(exception)
   end
 
   it "extracts the path from the request" do
-    @http_authentication_request.path.should == '/nodes'
+    expect(@http_authentication_request.path).to eq('/nodes')
   end
 
   it "extracts the request method from the request" do
-    @http_authentication_request.http_method.should == 'POST'
+    expect(@http_authentication_request.http_method).to eq('POST')
   end
 
   it "extracts the signing description from the request headers" do
-    @http_authentication_request.signing_description.should == 'version=1.0'
+    expect(@http_authentication_request.signing_description).to 
eq('version=1.0')
   end
 
   it "extracts the user_id from the request headers" do
-    @http_authentication_request.user_id.should == 'spec-user'
+    expect(@http_authentication_request.user_id).to eq('spec-user')
   end
 
   it "extracts the timestamp from the request headers" do
-    @http_authentication_request.timestamp.should == "2009-01-01T12:00:00Z"
+    expect(@http_authentication_request.timestamp).to 
eq("2009-01-01T12:00:00Z")
   end
 
   it "extracts the host from the request headers" do
-    @http_authentication_request.host.should == "127.0.0.1"
+    expect(@http_authentication_request.host).to eq("127.0.0.1")
   end
 
   it "extracts the content hash from the request headers" do
-    @http_authentication_request.content_hash.should == 
"DFteJZPVv6WKdQmMqZUQUumUyRs="
+    expect(@http_authentication_request.content_hash).to 
eq("DFteJZPVv6WKdQmMqZUQUumUyRs=")
   end
 
   it "rebuilds the request signature from the headers" do
@@ -122,7 +122,11 @@
 9q4rlh/+1tBReg60QdsmDRsw/cdO1GZrKtuCwbuD4+nbRdVBKv72rqHX9cu0
 utju9jzczCyB+sSAQWrxSsXB/b8vV2qs0l4VD2ML+w==
 SIG
-    @http_authentication_request.request_signature.should == expected.chomp
+    expect(@http_authentication_request.request_signature).to 
eq(expected.chomp)
+  end
+
+  it "defaults to server api version 0" do
+    expect(@http_authentication_request.server_api_version).to eq('0')
   end
 
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/spec/mixlib/authentication/mixlib_authentication_spec.rb 
new/spec/mixlib/authentication/mixlib_authentication_spec.rb
--- old/spec/mixlib/authentication/mixlib_authentication_spec.rb        
1970-01-01 01:00:00.000000000 +0100
+++ new/spec/mixlib/authentication/mixlib_authentication_spec.rb        
2016-01-19 18:37:56.000000000 +0100
@@ -72,52 +72,65 @@
 
   it "should generate the correct string to sign and signature, version 1.0 
(default)" do
 
-    V1_0_SIGNING_OBJECT.canonicalize_request.should == V1_0_CANONICAL_REQUEST
+    expect(V1_0_SIGNING_OBJECT.canonicalize_request).to 
eq(V1_0_CANONICAL_REQUEST)
 
     # If you need to regenerate the constants in this test spec, print out
     # the results of res.inspect and copy them as appropriate into the
     # the constants in this file.
-    V1_0_SIGNING_OBJECT.sign(PRIVATE_KEY).should == EXPECTED_SIGN_RESULT_V1_0
+    expect(V1_0_SIGNING_OBJECT.sign(PRIVATE_KEY)).to 
eq(EXPECTED_SIGN_RESULT_V1_0)
   end
 
   it "should generate the correct string to sign and signature, version 1.1" do
-    V1_1_SIGNING_OBJECT.proto_version.should == "1.1"
-    V1_1_SIGNING_OBJECT.canonicalize_request.should == V1_1_CANONICAL_REQUEST
+    expect(V1_1_SIGNING_OBJECT.proto_version).to eq("1.1")
+    expect(V1_1_SIGNING_OBJECT.canonicalize_request).to 
eq(V1_1_CANONICAL_REQUEST)
 
     # If you need to regenerate the constants in this test spec, print out
     # the results of res.inspect and copy them as appropriate into the
     # the constants in this file.
-    V1_1_SIGNING_OBJECT.sign(PRIVATE_KEY).should == EXPECTED_SIGN_RESULT_V1_1
+    expect(V1_1_SIGNING_OBJECT.sign(PRIVATE_KEY)).to 
eq(EXPECTED_SIGN_RESULT_V1_1)
   end
 
+  it "should generate the correct string to sign and signature for version 1.3 
with SHA256" do
+    expect(V1_3_SHA256_SIGNING_OBJECT.proto_version).to eq("1.3")
+    expect(V1_3_SHA256_SIGNING_OBJECT.algorithm).to eq("sha256")
+    expect(V1_3_SHA256_SIGNING_OBJECT.server_api_version).to eq("1")
+    expect(V1_3_SHA256_SIGNING_OBJECT.canonicalize_request).to 
eq(V1_3_SHA256_CANONICAL_REQUEST)
+
+    # If you need to regenerate the constants in this test spec, print out
+    # the results of res.inspect and copy them as appropriate into the
+    # the constants in this file.
+    expect(V1_3_SHA256_SIGNING_OBJECT.sign(PRIVATE_KEY)).to 
eq(EXPECTED_SIGN_RESULT_V1_3_SHA256)
+  end
+
+
   it "should generate the correct string to sign and signature for non-default 
proto version when used as a mixin" do
     algorithm = 'sha1'
     version = '1.1'
 
     V1_1_SIGNING_OBJECT.proto_version = "1.0"
-    V1_1_SIGNING_OBJECT.proto_version.should == "1.0"
-    V1_1_SIGNING_OBJECT.canonicalize_request(algorithm, version).should == 
V1_1_CANONICAL_REQUEST
+    expect(V1_1_SIGNING_OBJECT.proto_version).to eq("1.0")
+    expect(V1_1_SIGNING_OBJECT.canonicalize_request(algorithm, version)).to 
eq(V1_1_CANONICAL_REQUEST)
 
     # If you need to regenerate the constants in this test spec, print out
     # the results of res.inspect and copy them as appropriate into the
     # the constants in this file.
-    V1_1_SIGNING_OBJECT.sign(PRIVATE_KEY, algorithm, version).should == 
EXPECTED_SIGN_RESULT_V1_1
+    expect(V1_1_SIGNING_OBJECT.sign(PRIVATE_KEY, algorithm, version)).to 
eq(EXPECTED_SIGN_RESULT_V1_1)
   end
 
   it "should not choke when signing a request for a long user id with version 
1.1" do
-    lambda { LONG_SIGNING_OBJECT.sign(PRIVATE_KEY, 'sha1', '1.1') }.should_not 
raise_error
+    expect { LONG_SIGNING_OBJECT.sign(PRIVATE_KEY, 'sha1', '1.1') }.not_to 
raise_error
   end
 
   it "should choke when signing a request for a long user id with version 1.0" 
do
-    lambda { LONG_SIGNING_OBJECT.sign(PRIVATE_KEY, 'sha1', '1.0') }.should 
raise_error
+    expect { LONG_SIGNING_OBJECT.sign(PRIVATE_KEY, 'sha1', '1.0') }.to 
raise_error(OpenSSL::PKey::RSAError)
   end
 
   it "should choke when signing a request with a bad version" do
-    lambda { V1_1_SIGNING_OBJECT.sign(PRIVATE_KEY, 'sha1', 'poo') }.should 
raise_error
+    expect { V1_1_SIGNING_OBJECT.sign(PRIVATE_KEY, 'sha1', 'poo') }.to 
raise_error(Mixlib::Authentication::AuthenticationError)
   end
 
   it "should choke when signing a request with a bad algorithm" do
-    lambda { V1_1_SIGNING_OBJECT.sign(PRIVATE_KEY, 'sha_poo', '1.1') }.should 
raise_error
+    expect { V1_1_SIGNING_OBJECT.sign(PRIVATE_KEY, 'sha_poo', '1.1') }.to 
raise_error(Mixlib::Authentication::AuthenticationError)
   end
 
 end
@@ -128,17 +141,30 @@
     @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 }
 
     mock_request = MockRequest.new(PATH, request_params, MERB_HEADERS_V1_1, "")
-    Time.should_receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
+    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)
-    res.should_not be_nil
+    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
@@ -146,29 +172,38 @@
     request_params["tarball"] = MockFile.new
 
     mock_request = MockRequest.new(PATH, request_params, 
PASSENGER_HEADERS_V1_0, "")
-    Time.should_receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
+    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)
-    res.should_not be_nil
+    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_SHA256, 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 - Merb" do
+  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)
-    Time.should_receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
+    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)
-    res.should_not be_nil
+    expect(res).not_to be_nil
   end
 
   it "should authenticate a normal (post body) request from a v1.0 client - 
Merb" do
     mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, 
MERB_HEADERS_V1_0, BODY)
-    Time.should_receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
+    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)
-    res.should_not be_nil
+    expect(res).not_to be_nil
   end
 
   it "shouldn't authenticate if an Authorization header is missing" do
@@ -176,15 +211,16 @@
     headers.delete("HTTP_X_OPS_SIGN")
 
     mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, headers, BODY)
-    Time.stub!(:now).and_return(TIMESTAMP_OBJ)
+    allow(Time).to receive(:now).and_return(TIMESTAMP_OBJ)
+    #Time.stub!(:now).and_return(TIMESTAMP_OBJ)
 
     auth_req = Mixlib::Authentication::SignatureVerification.new
-    lambda {auth_req.authenticate_user_request(mock_request, 
@user_private_key)}.should 
raise_error(Mixlib::Authentication::AuthenticationError)
+    expect {auth_req.authenticate_user_request(mock_request, 
@user_private_key)}.to raise_error(Mixlib::Authentication::AuthenticationError)
 
-    auth_req.should_not be_a_valid_request
-    auth_req.should_not be_a_valid_timestamp
-    auth_req.should_not be_a_valid_signature
-    auth_req.should_not be_a_valid_content_hash
+    expect(auth_req).not_to be_a_valid_request
+    expect(auth_req).not_to be_a_valid_timestamp
+    expect(auth_req).not_to be_a_valid_signature
+    expect(auth_req).not_to be_a_valid_content_hash
   end
 
 
@@ -193,52 +229,67 @@
     headers["HTTP_X_OPS_CONTENT_HASH"] += "_"
 
     mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, headers, BODY)
-    Time.should_receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
+    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)
-    res.should be_nil
+    expect(res).to be_nil
 
-    auth_req.should_not be_a_valid_request
-    auth_req.should be_a_valid_timestamp
-    auth_req.should be_a_valid_signature
-    auth_req.should_not be_a_valid_content_hash
+    expect(auth_req).not_to be_a_valid_request
+    expect(auth_req).to be_a_valid_timestamp
+    expect(auth_req).to be_a_valid_signature
+    expect(auth_req).not_to be_a_valid_content_hash
   end
 
   it "shouldn't authenticate if the timestamp is not within bounds" do
     mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, 
MERB_HEADERS_V1_1, BODY)
-    Time.should_receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ - 1000)
+    expect(Time).to receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ - 
1000)
 
     auth_req = Mixlib::Authentication::SignatureVerification.new
     res = auth_req.authenticate_user_request(mock_request, @user_private_key)
-    res.should be_nil
-    auth_req.should_not be_a_valid_request
-    auth_req.should_not be_a_valid_timestamp
-    auth_req.should be_a_valid_signature
-    auth_req.should be_a_valid_content_hash
+    expect(res).to be_nil
+    expect(auth_req).not_to be_a_valid_request
+    expect(auth_req).not_to be_a_valid_timestamp
+    expect(auth_req).to be_a_valid_signature
+    expect(auth_req).to be_a_valid_content_hash
   end
 
   it "shouldn't authenticate if the signature is wrong" do
     headers =  MERB_HEADERS_V1_1.dup
     headers["HTTP_X_OPS_AUTHORIZATION_1"] = "epicfail"
     mock_request = MockRequest.new(PATH, MERB_REQUEST_PARAMS, headers, BODY)
-    Time.should_receive(:now).at_least(:once).and_return(TIMESTAMP_OBJ)
+    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)
-    res.should be_nil
-    auth_req.should_not be_a_valid_request
-    auth_req.should_not be_a_valid_signature
-    auth_req.should be_a_valid_timestamp
-    auth_req.should be_a_valid_content_hash
+    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"
 DIGESTED_USER_ID = Base64.encode64(Digest::SHA1.new.digest(USER_ID)).chomp
 BODY = "Spec Body"
 HASHED_BODY = "DFteJZPVv6WKdQmMqZUQUumUyRs=" # 
Base64.encode64(Digest::SHA1.digest("Spec Body")).chomp
+HASHED_BODY_SHA256 = "hDlKNZhIhgso3Fs0S0pZwJ0xyBWtR1RBaeHs1DrzOho="
 TIMESTAMP_ISO8601 = "2009-01-01T12:00:00Z"
 TIMESTAMP_OBJ = Time.parse("Thu Jan 01 12:00:00 -0000 2009")
 PATH = "/organizations/clownco"
@@ -263,6 +314,20 @@
   :proto_version => 1.1
 }
 
+V1_3_ARGS_SHA256 = {
+  :body => BODY,
+  :user_id => USER_ID,
+  :http_method => :post,
+  :timestamp => TIMESTAMP_ISO8601,    # fixed timestamp so we get back the 
same answer each time.
+  :file => MockFile.new,
+  :path => PATH,
+  :proto_version => '1.3',
+  :headers => {
+    'X-OpS-SeRvEr-ApI-VerSiOn' => '1'
+  }
+  # This defaults to sha256
+}
+
 LONG_PATH_LONG_USER_ARGS = {
   :body => BODY,
   :user_id => "A" * 200,
@@ -276,6 +341,8 @@
 
 # Content hash is ???TODO
 X_OPS_CONTENT_HASH = "DFteJZPVv6WKdQmMqZUQUumUyRs="
+X_OPS_CONTENT_HASH_SHA256 = "hDlKNZhIhgso3Fs0S0pZwJ0xyBWtR1RBaeHs1DrzOho="
+
 X_OPS_AUTHORIZATION_LINES_V1_0 = [
 "jVHrNniWzpbez/eGWjFnO6lINRIuKOg40ZTIQudcFe47Z9e/HvrszfVXlKG4",
 "NMzYZgyooSvU85qkIUmKuCqgG2AIlvYa2Q/2ctrMhoaHhLOCWWoqYNMaEqPc",
@@ -294,6 +361,14 @@
 "FDlbAG7H8Dmvo+wBxmtNkszhzbBnEYtuwQqT8nM/8A=="
 ]
 
+X_OPS_AUTHORIZATION_LINES_V1_3_SHA256 = [
+  "FZOmXAyOBAZQV/uw188iBljBJXOm+m8xQ/8KTGLkgGwZNcRFxk1m953XjE3W",
+  "VGy1dFT76KeaNWmPCNtDmprfH2na5UZFtfLIKrPv7xm80V+lzEzTd9WBwsfP",
+  "42dZ9N+V9I5SVfcL/lWrrlpdybfceJC5jOcP5tzfJXWUITwb6Z3Erg3DU3Uh",
+  "H9h9E0qWlYGqmiNCVrBnpe6Si1gU/Jl+rXlRSNbLJ4GlArAPuL976iTYJTzE",
+  "MmbLUIm3JRYi00Yb01IUCCKdI90vUq1HHNtlTEu93YZfQaJwRxXlGkCNwIJe",
+  "fy49QzaCIEu1XiOx5Jn+4GmkrZch/RrK9VzQWXgs+w=="
+]
 # We expect Mixlib::Authentication::SignedHeaderAuth#sign to return this
 # if passed the BODY above, based on version
 
@@ -323,6 +398,19 @@
   "X-Ops-Timestamp"=>TIMESTAMP_ISO8601
 }
 
+EXPECTED_SIGN_RESULT_V1_3_SHA256 = {
+  "X-Ops-Content-Hash"=>X_OPS_CONTENT_HASH_SHA256,
+  "X-Ops-Userid"=>USER_ID,
+  "X-Ops-Sign"=>"algorithm=sha256;version=1.3;",
+  "X-Ops-Authorization-1"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[0],
+  "X-Ops-Authorization-2"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[1],
+  "X-Ops-Authorization-3"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[2],
+  "X-Ops-Authorization-4"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[3],
+  "X-Ops-Authorization-5"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[4],
+  "X-Ops-Authorization-6"=>X_OPS_AUTHORIZATION_LINES_V1_3_SHA256[5],
+  "X-Ops-Timestamp"=>TIMESTAMP_ISO8601
+}
+
 OTHER_HEADERS = {
   # An arbitrary sampling of non-HTTP_* headers are in here to
   # exercise that code path.
@@ -339,6 +427,23 @@
   "organization_id"=>"local-test-org", 
"requesting_actor_id"=>REQUESTING_ACTOR_ID,
 }
 
+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_SERVER_API_VERSION"=>"1",
+  "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.
@@ -477,6 +582,18 @@
 EOS
 V1_1_CANONICAL_REQUEST = V1_1_CANONICAL_REQUEST_DATA.chomp
 
+V1_3_SHA256_CANONICAL_REQUEST_DATA = <<EOS
+Method:POST
+Path:#{PATH}
+X-Ops-Content-Hash:#{HASHED_BODY_SHA256}
+X-Ops-Sign:version=1.3
+X-Ops-Timestamp:#{TIMESTAMP_ISO8601}
+X-Ops-UserId:#{USER_ID}
+X-Ops-Server-API-Version:1
+EOS
+V1_3_SHA256_CANONICAL_REQUEST = V1_3_SHA256_CANONICAL_REQUEST_DATA.chomp
+
+V1_3_SHA256_SIGNING_OBJECT = 
Mixlib::Authentication::SignedHeaderAuth.signing_object(V1_3_ARGS_SHA256)
 V1_1_SIGNING_OBJECT = 
Mixlib::Authentication::SignedHeaderAuth.signing_object(V1_1_ARGS)
 V1_0_SIGNING_OBJECT = 
Mixlib::Authentication::SignedHeaderAuth.signing_object(V1_0_ARGS)
 LONG_SIGNING_OBJECT = 
Mixlib::Authentication::SignedHeaderAuth.signing_object(LONG_PATH_LONG_USER_ARGS)


Reply via email to