Skip to content

Commit

Permalink
Disable auth rebuilding on redirects
Browse files Browse the repository at this point in the history
In newer versions of requests, the Authorization
header is removed if a redirect occurs where the new
host does not equal the original host.  In the case
of S3 redirects, we know that this is ok so we need
to add back the old behavior.  We do this by subclassing
the session and overriding its rebuild_auth() class to
be a no-op.  That is, it just keeps the auth from the
original request.
  • Loading branch information
jamesls committed Feb 5, 2015
1 parent 0ed96b7 commit 0c9790d
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 6 deletions.
14 changes: 8 additions & 6 deletions botocore/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
from botocore.vendored.requests.sessions import Session
from botocore.vendored.requests.utils import get_environ_proxies

import botocore.response
import botocore.exceptions
from botocore.exceptions import UnknownEndpointError
from botocore.awsrequest import AWSRequest
from botocore.compat import urljoin
Expand Down Expand Up @@ -66,6 +64,11 @@ def convert_to_response_dict(http_response, operation_model):
return response_dict


class PreserveAuthSession(Session):
def rebuild_auth(self, prepared_request, response):
pass


class Endpoint(object):
"""
Represents an endpoint for a particular service in a specific
Expand All @@ -89,7 +92,7 @@ def __init__(self, region_name, host, user_agent,
if proxies is None:
proxies = {}
self.proxies = proxies
self.http_session = Session()
self.http_session = PreserveAuthSession()
self.timeout = timeout
self._lock = threading.Lock()
if response_parser_factory is None:
Expand All @@ -111,9 +114,8 @@ def create_request(self, params, operation_model=None):
endpoint_prefix=self._endpoint_prefix,
op_name=operation_model.name)
self._event_emitter.emit(event_name, request=request,
operation_name=operation_model.name)
prepared_request = self.prepare_request(
request)
operation_name=operation_model.name)
prepared_request = self.prepare_request(request)
return prepared_request

def _create_request_object(self, request_dict):
Expand Down
38 changes: 38 additions & 0 deletions tests/unit/test_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
from botocore.vendored.requests.models import Response

from botocore.compat import six
from botocore.awsrequest import AWSRequest
from botocore.endpoint import get_endpoint, Endpoint, DEFAULT_TIMEOUT
from botocore.endpoint import EndpointCreator
from botocore.endpoint import PreserveAuthSession
from botocore.auth import SigV4Auth
from botocore.session import Session
from botocore.exceptions import UnknownServiceStyle
Expand Down Expand Up @@ -318,3 +320,39 @@ def test_endpoint_resolver_uses_credential_scope(self):
Mock(), 'user-agent')
endpoint = creator.create_endpoint(self.service_model)
self.assertEqual(endpoint.region_name, 'us-east-1')


class TestAWSSession(unittest.TestCase):
def test_auth_header_preserved_from_s3_redirects(self):
request = AWSRequest()
request.url = 'https://bucket.s3.amazonaws.com/'
request.method = 'GET'
request.headers['Authorization'] = 'original auth header'
prepared_request = request.prepare()

fake_response = Mock()
fake_response.headers = {
'location': 'https://bucket.s3-us-west-2.amazonaws.com'}
fake_response.url = request.url
fake_response.status_code = 307
fake_response.is_permanent_redirect = False
# This line is needed to disable the cookie handling
# code in requests.
fake_response.raw._original_response = None

success_response = Mock()
success_response.raw._original_response = None
success_response.is_redirect = False
success_response.status_code = 200
session = PreserveAuthSession()
session.send = Mock(return_value=success_response)

responses = list(session.resolve_redirects(
fake_response, prepared_request, stream=False))

redirected_request = session.send.call_args[0][0]
# The Authorization header for the newly sent request should
# still have our original Authorization header.
self.assertEqual(
redirected_request.headers['Authorization'],
'original auth header')

0 comments on commit 0c9790d

Please sign in to comment.