Skip to content

Commit

Permalink
Merge pull request #61 from mithrandi/20-fix-signing-encoding
Browse files Browse the repository at this point in the history
Fix signing encoding handling.

Author: mithrandi
Reviewer: exarkun

S3 object names now have correct encoding applied to them for the purposes of calculating an authentication signature.
  • Loading branch information
exarkun authored May 15, 2017
2 parents 247dda5 + b76c611 commit 8127b45
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 6 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
_trial_temp/
*.egg-info/
.testrepository
.venv-*
_trial_temp/
2 changes: 1 addition & 1 deletion txaws/_auth_v4.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ def serialize(self):
request.
@rtype: L{str}
"""
return '\n'.join(attr.astuple(self))
return b'\n'.join(attr.astuple(self))

def hash(self):
"""
Expand Down
15 changes: 14 additions & 1 deletion txaws/client/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,17 @@ def get_encoded_url(self):
return b"%(scheme)s://%(host)s:%(port)d%(path)s%(query)s" % params


def _get_joined_path(ctx):
"""
@type ctx: L{_URLContext}
@param ctx: A URL context.
@return: The path component, un-urlencoded, but joined by slashes.
@rtype: L{bytes}
"""
return b'/' + b'/'.join(seg.encode('utf-8') for seg in ctx.path)


@attr.s
class RequestDetails(object):
"""
Expand Down Expand Up @@ -412,7 +423,9 @@ def _canonical_request(self, headers):
return _auth_v4._CanonicalRequest.from_request_components(
method=self._details.method,
url=(
self._details.url_context.get_encoded_path() +
# We need to pass an unfortunate version of the path here: see
# https://github.com/twisted/txaws/issues/70
_get_joined_path(self._details.url_context) +
b"?" +
self._details.url_context.get_encoded_query()
),
Expand Down
1 change: 1 addition & 0 deletions txaws/newsfragments/20.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
txaws now correctly signs requests with paths that require urlencoding.
8 changes: 5 additions & 3 deletions txaws/testing/s3.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@ def get_bucket(self, bucket):
pieces = self._state.buckets[bucket]
except KeyError:
return fail(S3Error("<nosuchbucket/>", 400))
return pieces["listing"]
return succeed(pieces["listing"])

@_rate_limited
def get_bucket_location(self, bucket):
return b""
return succeed(b"")

@_rate_limited
def put_object(
Expand Down Expand Up @@ -144,11 +144,12 @@ def put_object(

def _store_object(self, bucket, obj, data):
self._state.objects[bucket, obj] = data
return succeed(None)


@_rate_limited
def get_object(self, bucket, object_name):
return self._state.objects[bucket, object_name]
return succeed(self._state.objects[bucket, object_name])

@_rate_limited
def delete_object(self, bucket, object_name):
Expand All @@ -158,6 +159,7 @@ def delete_object(self, bucket, object_name):
if item.key == object_name:
contents.remove(item)
break
return succeed(None)


@attr.s
Expand Down
28 changes: 28 additions & 0 deletions txaws/testing/s3_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,32 @@ def test_put_object_body_producer(self):
self.assertEqual(object_data, retrieved)


@inlineCallbacks
def test_object_encoded_chars(self):
"""
C{get_object} and C{put_object} succeed with an object name that
requires encoding.
"""
bucket_name = str(uuid4())
object_names = [
b'object:with:colons',
b'object with spaces',
u'\N{SNOWMAN}'.encode('utf-8'),
]
object_data = b'some text'
object_type = b'application/x-txaws-integration-testing'

client = get_client(self)
yield client.create_bucket(bucket_name)
for object_name in object_names:
yield client.put_object(
bucket_name, object_name, object_data,
content_type=object_type)
retrieved = yield gatherResults(
[client.get_object(bucket_name, object_name)
for object_name in object_names],
consumeErrors=True)
self.assertEqual([object_data] * len(object_names), retrieved)


return S3IntegrationTests

0 comments on commit 8127b45

Please sign in to comment.