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 - coolo@suse.com + +- 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: info@opscode.com 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 = "info@opscode.com" + 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)