Azure / azure-storage-ruby

Microsoft Azure Storage Library for Ruby
http://azure.github.io/azure-storage-ruby/
82 stars 158 forks source link

Tokens generated for blobs ending with '.' get a signature mismatch #191

Open ci opened 3 years ago

ci commented 3 years ago

Calling Azure::Storage::Common::Core::Auth::SharedAccessSignature#generate_service_sas_token with a path ending in with one or multiple . generates the signature using the . as expected, however Azure reports that the string used doesn't contain the trailing slashes.

We've ran into this in https://gitlab.com/gitlab-org/gitlab/-/issues/332027 - the specific example from there is:

Azure::Storage::Common::Core::Auth::SharedAccessSignature.alias_method(:old_method, :generate_service_sas_token)
Azure::Storage::Common::Core::Auth::SharedAccessSignature.define_method(:generate_service_sas_token) do |relative_path, params|
  pp [relative_path, params]
  self.old_method(path2, params)
end

local_file.url(expire_at)

["uploads/@hashed/d4/73/d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35/4842ef328558dd3e3b430308259541b1/test.",
{:service=>"b",
 :resource=>"b",
 :permissions=>"r",
 :expiry=>"2021-05-27T11:04:28Z",
 :protocol=>"https"}]
=> 'https://[..]'

However accessing the URL returns a AuthenticationFailed error with a signature mismatch, because apparently the backend uses the filename without any trailing periods to verify:

Signature did not match. String to sign used was
r\n\n2021-05-27T10:58:10Z\n/blob/catalinrepro/uploads/@hashed/d4/73/d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35/4842ef328558dd3e3b430308259541b1/test\n\n\nhttps\n2018-11-09\nb\n\n\n\n\n\n

Compared to the one we use to sign:

Azure::Storage::Common::Core::Auth::SharedAccessSignature.define_method(:generate_service_sas_token) do |*args|
  binding.irb
  self.old_method(*args)
end

irb(main):042:0> local_file.url(expire_at)
irb(#<Azure::Storage::Common::Core::Auth::SharedAccessSignature:0x00007f1013e39890>):001:0> signable_string_for_service('blob', args[0], args[1])
=> "r\n\n2021-05-27T11:29:28Z\n/blob/catalinrepro/uploads/@hashed/d4/73/d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35/4842ef328558dd3e3b430308259541b1/test.\n\n\nhttps\n2018-11-09\nb\n\n\n\n\n\n"

The Azure storage docs for blob names do mention avoiding this scenario:

Avoid blob names that end with a dot (.), a forward slash (/), or a sequence or combination of the two. No path segments should end with a dot (.).

Should Azure::Storage::Common::Core::Auth::SharedAccessSignature#generate_service_sas_token maybe have logic to strip trailing periods on the path if service_type is b?