Repository: boto/botocore
Pull request #414 (2014-12-16 22:49:56)

Refactor to decouple auth/endpoints and unify events.
Refactor to decouple auth/endpoints and unify events.

This change decouples authentication from the `Endpoint` class and
introduces a new `RequestSigner` class to handle the signing of
requests. It fires the following events:

* `choose-signer.service.operation`: Allow overriding signature version
* `before-sign.service.operation`: Allow mutating request before signing

This also fixes the EC2 encrypted snapshot copying customization to work
with clients, as well as implements the changes needed for boto/boto3#39
(signature version overrides) and boto/boto3#30 (anonymous operations)
for the Botocore client interface.

The previous `before-auth` event is now removed, and all handlers that
previously used an endpoint's `.auth` property are now switched to
use the request signer. This may require changes upstream in the AWS CLI
as it is a potentially breaking change.

Additionally, the event emitter now supports an `emit_until_response`
method that will **stop** processing handlers once the first non-`None`
response has been received.

Tests have been updated/moved/removed accordingly.

cc @jamesls, @kyleknap 

coveralls: 
[![Coverage Status](https://coveralls.io/builds/1757030/badge)](https://coveralls.io/builds/1757030)

Coverage decreased (-0.21%) when pulling **f4a52b04e209e11108330de854c16ef21a77e8d4 on danielgtaylor:auth-refactor** into **fa91d1bc7f08705aaf211a90c4fceb4242ed1e46 on boto:develop**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/1757625/badge)](https://coveralls.io/builds/1757625)

Coverage increased (+0.22%) when pulling **a0398fc098cb8fdc4946c378c239ad3fc018ad4f on danielgtaylor:auth-refactor** into **fa91d1bc7f08705aaf211a90c4fceb4242ed1e46 on boto:develop**.

kyleknap: Looks good overall. My comments came from questions in how the code works in certain places and edge cases that I was not sure if were caught or not.
jamesls: Overall I think there were only a few questions/concerns I had:

1. The issue with recreating some of the endpoint dependencies in the operation.call method
2. The RequestSigner needing the scoped_config when this can be handled outside of that object (I'm ok if the signature_override from config is no longer a handler)
3.  The request signer being sent in an event which appears to be only to support the copy snapshot handler.  I'd rather not complicate that event just to support a single specific handler.  Perhaps there's another way of writing the handler that keeps everything simple.  Maybe there's another event besides `before-call` we can use.
4. The monkey patch.  I'd really recommend exploring alternatives.  Thinking out loud: 1) Just share handlers for signing (ensure it's thread safe) 2) Make the RequestSigner not tied to a specific service 3) Sign the request directly in operation (maybe don't use make_request) 4) Clone the event handlers when we create a service object, etc.  I haven't really thought through each of those options, but I think we should avoid monkey patching if we can avoid it.

Overall though, I think this is definitely heading in the right direction.
coveralls: 
[![Coverage Status](https://coveralls.io/builds/1789829/badge)](https://coveralls.io/builds/1789829)

Coverage increased (+0.03%) to 94.13% when pulling **ab9e4634cd3111e1e933742ed0a0d30b11dc4498 on danielgtaylor:auth-refactor** into **fa91d1bc7f08705aaf211a90c4fceb4242ed1e46 on boto:develop**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/1789976/badge)](https://coveralls.io/builds/1789976)

Coverage increased (+0.05%) to 94.16% when pulling **6754f711e90635f251e7545e6f39dcb2d4134fa3 on danielgtaylor:auth-refactor** into **fa91d1bc7f08705aaf211a90c4fceb4242ed1e46 on boto:develop**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/1790378/badge)](https://coveralls.io/builds/1790378)

Coverage increased (+0.05%) to 94.16% when pulling **a8ebc1d647b434908731a415234021bf2aa7f5c2 on danielgtaylor:auth-refactor** into **fa91d1bc7f08705aaf211a90c4fceb4242ed1e46 on boto:develop**.

kyleknap: Looks good now. :ship: Just as a reminder could you run the CLI's unit and integration tests before this gets merged so we can ensure functionality of the CLI.
jamesls: Overall it looks good.  I'd suggest cutting down on method length in both the operation.py and client.py modules.  But my main concern is the operation.call().  I'm still concerned that this code has race conditions and performance implications.  Can we come up with an alternate way that does not have these problems?
coveralls: 
[![Coverage Status](https://coveralls.io/builds/1808822/badge)](https://coveralls.io/builds/1808822)

Coverage increased (+0.0%) to 94.1% when pulling **8e7d576299c020b9bd6e604651a457d77b93eef5 on danielgtaylor:auth-refactor** into **fa91d1bc7f08705aaf211a90c4fceb4242ed1e46 on boto:develop**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/1809376/badge)](https://coveralls.io/builds/1809376)

Coverage increased (+0.07%) to 94.17% when pulling **0f417d0bf347974c48794879fcf90ae6e276f3a1 on danielgtaylor:auth-refactor** into **fa91d1bc7f08705aaf211a90c4fceb4242ed1e46 on boto:develop**.


Patch:
diff --git a/botocore/client.py b/botocore/client.py
index 02b03b2e9..8ee369906 100644
--- a/botocore/client.py
+++ b/botocore/client.py
@@ -11,6 +11,8 @@
 # ANY KIND, either express or implied. See the License for the specific
 # language governing permissions and limitations under the License.
 import copy
+import functools
+import logging
 
 from botocore.model import ServiceModel
 from botocore.exceptions import DataNotFoundError
@@ -23,27 +25,31 @@ from botocore.utils import CachedProperty
 import botocore.validate
 import botocore.serialize
 from botocore import credentials
+from botocore.signers import RequestSigner
+from botocore.endpoint import EndpointCreator
+
+
+logger = logging.getLogger(__name__)
 
 
 class ClientCreator(object):
     """Creates client objects for a service."""
-    def __init__(self, loader, endpoint_creator, event_emitter,
+    def __init__(self, loader, endpoint_resolver, user_agent, event_emitter,
                  response_parser_factory=None):
         self._loader = loader
-        self._endpoint_creator = endpoint_creator
+        self._endpoint_resolver = endpoint_resolver
+        self._user_agent = user_agent
         self._event_emitter = event_emitter
         self._response_parser_factory = response_parser_factory
 
     def create_client(self, service_name, region_name, is_secure=True,
                       endpoint_url=None, verify=None,
-                      aws_access_key_id=None, aws_secret_access_key=None,
-                      aws_session_token=None):
+                      credentials=None, scoped_config=None):
         service_model = self._load_service_model(service_name)
         cls = self.create_client_class(service_name)
         client_args = self._get_client_args(
             service_model, region_name, is_secure, endpoint_url,
-            verify, aws_access_key_id, aws_secret_access_key,
-            aws_session_token)
+            verify, credentials, scoped_config)
         return cls(**client_args)
 
     def create_client_class(self, service_name):
@@ -169,34 +175,73 @@ class ClientCreator(object):
         service_model = ServiceModel(json_model, service_name=service_name)
         return service_model
 
+    def _get_signature_version_and_region(self, service_model, region_name,
+                                          is_secure, scoped_config):
+        # Get endpoint heuristic overrides before creating the
+        # request signer.
+        resolver = self._endpoint_resolver
+        scheme = 'https' if is_secure else 'http'
+        endpoint_config = resolver.construct_endpoint(
+                service_model.endpoint_prefix,
+                region_name, scheme=scheme)
+        # Region name override from endpoint
+        region_name = endpoint_config.get('properties', {}).get(
+            'credentialScope', {}).get('region', region_name)
+        # Signature version override from endpoint
+        signature_version = service_model.signature_version
+        if 'signatureVersion' in endpoint_config.get('properties', {}):
+            signature_version = endpoint_config['properties']\
+                                               ['signatureVersion']
+
+        # Signature overrides from a configuration file
+        if scoped_config is not None:
+            service_config = scoped_config.get(service_model.endpoint_prefix)
+            if service_config is not None and isinstance(service_config, dict):
+                override = service_config.get('signature_version')
+                if override:
+                    logger.debug(
+                        "Switching signature version for service %s "
+                         "to version %s based on config file override.",
+                         service_model.endpoint_prefix, override)
+                    signature_version = override
+
+        return signature_version, region_name
+
     def _get_client_args(self, service_model, region_name, is_secure,
-                         endpoint_url, verify, aws_access_key_id,
-                         aws_secret_access_key, aws_session_token):
+                         endpoint_url, verify, credentials,
+                         scoped_config):
         # A client needs:
         #
         # * serializer
         # * endpoint
         # * response parser
+        # * request signer
         protocol = service_model.metadata['protocol']
         serializer = botocore.serialize.create_serializer(
             protocol, include_validation=True)
-        creds = None
-        if aws_secret_access_key is not None:
-            creds = credentials.Credentials(
-                access_key=aws_access_key_id,
-                secret_key=aws_secret_access_key,
-                token=aws_session_token)
-        endpoint = self._endpoint_creator.create_endpoint(
+        event_emitter = copy.copy(self._event_emitter)
+        endpoint_creator = EndpointCreator(self._endpoint_resolver, region_name,
+                                           event_emitter, self._user_agent)
+        endpoint = endpoint_creator.create_endpoint(
             service_model, region_name, is_secure=is_secure,
             endpoint_url=endpoint_url, verify=verify,
-            credentials=creds,
             response_parser_factory=self._response_parser_factory)
         response_parser = botocore.parsers.create_parser(protocol)
+
+        signature_version, region_name = \
+            self._get_signature_version_and_region(
+                service_model, region_name, is_secure, scoped_config)
+
+        signer = RequestSigner(service_model.service_name, region_name,
+                               service_model.signing_name,
+                               signature_version, credentials,
+                               event_emitter)
         return {
             'serializer': serializer,
             'endpoint': endpoint,
             'response_parser': response_parser,
-            'event_emitter': copy.copy(self._event_emitter),
+            'event_emitter': event_emitter,
+            'request_signer': signer,
         }
 
     def _create_methods(self, service_model):
@@ -235,7 +280,8 @@ class ClientCreator(object):
                 'before-call.{endpoint_prefix}.{operation_name}'.format(
                     endpoint_prefix=service_model.endpoint_prefix,
                     operation_name=operation_name),
-                model=operation_model, params=request_dict
+                model=operation_model, params=request_dict,
+                request_signer=self._request_signer
             )
 
             http, parsed_response = self._endpoint.make_request(
@@ -262,15 +308,27 @@ class ClientCreator(object):
 class BaseClient(object):
 
     def __init__(self, serializer, endpoint, response_parser,
-                 event_emitter):
+                 event_emitter, request_signer):
         self._serializer = serializer
         self._endpoint = endpoint
         self._response_parser = response_parser
+        self._request_signer = request_signer
         self._cache = {}
         self.meta = ClientMeta(event_emitter)
 
+        # Register request signing, but only if we have an event
+        # emitter. When a client is cloned this is ignored, because
+        # the client's ``meta`` will be copied anyway.
+        if self.meta.events:
+            self.meta.events.register('request-created', self._sign_request)
+
+    def _sign_request(self, operation_name=None, request=None, **kwargs):
+        # Sign the request. This fires its own events and will
+        # mutate the request as needed.
+        self._request_signer.sign(operation_name, request)
+
     def clone_client(self, serializer=None, endpoint=None,
-                     response_parser=None):
+                     response_parser=None, request_signer=None):
         """Create a copy of the client object.
 
         This method will create a clone of an existing client.  By default, the
@@ -289,6 +347,7 @@ class BaseClient(object):
             'serializer': serializer,
             'endpoint': endpoint,
             'response_parser': response_parser,
+            'request_signer': request_signer,
         }
         for key, value in kwargs.items():
             if value is None:
@@ -317,4 +376,5 @@ class ClientMeta(object):
         self.events = events
 
     def __copy__(self):
-        return ClientMeta(**copy.deepcopy(self.__dict__))
+        copied_events = copy.copy(self.events)
+        return ClientMeta(copied_events)
diff --git a/botocore/endpoint.py b/botocore/endpoint.py
index 519dd6c61..db6179b2a 100644
--- a/botocore/endpoint.py
+++ b/botocore/endpoint.py
@@ -22,8 +22,6 @@ from botocore.vendored.requests.utils import get_environ_proxies
 
 import botocore.response
 import botocore.exceptions
-from botocore.auth import AUTH_TYPE_MAPS
-from botocore.exceptions import UnknownSignatureVersionError
 from botocore.exceptions import UnknownEndpointError
 from botocore.awsrequest import AWSRequest
 from botocore.compat import urljoin
@@ -79,17 +77,15 @@ class Endpoint(object):
     :ivar session: The session object.
     """
 
-    def __init__(self, region_name, host, auth, user_agent, signature_version,
+    def __init__(self, region_name, host, user_agent,
                  endpoint_prefix, event_emitter, proxies=None, verify=True,
                  timeout=DEFAULT_TIMEOUT, response_parser_factory=None):
         self._endpoint_prefix = endpoint_prefix
-        self._signature_version = signature_version
         self._event_emitter = event_emitter
         self._user_agent = user_agent
         self.region_name = region_name
         self.host = host
         self.verify = verify
-        self.auth = auth
         if proxies is None:
             proxies = {}
         self.proxies = proxies
@@ -106,33 +102,18 @@ class Endpoint(object):
     def make_request(self, operation_model, request_dict):
         logger.debug("Making request for %s (verify_ssl=%s) with params: %s",
                      operation_model, self.verify, request_dict)
-        prepared_request = self.create_request(request_dict)
-        return self._send_request(prepared_request, operation_model)
-
-    def _choose_signer(self, signer=None):
-        # To decide if we need to do auth or not we check the
-        # signature_version attribute on both the service and
-        # the operation are not None and we make sure there is an
-        # auth class associated with the endpoint.
-        # If any of these are not true, we skip auth.
-        if signer is not None:
-            # If the user explicitly specifies a signer, then we will sign
-            # the request.
-            signer = signer
-        else:
-            do_auth = self._signature_version and self.auth
-            if do_auth:
-                signer = self.auth
-            else:
-                # If we're not suppose to sign the request, then we set the
-                # signer to None.
-                signer = None
-        return signer
+        return self._send_request(request_dict, operation_model)
 
-    def create_request(self, params, signer=None):
-        signer = self._choose_signer(signer)
+    def create_request(self, params, operation_model=None):
         request = self._create_request_object(params)
-        prepared_request = self.prepare_request(request, signer)
+        if operation_model:
+            event_name = 'request-created.{endpoint_prefix}.{op_name}'.format(
+                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)
         return prepared_request
 
     def _create_request_object(self, request_dict):
@@ -152,21 +133,12 @@ class Endpoint(object):
                              headers=headers)
         return request
 
-    def prepare_request(self, request, signer):
-        if signer is not None:
-            with self._lock:
-                # Parts of the auth signing code aren't thread safe (things
-                # that manipulate .auth_path), so we're using a lock here to
-                # prevent race conditions.
-                event_name = 'before-auth.%s' % self._endpoint_prefix
-                self._event_emitter.emit(
-                    event_name, endpoint=self, request=request, auth=signer)
-                signer.add_auth(request=request)
-        prepared_request = request.prepare()
-        return prepared_request
+    def prepare_request(self, request):
+        return request.prepare()
 
-    def _send_request(self, request, operation_model):
+    def _send_request(self, request_dict, operation_model):
         attempts = 1
+        request = self.create_request(request_dict, operation_model)
         response, exception = self._get_response(
             request, operation_model, attempts)
         while self._needs_retry(attempts, operation_model,
@@ -177,9 +149,9 @@ class Endpoint(object):
             # This will ensure that we resend the entire contents of the
             # body.
             request.reset_stream()
-            # Resign the request when retried.
-            signer = self._choose_signer()
-            request = self.prepare_request(request.original, signer)
+            # Create a new request when retried (including a new signature).
+            request = self.create_request(
+                request_dict, operation_model=operation_model)
             response, exception = self._get_response(request, operation_model,
                                                      attempts)
         return response
@@ -235,33 +207,25 @@ def get_endpoint(service, region_name, endpoint_url, verify=None):
     endpoint_prefix = service.endpoint_prefix
     signature_version = getattr(service, 'signature_version', None)
     session = service.session
-    credentials = session.get_credentials()
     event_emitter = session.get_component('event_emitter')
     user_agent = session.user_agent()
     return get_endpoint_complex(service_name, endpoint_prefix,
-                                signature_version, credentials,
+                                signature_version,
                                 region_name, endpoint_url, verify, user_agent,
                                 event_emitter)
 
 
 def get_endpoint_complex(service_name, endpoint_prefix, signature_version,
-                         credentials, region_name, endpoint_url, verify,
+                         region_name, endpoint_url, verify,
                          user_agent, event_emitter,
                          response_parser_factory=None):
-    auth = None
-    if signature_version is not None:
-        auth = _get_auth(signature_version,
-                         credentials=credentials,
-                         service_name=service_name,
-                         region_name=region_name)
     proxies = _get_proxies(endpoint_url)
     verify = _get_verify_value(verify)
     return Endpoint(
-        region_name, endpoint_url, auth=auth,
+        region_name, endpoint_url,
         user_agent=user_agent,
         endpoint_prefix=endpoint_prefix,
         event_emitter=event_emitter,
-        signature_version=signature_version,
         proxies=proxies,
         verify=verify,
         response_parser_factory=response_parser_factory)
@@ -281,28 +245,12 @@ def _get_verify_value(verify):
     return os.environ.get('REQUESTS_CA_BUNDLE', True)
 
 
-def _get_auth(signature_version, credentials, service_name, region_name):
-    cls = AUTH_TYPE_MAPS.get(signature_version)
-    if cls is None:
-        raise UnknownSignatureVersionError(signature_version=signature_version)
-    else:
-        kwargs = {'credentials': credentials}
-        if cls.REQUIRES_REGION:
-            if region_name is None:
-                raise botocore.exceptions.NoRegionError(
-                    env_var='AWS_DEFAULT_REGION')
-            kwargs['region_name'] = region_name
-            kwargs['service_name'] = service_name
-        return cls(**kwargs)
-
-
 class EndpointCreator(object):
     def __init__(self, endpoint_resolver, configured_region, event_emitter,
-                 credentials, user_agent):
+                 user_agent):
         self._endpoint_resolver = endpoint_resolver
         self._configured_region = configured_region
         self._event_emitter = event_emitter
-        self._credentials = credentials
         self._user_agent = user_agent
 
     def create_endpoint(self, service_model, region_name=None, is_secure=True,
@@ -347,23 +295,17 @@ class EndpointCreator(object):
             final_endpoint_url = endpoint['uri']
         return self._get_endpoint(service_model, region_name,
                                   signature_version, final_endpoint_url,
-                                  verify, credentials, response_parser_factory)
+                                  verify, response_parser_factory)
 
     def _get_endpoint(self, service_model, region_name, signature_version,
-                      endpoint_url, verify, user_provided_creds,
-                      response_parser_factory):
+                      endpoint_url, verify, response_parser_factory):
         service_name = service_model.signing_name
         endpoint_prefix = service_model.endpoint_prefix
-        credentials = self._credentials
-        if user_provided_creds is not None:
-            # Credentials provided via create_endpoint() override the
-            # credentials provided when the EndpointCreator was created.
-            credentials = user_provided_creds
         user_agent = self._user_agent
         event_emitter = self._event_emitter
         user_agent = self._user_agent
         return get_endpoint_complex(service_name, endpoint_prefix,
-                                    signature_version, credentials,
+                                    signature_version,
                                     region_name, endpoint_url,
                                     verify, user_agent, event_emitter,
                                     response_parser_factory)
diff --git a/botocore/handlers.py b/botocore/handlers.py
index 3ab43ca0c..333e7f108 100644
--- a/botocore/handlers.py
+++ b/botocore/handlers.py
@@ -18,6 +18,7 @@ This module contains builtin handlers for events emitted by botocore.
 
 import base64
 import hashlib
+import functools
 import logging
 import re
 import xml.etree.cElementTree
@@ -164,7 +165,7 @@ def check_dns_name(bucket_name):
     return True
 
 
-def fix_s3_host(event_name, endpoint, request, auth, **kwargs):
+def fix_s3_host(request, signature_version, region_name, **kwargs):
     """
     This handler looks at S3 requests just before they are signed.
     If there is a bucket name on the path (true for everything except
@@ -189,13 +190,13 @@ def fix_s3_host(event_name, endpoint, request, auth, **kwargs):
     parts = urlsplit(request.url)
     request.auth_path = parts.path
     path_parts = parts.path.split('/')
-    if isinstance(auth, botocore.auth.SigV4Auth):
+    if signature_version in ['s3v4', 'v4']:
         return
     if len(path_parts) > 1:
         bucket_name = path_parts[1]
         logger.debug('Checking for DNS compatible bucket for: %s',
                      request.url)
-        if check_dns_name(bucket_name) and _allowed_region(endpoint.region_name):
+        if check_dns_name(bucket_name) and _allowed_region(region_name):
             # If the operation is on a bucket, the auth_path must be
             # terminated with a '/' character.
             if len(path_parts) == 2:
@@ -265,18 +266,13 @@ def _register_for_operations(config, session, service_name):
                          handler, unique_id=unique_id)
 
 
-def signature_overrides(service_data, service_name, session, **kwargs):
-    scoped_config = session.get_scoped_config()
-    service_config = scoped_config.get(service_name)
-    if service_config is None or not isinstance(service_config, dict):
-        return
-    signature_version_override = service_config.get('signature_version')
-    if signature_version_override is not None:
-        logger.debug("Switching signature version for service %s "
-                     "to version %s based on config file override.",
-                     service_name, signature_version_override)
-        service_metadata = service_data['metadata']
-        service_metadata['signatureVersion'] = signature_version_override
+def disable_signing(**kwargs):
+    """
+    This handler disables request signing by setting the signer
+    name to an empty string, similar to how the signature
+    overrides above work.
+    """
+    return ''
 
 
 def add_expect_header(model, params, **kwargs):
@@ -298,7 +294,7 @@ def quote_source_header(params, **kwargs):
             value.encode('utf-8'), '/~')
 
 
-def copy_snapshot_encrypted(operation, params, endpoint, **kwargs):
+def copy_snapshot_encrypted(operation, params, request_signer, **kwargs):
     # The presigned URL that facilities copying an encrypted snapshot.
     # If the user does not provide this value, we will automatically
     # calculate on behalf of the user and inject the PresignedUrl
@@ -311,19 +307,18 @@ def copy_snapshot_encrypted(operation, params, endpoint, **kwargs):
         # If the customer provided this value, then there's nothing for
         # us to do.
         return
-    params['DestinationRegion'] = endpoint.region_name
+    params['DestinationRegion'] = request_signer._region_name
     # The request will be sent to the destination region, so we need
     # to create an endpoint to the source region and create a presigned
     # url based on the source endpoint.
     region = params['SourceRegion']
     source_endpoint = operation.service.get_endpoint(region)
-    presigner = botocore.auth.SigV4QueryAuth(
-        credentials=source_endpoint.auth.credentials,
-        region_name=region,
-        service_name='ec2',
-        expires=60 * 60)
-    signed_request = source_endpoint.create_request(request_dict, presigner)
-    params['PresignedUrl'] = signed_request.url
+    presigner = request_signer.get_auth(
+        'ec2', region, signature_version='v4-query')
+    request = source_endpoint.create_request(request_dict)
+    presigner.add_auth(request=request.original)
+    request = request.original.prepare()
+    params['PresignedUrl'] = request.url
 
 
 def json_decode_policies(parsed, model, **kwargs):
@@ -470,13 +465,14 @@ BUILTIN_HANDLERS = [
     ('before-call.glacier.UploadArchive', add_glacier_checksums),
     ('before-call.glacier.UploadMultipartPart', add_glacier_checksums),
     ('before-call.ec2.CopySnapshot', copy_snapshot_encrypted),
-    ('before-auth.s3', fix_s3_host),
     ('needs-retry.s3.UploadPartCopy', check_for_200_error, REGISTER_FIRST),
     ('needs-retry.s3.CopyObject', check_for_200_error, REGISTER_FIRST),
     ('needs-retry.s3.CompleteMultipartUpload', check_for_200_error,
      REGISTER_FIRST),
     ('service-data-loaded', register_retries_for_service),
-    ('service-data-loaded', signature_overrides),
+    ('choose-signer.cognito-identity.GetId', disable_signing),
+    ('choose-signer.cognito-identity.GetOpenIdToken', disable_signing),
+    ('before-sign.s3', fix_s3_host),
     ('before-parameter-build.s3.HeadObject', sse_md5),
     ('before-parameter-build.s3.GetObject', sse_md5),
     ('before-parameter-build.s3.PutObject', sse_md5),
diff --git a/botocore/operation.py b/botocore/operation.py
index f3aff77db..526593a42 100644
--- a/botocore/operation.py
+++ b/botocore/operation.py
@@ -12,10 +12,14 @@
 # ANY KIND, either express or implied. See the License for the specific
 # language governing permissions and limitations under the License.
 
+import functools
 import logging
+import threading
 from botocore.exceptions import MissingParametersError
 from botocore.exceptions import UnknownParameterError
+from botocore.exceptions import NoRegionError
 from botocore.paginate import DeprecatedPaginator
+from botocore.signers import RequestSigner
 from botocore import serialize
 from botocore import BotoCoreObject, xform_name
 
@@ -61,6 +65,39 @@ class Operation(BotoCoreObject):
     def signature_version(self):
         return self.service.signature_version
 
+    def _get_signature_version_and_region(self, endpoint, service_model):
+        # An endpoint-aware signature version and region check
+        scoped_config = self.session.get_scoped_config()
+        resolver = self.session.get_component('endpoint_resolver')
+        scheme = endpoint.host.split(':')[0]
+        if endpoint.region_name is None:
+            raise NoRegionError(env_var='region')
+        endpoint_config = resolver.construct_endpoint(
+                service_model.endpoint_prefix,
+                endpoint.region_name, scheme=scheme)
+        # Region name override from endpoint
+        region_name = endpoint_config.get('properties', {}).get(
+            'credentialScope', {}).get('region', endpoint.region_name)
+        # Signature version override from endpoint
+        signature_version = self.service.signature_version
+        if 'signatureVersion' in endpoint_config.get('properties', {}):
+            signature_version = endpoint_config['properties']\
+                                               ['signatureVersion']
+
+        # Signature overrides from a configuration file
+        if scoped_config is not None:
+            service_config = scoped_config.get(service_model.endpoint_prefix)
+            if service_config is not None and isinstance(service_config, dict):
+                override = service_config.get('signature_version')
+                if override:
+                    logger.debug(
+                        "Switching signature version for service %s "
+                         "to version %s based on config file override.",
+                         service_model.endpoint_prefix, override)
+                    signature_version = override
+
+        return signature_version, region_name
+
     def call(self, endpoint, **kwargs):
         logger.debug("%s called with kwargs: %s", self, kwargs)
         # It probably seems a little weird to be firing two different
@@ -77,6 +114,21 @@ class Operation(BotoCoreObject):
                           model=self.model,
                           params=kwargs)
         request_dict = self.build_parameters(**kwargs)
+
+        service_name = self.service.service_name
+        service_model = self.session.get_service_model(service_name)
+
+        signature_version, region_name = \
+            self._get_signature_version_and_region(
+                endpoint, service_model)
+
+        credentials = self.session.get_credentials()
+        event_emitter = self.session.get_component('event_emitter')
+        signer = RequestSigner(service_model.service_name,
+                               region_name, service_model.signing_name,
+                               signature_version, credentials,
+                               event_emitter)
+
         event = self.session.create_event('before-call',
                                           self.service.endpoint_prefix,
                                           self.name)
@@ -86,8 +138,34 @@ class Operation(BotoCoreObject):
         self.session.emit(event, endpoint=endpoint,
                           model=self.model,
                           params=request_dict,
-                          operation=self)
-        response = endpoint.make_request(self.model, request_dict)
+                          operation=self,
+                          request_signer=signer)
+
+        # Here we register to the specific request-created event
+        # for this operation. Since it's possible to run the same
+        # operation in multiple threads, we used a lock to prevent
+        # issues. It's possible a request will be signed more than
+        # once. Once the request has been made, we unregister the
+        # handler.
+        def request_created(request, **kwargs):
+            # This first check lets us quickly determine when
+            # a request has already been signed without needing
+            # to acquire the lock.
+            if not getattr(request, '_is_signed', False):
+                with threading.Lock():
+                    if not getattr(request, '_is_signed', False):
+                        signer.sign(self.name, request)
+                        request._is_signed = True
+
+        event_emitter.register('request-created.{0}.{1}'.format(
+            self.service.endpoint_prefix, self.name), request_created)
+
+        try:
+            response = endpoint.make_request(self.model, request_dict)
+        finally:
+            event_emitter.unregister('request-created.{0}.{1}'.format(
+                self.service.endpoint_prefix, self.name), request_created)
+
         event = self.session.create_event('after-call',
                                           self.service.endpoint_prefix,
                                           self.name)
diff --git a/botocore/service.py b/botocore/service.py
index 409566f0f..9dd2de2c7 100644
--- a/botocore/service.py
+++ b/botocore/service.py
@@ -156,11 +156,9 @@ class Service(object):
         event_emitter = self.session.get_component('event_emitter')
         response_parser_factory = self.session.get_component(
             'response_parser_factory')
-        model = self._model
-        credentials = self.session.get_credentials()
         user_agent= self.session.user_agent()
         endpoint_creator = EndpointCreator(resolver, region, event_emitter,
-                                           credentials, user_agent)
+                                           user_agent)
         kwargs = {'service_model': self._model, 'region_name': region_name,
                   'is_secure': is_secure, 'endpoint_url': endpoint_url,
                   'verify': verify,
diff --git a/botocore/session.py b/botocore/session.py
index 6d8ba59ce..a39803e28 100644
--- a/botocore/session.py
+++ b/botocore/session.py
@@ -809,36 +809,27 @@ class Session(object):
         :return: A botocore client instance
 
         """
+        if region_name is None:
+            region_name = self.get_config_variable('region')
         loader = self.get_component('data_loader')
-        endpoint_creator = self._create_endpoint_creator(aws_access_key_id,
-                                                         aws_secret_access_key,
-                                                         aws_session_token)
         event_emitter = self.get_component('event_emitter')
         response_parser_factory = self.get_component(
             'response_parser_factory')
-        client_creator = botocore.client.ClientCreator(loader, endpoint_creator,
-                                                       event_emitter,
-                                                       response_parser_factory)
-        client = client_creator.create_client(service_name, region_name, use_ssl,
-                                              endpoint_url, verify,
-                                              aws_access_key_id,
-                                              aws_secret_access_key,
-                                              aws_session_token)
-        return client
-
-    def _create_endpoint_creator(self, aws_access_key_id, aws_secret_access_key,
-                                 aws_session_token):
-        resolver = self.get_component('endpoint_resolver')
-        region = self.get_config_variable('region')
-        event_emitter = self.get_component('event_emitter')
-        if aws_secret_access_key is None:
-            credentials = self.get_credentials()
+        if aws_secret_access_key is not None:
+            credentials = botocore.credentials.Credentials(
+                access_key=aws_access_key_id,
+                secret_key=aws_secret_access_key,
+                token=aws_session_token)
         else:
-            credentials = None
-        user_agent= self.user_agent()
-        endpoint_creator = EndpointCreator(resolver, region, event_emitter,
-                                           credentials, user_agent)
-        return endpoint_creator
+            credentials = self.get_credentials()
+        endpoint_resolver = self.get_component('endpoint_resolver')
+        client_creator = botocore.client.ClientCreator(
+            loader, endpoint_resolver, self.user_agent(), event_emitter,
+            response_parser_factory)
+        client = client_creator.create_client(
+            service_name, region_name, use_ssl, endpoint_url, verify,
+            credentials, scoped_config=self.get_scoped_config())
+        return client
 
 
 class ComponentLocator(object):
diff --git a/botocore/signers.py b/botocore/signers.py
index 99c20306d..4b54373b2 100644
--- a/botocore/signers.py
+++ b/botocore/signers.py
@@ -42,20 +42,15 @@ class RequestSigner(object):
     :param credentials: User credentials with which to sign requests.
     :type event_emitter: :py:class:`~botocore.hooks.BaseEventHooks`
     :param event_emitter: Extension mechanism to fire events.
-    :type scoped_config: dict
-    :param scoped_config: User configuration which may include
-                          signature overrides.
     """
     def __init__(self, service_name, region_name, signing_name,
-                 signature_version, credentials, event_emitter,
-                 scoped_config):
+                 signature_version, credentials, event_emitter):
         self._service_name = service_name
         self._region_name = region_name
         self._signing_name = signing_name
         self._signature_version = signature_version
         self._credentials = credentials
         self._event_emitter = event_emitter
-        self._scoped_config = scoped_config
 
         # Used to cache auth instances since one request signer
         # can be used for many requests in a single client.
@@ -79,7 +74,7 @@ class RequestSigner(object):
         handler, response = self._event_emitter.emit_until_response(
             'choose-signer.{0}.{1}'.format(self._service_name, operation_name),
             signing_name=self._signing_name, region_name=self._region_name,
-            signature_version=signature_version, config=self._scoped_config)
+            signature_version=signature_version)
         if response is not None:
             signature_version = response
 


Test patch:
diff --git a/tests/integration/test_s3.py b/tests/integration/test_s3.py
index 2bae2fa5a..733ca2a9e 100644
--- a/tests/integration/test_s3.py
+++ b/tests/integration/test_s3.py
@@ -150,7 +150,7 @@ class TestS3Objects(TestS3BaseWithBucket):
                            key=key)
         super(TestS3Objects, self).tearDown()
 
-    def increment_auth(self, request, auth, **kwargs):
+    def increment_auth(self, request, **kwargs):
         self.auth_paths.append(request.auth_path)
 
     def test_can_delete_urlencoded_object(self):
@@ -341,7 +341,7 @@ class TestS3Objects(TestS3BaseWithBucket):
     def test_thread_safe_auth(self):
         self.auth_paths = []
         self.caught_exceptions = []
-        self.session.register('before-auth', self.increment_auth)
+        self.session.register('before-sign', self.increment_auth)
         self.create_object(key_name='foo1')
         threads = []
         for i in range(10):
@@ -483,8 +483,9 @@ class TestS3Presign(BaseS3Test):
             region_name='us-east-1', service_name='s3', expires=60)
         op = self.service.get_operation('GetObject')
         params = op.build_parameters(bucket=self.bucket_name, key=key_name)
-        request = self.endpoint.create_request(params, signer)
-        presigned_url = request.url
+        request = self.endpoint.create_request(params)
+        signer.add_auth(request.original)
+        presigned_url = request.original.prepare().url
         # We should now be able to retrieve the contents of 'mykey' using
         # this presigned url.
         self.assertEqual(requests.get(presigned_url).content, b'foobar')
@@ -500,8 +501,9 @@ class TestS3PresignFixHost(BaseS3Test):
             region_name='us-west-2', service_name='s3', expires=60)
         op = self.service.get_operation('GetObject')
         params = op.build_parameters(bucket=bucket_name, key=key_name)
-        request = endpoint.create_request(params, signer)
-        presigned_url = request.url
+        request = endpoint.create_request(params)
+        signer.add_auth(request.original)
+        presigned_url = request.original.prepare().url
         # We should not have rewritten the host to be s3.amazonaws.com.
         self.assertTrue(presigned_url.startswith(
             'https://s3-us-west-2.amazonaws.com/mybucket/mykey'),
@@ -726,21 +728,6 @@ class TestCanSwitchToSigV4(unittest.TestCase):
         self.environ_patch.stop()
         shutil.rmtree(self.tempdir)
 
-    def test_verify_can_switch_sigv4(self):
-        # Verify we can turn on sigv4 from a config file.
-        with open(self.config_filename, 'w') as f:
-            f.write(
-                '[default]\n'
-                's3 =\n'
-                '  signature_version = s3v4\n')
-        # We need to verify this option for service/operation objects so we're
-        # not using client objects now (though we should add a test for client
-        # objects eventually).
-        service = self.session.get_service('s3')
-        endpoint = service.get_endpoint('us-east-1')
-        # The set_config_variable should ensure that we use sigv4 for s3.
-        self.assertIsInstance(endpoint.auth, botocore.auth.S3SigV4Auth)
-
 
 class TestSSEKeyParamValidation(unittest.TestCase):
     def setUp(self):
diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py
index 4d5164863..76781c32f 100644
--- a/tests/unit/test_client.py
+++ b/tests/unit/test_client.py
@@ -16,6 +16,7 @@ import mock
 
 from botocore import client
 from botocore import hooks
+from botocore.credentials import Credentials
 from botocore.exceptions import ParamValidationError
 from botocore import exceptions
 
@@ -53,97 +54,151 @@ class TestAutoGeneratedClient(unittest.TestCase):
         }
         self.loader = mock.Mock()
         self.loader.load_service_model.return_value = self.service_description
+        self.credentials = Credentials('access-key', 'secret-key')
+
+        self.endpoint_creator_patch = mock.patch('botocore.client.EndpointCreator')
+        self.endpoint_creator_cls = self.endpoint_creator_patch.start()
+        self.endpoint_creator = self.endpoint_creator_cls.return_value
+
+        self.endpoint = mock.Mock()
+        self.endpoint.make_request.return_value = (mock.Mock(status_code=200), {})
+        self.endpoint_creator.create_endpoint.return_value = self.endpoint
+
+    def tearDown(self):
+        self.endpoint_creator_patch.stop()
 
     def create_client_creator(self, endpoint_creator=None, event_emitter=None,
                               response_parser_factory=None):
-        if endpoint_creator is None:
-            endpoint_creator = mock.Mock()
-            endpoint = mock.Mock()
-            endpoint_creator.create_endpoint.return_value = endpoint
-            endpoint.make_request.return_value = (
-                mock.Mock(status_code=200), {})
         if event_emitter is None:
             event_emitter = hooks.HierarchicalEmitter()
+        endpoint_resolver = mock.Mock()
+        endpoint_resolver.construct_endpoint.return_value = {
+            'properties': {},
+            'uri': 'http://foo'
+        }
+
+        if endpoint_creator is not None:
+            self.endpoint_creator_cls.return_value = endpoint_creator
         creator = client.ClientCreator(
-            self.loader, endpoint_creator, event_emitter,
+            self.loader, endpoint_resolver, 'user-agent', event_emitter,
             response_parser_factory)
         return creator
 
     def test_client_generated_from_model(self):
         creator = self.create_client_creator()
-        service_client = creator.create_client('myservice', 'us-west-2')
+        service_client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
         self.assertTrue(hasattr(service_client, 'test_operation'))
 
+    @mock.patch('botocore.client.RequestSigner')
+    def test_client_signature_no_override(self, request_signer):
+        creator = self.create_client_creator()
+        service_client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials,
+            scoped_config={})
+        request_signer.assert_called_with(
+            mock.ANY, mock.ANY, mock.ANY, 'v4', mock.ANY, mock.ANY)
+
+    @mock.patch('botocore.client.RequestSigner')
+    def test_client_signature_override(self, request_signer):
+        creator = self.create_client_creator()
+        config = {
+            'myservice': {'signature_version': 'foo'}
+        }
+        service_client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials,
+            scoped_config=config)
+        request_signer.assert_called_with(
+            mock.ANY, mock.ANY, mock.ANY, 'foo', mock.ANY, mock.ANY)
+
+    def test_client_registers_request_created_handler(self):
+        event_emitter = mock.Mock()
+        creator = self.create_client_creator(event_emitter=event_emitter)
+        service_client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
+        event_emitter.register.assert_called_with('request-created', mock.ANY)
+
     def test_client_makes_call(self):
-        endpoint_creator = mock.Mock()
-        endpoint = mock.Mock()
-        endpoint_creator.create_endpoint.return_value = endpoint
-        endpoint.make_request.return_value = (mock.Mock(status_code=200), {})
-        creator = self.create_client_creator(endpoint_creator)
+        creator = self.create_client_creator()
+        service_client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
+
+        self.assertTrue(self.endpoint_creator.create_endpoint.called)
 
-        service_client = creator.create_client('myservice', 'us-west-2')
         response = service_client.test_operation(Foo='one', Bar='two')
         self.assertEqual(response, {})
 
+    @mock.patch('botocore.client.RequestSigner')
+    def test_client_signs_call(self, signer_mock):
+        creator = self.create_client_creator()
+        service_client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
+        request = mock.Mock()
+
+        # Emit the request created event to see if it would be signed.
+        # We tested above to ensure this event is registered when
+        # a client is created. This prevents testing the entire client
+        # call logic.
+        service_client.meta.events.emit(
+            'request-created.myservice.test_operation', request=request,
+            operation_name='test_operation')
+
+        signer_mock.return_value.sign.assert_called_with(
+            'test_operation', request)
+
     def test_client_makes_call_with_error(self):
-        endpoint_creator = mock.Mock()
-        endpoint = mock.Mock()
-        endpoint_creator.create_endpoint.return_value = endpoint
         error_response = {
             'Error': {'Code': 'code', 'Message': 'error occurred'}
         }
-        endpoint.make_request.return_value = (mock.Mock(status_code=400),
-                                              error_response)
-        creator = self.create_client_creator(endpoint_creator)
+        self.endpoint.make_request.return_value = (
+            mock.Mock(status_code=400), error_response)
 
-        service_client = creator.create_client('myservice', 'us-west-2')
+        creator = self.create_client_creator()
+
+        service_client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
         with self.assertRaises(client.ClientError):
             service_client.test_operation(Foo='one', Bar='two')
 
     def test_client_validates_params(self):
-        endpoint_creator = mock.Mock()
-        creator = self.create_client_creator(endpoint_creator)
+        creator = self.create_client_creator()
 
-        service_client = creator.create_client('myservice', 'us-west-2')
+        service_client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
         with self.assertRaises(ParamValidationError):
             # Missing required 'Foo' param.
             service_client.test_operation(Bar='two')
 
     def test_client_with_custom_params(self):
-        endpoint_creator = mock.Mock()
-        creator = self.create_client_creator(endpoint_creator)
+        creator = self.create_client_creator()
 
         creator.create_client('myservice', 'us-west-2',
                               is_secure=False, verify=False)
-        endpoint_creator.create_endpoint.assert_called_with(
+        self.endpoint_creator.create_endpoint.assert_called_with(
             mock.ANY, 'us-west-2', is_secure=False,
-            endpoint_url=None, verify=False, credentials=None,
+            endpoint_url=None, verify=False,
             response_parser_factory=None)
 
     def test_client_with_endpoint_url(self):
-        endpoint_creator = mock.Mock()
-        creator = self.create_client_creator(endpoint_creator)
+        creator = self.create_client_creator()
 
         creator.create_client('myservice', 'us-west-2',
                               endpoint_url='http://custom.foo')
-        endpoint_creator.create_endpoint.assert_called_with(
+        self.endpoint_creator.create_endpoint.assert_called_with(
             mock.ANY, 'us-west-2', is_secure=True,
-            endpoint_url='http://custom.foo', verify=None, credentials=None,
+            endpoint_url='http://custom.foo', verify=None,
             response_parser_factory=None)
 
     def test_client_with_response_parser_factory(self):
         factory = mock.Mock()
-        endpoint_creator = mock.Mock()
-        creator = self.create_client_creator(endpoint_creator,
-                                             response_parser_factory=factory)
+        creator = self.create_client_creator(response_parser_factory=factory)
         creator.create_client('myservice', 'us-west-2')
-        endpoint_creator.create_endpoint.assert_called_with(
+        self.endpoint_creator.create_endpoint.assert_called_with(
             mock.ANY, 'us-west-2', is_secure=True,
-            endpoint_url=None, verify=None, credentials=None,
+            endpoint_url=None, verify=None,
             response_parser_factory=factory)
 
     def test_operation_cannot_paginate(self):
-        endpoint_creator = mock.Mock()
         pagination_config = {
             'pagination': {
                 # Note that there's no pagination config for
@@ -159,12 +214,11 @@ class TestAutoGeneratedClient(unittest.TestCase):
             }
         }
         self.loader.load_data.return_value = pagination_config
-        creator = self.create_client_creator(endpoint_creator)
+        creator = self.create_client_creator()
         service_client = creator.create_client('myservice', 'us-west-2')
         self.assertFalse(service_client.can_paginate('test_operation'))
 
     def test_operation_can_paginate(self):
-        endpoint_creator = mock.Mock()
         pagination_config = {
             'pagination': {
                 'TestOperation': {
@@ -177,7 +231,7 @@ class TestAutoGeneratedClient(unittest.TestCase):
             }
         }
         self.loader.load_data.return_value = pagination_config
-        creator = self.create_client_creator(endpoint_creator)
+        creator = self.create_client_creator()
         service_client = creator.create_client('myservice', 'us-west-2')
         self.assertTrue(service_client.can_paginate('test_operation'))
         # Also, the config is cached, but we want to make sure we get
@@ -187,23 +241,21 @@ class TestAutoGeneratedClient(unittest.TestCase):
     def test_service_has_no_pagination_configs(self):
         # This is the case where there is an actual *.paginator.json, file,
         # but the specific operation itself is not actually pageable.
-        endpoint_creator = mock.Mock()
         # If the loader cannot load pagination configs, it communicates
         # this by raising a DataNotFoundError.
         self.loader.load_data.side_effect = exceptions.DataNotFoundError(
             data_path='/foo')
-        creator = self.create_client_creator(endpoint_creator)
+        creator = self.create_client_creator()
         service_client = creator.create_client('myservice', 'us-west-2')
         self.assertFalse(service_client.can_paginate('test_operation'))
 
     def test_waiter_config_uses_service_name_not_endpoint_prefix(self):
-        endpoint_creator = mock.Mock()
         waiter_config = {
             'version': 2,
             'waiters': {}
         }
         self.loader.load_data.return_value = waiter_config
-        creator = self.create_client_creator(endpoint_creator)
+        creator = self.create_client_creator()
         # We're going to verify that the loader loads a service called
         # 'other-service-name', and even though the endpointPrefix is
         # 'myservice', we use 'other-service-name' for waiters/paginators, etc.
@@ -216,7 +268,6 @@ class TestAutoGeneratedClient(unittest.TestCase):
             'aws/other-service-name/2014-01-01.waiters')
 
     def test_service_has_waiter_configs(self):
-        endpoint_creator = mock.Mock()
         waiter_config = {
             'version': 2,
             'waiters': {
@@ -235,33 +286,30 @@ class TestAutoGeneratedClient(unittest.TestCase):
             }
         }
         self.loader.load_data.return_value = waiter_config
-        creator = self.create_client_creator(endpoint_creator)
+        creator = self.create_client_creator()
         service_client = creator.create_client('myservice', 'us-west-2')
         self.assertEqual(sorted(service_client.waiter_names),
                          sorted(['waiter_1', 'waiter_2']))
         self.assertTrue(hasattr(service_client.get_waiter('waiter_1'), 'wait'))
 
     def test_service_has_no_waiter_configs(self):
-        endpoint_creator = mock.Mock()
         self.loader.load_data.side_effect = exceptions.DataNotFoundError(
             data_path='/foo')
-        creator = self.create_client_creator(endpoint_creator)
+        creator = self.create_client_creator()
         service_client = creator.create_client('myservice', 'us-west-2')
         self.assertEqual(service_client.waiter_names, [])
         with self.assertRaises(ValueError):
             service_client.get_waiter("unknown_waiter")
 
     def test_try_to_paginate_non_paginated(self):
-        endpoint_creator = mock.Mock()
         self.loader.load_data.side_effect = exceptions.DataNotFoundError(
             data_path='/foo')
-        creator = self.create_client_creator(endpoint_creator)
+        creator = self.create_client_creator()
         service_client = creator.create_client('myservice', 'us-west-2')
         with self.assertRaises(exceptions.OperationNotPageableError):
             service_client.get_paginator('test_operation')
 
     def test_successful_pagination_object_created(self):
-        endpoint_creator = mock.Mock()
         pagination_config = {
             'pagination': {
                 'TestOperation': {
@@ -274,7 +322,7 @@ class TestAutoGeneratedClient(unittest.TestCase):
             }
         }
         self.loader.load_data.return_value = pagination_config
-        creator = self.create_client_creator(endpoint_creator)
+        creator = self.create_client_creator()
         service_client = creator.create_client('myservice', 'us-west-2')
         paginator = service_client.get_paginator('test_operation')
         # The pagination logic itself is tested elsewhere (test_paginate.py),
@@ -282,34 +330,27 @@ class TestAutoGeneratedClient(unittest.TestCase):
         self.assertTrue(hasattr(paginator, 'paginate'))
 
     def test_can_set_credentials_in_client_init(self):
-        endpoint_creator = mock.Mock()
-        creator = self.create_client_creator(endpoint_creator)
-        creator.create_client(
-            'myservice', 'us-west-2', aws_access_key_id='access_key',
-            aws_secret_access_key='secret_key',
-            aws_session_token='session_token')
+        creator = self.create_client_creator()
+        credentials = Credentials(
+            access_key='access_key', secret_key='secret_key',
+            token='session_token')
+        client = creator.create_client(
+            'myservice', 'us-west-2', credentials=credentials)
 
         # Verify that we create an endpoint with a credentials object
         # matching our creds arguments.
-        args = endpoint_creator.create_endpoint.call_args
-        creds_used_for_client = args[1]['credentials']
-        self.assertEqual(creds_used_for_client.access_key, 'access_key')
-        self.assertEqual(creds_used_for_client.secret_key, 'secret_key')
-        self.assertEqual(creds_used_for_client.token, 'session_token')
+        self.assertEqual(client._request_signer._credentials, credentials)
 
     def test_event_emitted_when_invoked(self):
         event_emitter = hooks.HierarchicalEmitter()
-        endpoint_creator = mock.Mock()
-        endpoint = mock.Mock()
-        endpoint_creator.create_endpoint.return_value = endpoint
-        endpoint.make_request.return_value = (mock.Mock(status_code=200), {})
-        creator = self.create_client_creator(endpoint_creator, event_emitter)
+        creator = self.create_client_creator(event_emitter=event_emitter)
 
         calls = []
         handler = lambda **kwargs: calls.append(kwargs)
         event_emitter.register('before-call', handler)
 
-        service_client = creator.create_client('myservice', 'us-west-2')
+        service_client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
         service_client.test_operation(Foo='one', Bar='two')
         self.assertEqual(len(calls), 1)
 
@@ -323,8 +364,10 @@ class TestAutoGeneratedClient(unittest.TestCase):
         second_calls = []
         second_handler = lambda **kwargs: second_calls.append(kwargs)
 
-        first_client = creator.create_client('myservice', 'us-west-2')
-        second_client = creator.create_client('myservice', 'us-west-2')
+        first_client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
+        second_client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
 
         first_client.meta.events.register('before-call', first_handler)
         second_client.meta.events.register('before-call', second_handler)
@@ -361,12 +404,14 @@ class TestAutoGeneratedClient(unittest.TestCase):
         # Then any client created from this point forward from the
         # event_emitter passed into the ClientCreator will have this
         # handler.
-        first_client = creator.create_client('myservice', 'us-west-2')
+        first_client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
         first_client.test_operation(Foo='one', Bar='two')
         self.assertEqual(len(base_calls), 1)
 
         # Same thing if we create another client.
-        second_client = creator.create_client('myservice', 'us-west-2')
+        second_client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
         second_client.test_operation(Foo='one', Bar='two')
         self.assertEqual(len(base_calls), 2)
 
@@ -377,7 +422,8 @@ class TestAutoGeneratedClient(unittest.TestCase):
         creator = self.create_client_creator(event_emitter=event_emitter)
 
         # 1. Create a client.
-        first_client = creator.create_client('myservice', 'us-west-2')
+        first_client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
 
         # 2. Now register an event handler from the originating event emitter.
         base_calls = []
@@ -394,20 +440,16 @@ class TestAutoGeneratedClient(unittest.TestCase):
         # to avoid testing internal attributes.
         # Instead we try to test this via the public API:
         #   - Cloning the API with a new endpoint will use the new endopint.
-        endpoint_creator = mock.Mock()
-        endpoint = mock.Mock()
-        endpoint_creator.create_endpoint.return_value = endpoint
-        endpoint.make_request.return_value = (
-            mock.Mock(status_code=200),
-            {'type': 'from-original-endpoint'})
-        creator = self.create_client_creator(endpoint_creator)
+        event_emitter = hooks.HierarchicalEmitter()
+        creator = self.create_client_creator(event_emitter=event_emitter)
 
         new_endpoint = mock.Mock()
         new_endpoint.make_request.return_value = (
             mock.Mock(status_code=200),
             {'type': 'from-replaced-endpoint'})
 
-        service_client = creator.create_client('myservice', 'us-west-2')
+        service_client = creator.create_client(
+            'myservice', 'us-west-2', credentials=self.credentials)
         cloned = service_client.clone_client(endpoint=new_endpoint)
         response = cloned.test_operation(Foo='one', Bar='two')
 
diff --git a/tests/unit/test_cloudsearchdomain.py b/tests/unit/test_cloudsearchdomain.py
index 7c127e0bc..64108fe47 100644
--- a/tests/unit/test_cloudsearchdomain.py
+++ b/tests/unit/test_cloudsearchdomain.py
@@ -28,7 +28,7 @@ class TestCloudsearchOperations(BaseSessionTest):
             contentType='application/json', documents=stream)
         endpoint = service.get_endpoint(region_name='us-east-1',
                                         endpoint_url='http://example.com')
-        request = endpoint.create_request(built, signer=None)
+        request = endpoint.create_request(built)
         self.assertEqual(request.body, stream)
 
     def test_region_required_due_to_sigv4(self):
@@ -38,5 +38,6 @@ class TestCloudsearchOperations(BaseSessionTest):
         built = operation.build_parameters(
             contentType='application/json', documents=stream)
         # Note we're not giving a region name.
+        endpoint = service.get_endpoint(endpoint_url='http://example.com')
         with self.assertRaises(NoRegionError):
-            endpoint = service.get_endpoint(endpoint_url='http://example.com')
+            operation.call(endpoint, contentType='application/json', documents=stream)
diff --git a/tests/unit/test_endpoint.py b/tests/unit/test_endpoint.py
index 53e8bcfe8..90cce94a0 100644
--- a/tests/unit/test_endpoint.py
+++ b/tests/unit/test_endpoint.py
@@ -61,29 +61,6 @@ class TestGetEndpoint(unittest.TestCase):
         service.signature_version = signature_version
         return service
 
-    def test_auth_is_properly_created_for_endpoint(self):
-        service = self.create_mock_service('query', signature_version='v4')
-        endpoint = get_endpoint(service, 'us-west-2',
-                                'https://service.region.amazonaws.com')
-        self.assertIsInstance(endpoint.auth, SigV4Auth)
-
-    def test_unknown_auth_handler(self):
-        service = self.create_mock_service('query', signature_version='v5000')
-        with self.assertRaises(UnknownSignatureVersionError):
-            endpoint = get_endpoint(service, 'us-west-2',
-                                    'https://service.region.amazonaws.com')
-
-    def test_signature_version_is_none(self):
-        # If signature_version is set to None, we don't assign any auth classes
-        # to the endpoint.
-        service = self.create_mock_service('query', signature_version=None)
-        # Verify we have a signature_version attr and that it's None.  This is
-        # a different case from not having the 'signature_version' at all.
-        self.assertIsNone(service.signature_version)
-        endpoint = get_endpoint(service, 'us-west-2',
-                                'https://service.region.amazonaws.com')
-        self.assertIsNone(endpoint.auth)
-
     def test_get_endpoint_default_verify_ssl(self):
         service = self.create_mock_service('query')
         endpoint = get_endpoint(service, 'us-west-2',
@@ -130,8 +107,6 @@ class TestEndpointBase(unittest.TestCase):
         self.op = Mock()
         self.op.has_streaming_output = False
         self.op.metadata = {'protocol': 'json'}
-        self.signature_version = True
-        self.auth = Mock()
         self.event_emitter = Mock()
         self.event_emitter.emit.return_value = []
         self.factory_patch = patch(
@@ -139,8 +114,8 @@ class TestEndpointBase(unittest.TestCase):
         self.factory = self.factory_patch.start()
         self.endpoint = Endpoint(
             'us-west-2', 'https://ec2.us-west-2.amazonaws.com/',
-            auth=self.auth, user_agent='botoore', signature_version='v4',
-            endpoint_prefix='ec2', event_emitter=self.event_emitter)
+            user_agent='botoore', endpoint_prefix='ec2',
+            event_emitter=self.event_emitter)
         self.http_session = Mock()
         self.http_session.send.return_value = Mock(
             status_code=200, headers={}, content=b'{"Foo": "bar"}',
@@ -182,7 +157,7 @@ class TestEndpointFeatures(TestEndpointBase):
     def test_make_request_no_signature_version(self):
         self.endpoint = Endpoint(
             'us-west-2', 'https://ec2.us-west-2.amazonaws.com/',
-            auth=self.auth, user_agent='botoore', signature_version=None,
+            user_agent='botoore',
             endpoint_prefix='ec2', event_emitter=self.event_emitter)
         self.endpoint.http_session = self.http_session
 
@@ -235,9 +210,9 @@ class TestRetryInterface(TestEndpointBase):
         op.name = 'DescribeInstances'
         op.metadata = {'protocol': 'json'}
         self.event_emitter.emit.side_effect = [
-            [], # For initially preparing request
+            [(None, None)], # Request created.
             [(None, 0)],  # Check if retry needed. Retry needed.
-            [],  # For preparing the request again
+            [(None, None)], # Request created.
             [(None, None)]  # Check if retry needed. Retry not needed.
         ]
         self.endpoint.make_request(op, request_dict())
@@ -245,11 +220,11 @@ class TestRetryInterface(TestEndpointBase):
         self.assertEqual(self.event_emitter.emit.call_count, 4)
         # Check that all of the events are as expected.
         self.assertEqual(call_args[0][0][0],
-                         'before-auth.ec2')
+                         'request-created.ec2.DescribeInstances')
         self.assertEqual(call_args[1][0][0],
                          'needs-retry.ec2.DescribeInstances')
         self.assertEqual(call_args[2][0][0],
-                         'before-auth.ec2')
+                         'request-created.ec2.DescribeInstances')
         self.assertEqual(call_args[3][0][0],
                          'needs-retry.ec2.DescribeInstances')
 
@@ -257,9 +232,9 @@ class TestRetryInterface(TestEndpointBase):
         op = Mock()
         op.name = 'DescribeInstances'
         self.event_emitter.emit.side_effect = [
-            [], # For initially preparing request
+            [(None, None)], # Request created.
             [(None, 0)],  # Check if retry needed. Retry needed.
-            [],  # For preparing the request again
+            [(None, None)], # Request created
             [(None, None)]  # Check if retry needed. Retry not needed.
         ]
         self.http_session.send.side_effect = ConnectionError()
@@ -268,11 +243,11 @@ class TestRetryInterface(TestEndpointBase):
         self.assertEqual(self.event_emitter.emit.call_count, 4)
         # Check that all of the events are as expected.
         self.assertEqual(call_args[0][0][0],
-                         'before-auth.ec2')
+                         'request-created.ec2.DescribeInstances')
         self.assertEqual(call_args[1][0][0],
                          'needs-retry.ec2.DescribeInstances')
         self.assertEqual(call_args[2][0][0],
-                         'before-auth.ec2')
+                         'request-created.ec2.DescribeInstances')
         self.assertEqual(call_args[3][0][0],
                          'needs-retry.ec2.DescribeInstances')
 
@@ -300,11 +275,11 @@ class TestS3ResetStreamOnRetry(TestEndpointBase):
         request = request_dict()
         request['body'] = body
         self.event_emitter.emit.side_effect = [
-            [(None, 0)],  # Prepare initial request.
+            [(None, None)], # Request created.
             [(None, 0)],  # Check if retry needed. Needs Retry.
-            [(None, 0)],  # Prepare request again.
+            [(None, None)], # Request created.
             [(None, 0)],  # Check if retry needed again. Needs Retry.
-            [(None, 0)],  # Prepare request again.
+            [(None, None)], # Request created.
             [(None, None)], # Finally emit no rety is needed.
         ]
         self.endpoint.make_request(op, request)
@@ -323,7 +298,7 @@ class TestEndpointCreator(unittest.TestCase):
             'uri': 'https://endpoint.url', 'properties': {}
         }
         creator = EndpointCreator(resolver, 'us-west-2',
-                                  Mock(), Mock(), 'user-agent')
+                                  Mock(), 'user-agent')
         endpoint = creator.create_endpoint(self.service_model)
         self.assertEqual(endpoint.host, 'https://endpoint.url')
 
@@ -340,22 +315,6 @@ class TestEndpointCreator(unittest.TestCase):
         }
         original_region_name = 'us-west-2'
         creator = EndpointCreator(resolver, original_region_name,
-                                  Mock(), Mock(), 'user-agent')
+                                  Mock(), 'user-agent')
         endpoint = creator.create_endpoint(self.service_model)
         self.assertEqual(endpoint.region_name, 'us-east-1')
-
-    def test_endpoint_resolver_uses_signature_version(self):
-        resolver = Mock()
-        resolver.construct_endpoint.return_value = {
-            'uri': 'https://endpoint.url',
-            'properties': {
-                # Setting a signatureVersion in the properties
-                # back of an endpoint heuristic will override
-                # any other value when constructing an endpoint.
-                'signatureVersion': 'v4',
-            }
-        }
-        creator = EndpointCreator(resolver, 'us-west-2',
-                                  Mock(), Mock(), 'user-agent')
-        endpoint = creator.create_endpoint(self.service_model)
-        self.assertIsInstance(endpoint.auth, SigV4Auth)
diff --git a/tests/unit/test_handlers.py b/tests/unit/test_handlers.py
index 73eeafe2b..7c8bc0813 100644
--- a/tests/unit/test_handlers.py
+++ b/tests/unit/test_handlers.py
@@ -47,29 +47,8 @@ class TestHandlers(BaseSessionTest):
         converted_value = handlers.decode_quoted_jsondoc(value)
         self.assertEqual(converted_value, value)
 
-    def test_switch_to_sigv4(self):
-        event = self.session.create_event('service-data-loaded', 's3')
-        mock_session = mock.Mock()
-        mock_session.get_scoped_config.return_value = {
-            's3': {'signature_version': 's3v4'}
-        }
-        kwargs = {'service_data': {'metadata': {'signatureVersion': 's3'}},
-                  'service_name': 's3', 'session': mock_session}
-        self.session.emit(event, **kwargs)
-        self.assertEqual(
-            kwargs['service_data']['metadata']['signatureVersion'],
-            's3v4')
-
-    def test_noswitch_to_sigv4(self):
-        event = self.session.create_event('service-data-loaded', 's3')
-        mock_session = mock.Mock()
-        mock_session.get_scoped_config.return_value = {}
-        kwargs = {'service_data': {'metadata': {'signatureVersion': 's3'}},
-                  'service_name': 's3', 'session': mock_session}
-        self.session.emit(event, **kwargs)
-        self.assertEqual(
-            kwargs['service_data']['metadata']['signatureVersion'],
-            's3')
+    def test_disable_signing(self):
+        self.assertEqual(handlers.disable_signing(), '')
 
     def test_quote_source_header(self):
         for op in ('UploadPartCopy', 'CopyObject'):
@@ -85,15 +64,15 @@ class TestHandlers(BaseSessionTest):
         operation = mock.Mock()
         source_endpoint = mock.Mock()
         signed_request = mock.Mock()
-        signed_request.url = 'SIGNED_REQUEST'
-        source_endpoint.auth.credentials = mock.sentinel.credentials
+        signed_request.original.prepare().url = 'SIGNED_REQUEST'
         source_endpoint.create_request.return_value = signed_request
         operation.service.get_endpoint.return_value = source_endpoint
-        endpoint = mock.Mock()
-        endpoint.region_name = 'us-east-1'
+        request_signer = mock.Mock()
+        request_signer._region_name = 'us-east-1'
 
         params = {'SourceRegion': 'us-west-2'}
-        handlers.copy_snapshot_encrypted(operation, {'body': params}, endpoint)
+        handlers.copy_snapshot_encrypted(operation, {'body': params},
+                                         request_signer)
         self.assertEqual(params['PresignedUrl'], 'SIGNED_REQUEST')
         # We created an endpoint in the source region.
         operation.service.get_endpoint.assert_called_with('us-west-2')
@@ -112,13 +91,14 @@ class TestHandlers(BaseSessionTest):
         source_endpoint.auth.credentials = mock.sentinel.credentials
         source_endpoint.create_request.return_value = signed_request
         operation.service.get_endpoint.return_value = source_endpoint
-        endpoint = mock.Mock()
-        endpoint.region_name = 'us-west-1'
+        request_signer = mock.Mock()
+        request_signer._region_name = 'us-west-1'
 
         # The user provides us-east-1, but we will override this to
         # endpoint.region_name, of 'us-west-1' in this case.
         params = {'SourceRegion': 'us-west-2', 'DestinationRegion': 'us-east-1'}
-        handlers.copy_snapshot_encrypted(operation, {'body': params}, endpoint)
+        handlers.copy_snapshot_encrypted(operation, {'body': params},
+                                         request_signer)
         # Always use the DestinationRegion from the endpoint, regardless of
         # whatever value the user provides.
         self.assertEqual(params['DestinationRegion'], 'us-west-1')
@@ -279,26 +259,32 @@ class TestHandlers(BaseSessionTest):
         self.assertEqual(params, result)
 
     def test_fix_s3_host_initial(self):
-        endpoint = mock.Mock(region_name='us-west-2')
         request = AWSRequest(
             method='PUT',headers={},
             url='https://s3-us-west-2.amazonaws.com/bucket/key.txt'
         )
-        auth = mock.Mock()
-        handlers.fix_s3_host('foo', endpoint, request, auth)
+        region_name = 'us-west-2'
+        signature_version = 's3'
+        handlers.fix_s3_host(
+            request=request, signature_version=signature_version,
+            region_name=region_name)
         self.assertEqual(request.url, 'https://bucket.s3.amazonaws.com/key.txt')
         self.assertEqual(request.auth_path, '/bucket/key.txt')
 
     def test_fix_s3_host_only_applied_once(self):
-        endpoint = mock.Mock(region_name='us-west-2')
         request = AWSRequest(
             method='PUT',headers={},
             url='https://s3-us-west-2.amazonaws.com/bucket/key.txt'
         )
-        auth = mock.Mock()
-        handlers.fix_s3_host('foo', endpoint, request, auth)
+        region_name = 'us-west-2'
+        signature_version = 's3'
+        handlers.fix_s3_host(
+            request=request, signature_version=signature_version,
+            region_name=region_name)
         # Calling the handler again should not affect the end result:
-        handlers.fix_s3_host('foo', endpoint, request, auth)
+        handlers.fix_s3_host(
+            request=request, signature_version=signature_version,
+            region_name=region_name)
         self.assertEqual(request.url, 'https://bucket.s3.amazonaws.com/key.txt')
         # This was a bug previously.  We want to make sure that
         # calling fix_s3_host() again does not alter the auth_path.
@@ -339,14 +325,16 @@ class TestHandlers(BaseSessionTest):
                                             unique_id='retry-config-foo')
 
     def test_dns_style_not_used_for_get_bucket_location(self):
-        endpoint = mock.Mock(region_name='us-west-2')
         original_url = 'https://s3-us-west-2.amazonaws.com/bucket?location'
         request = AWSRequest(
             method='GET',headers={},
             url=original_url,
         )
-        auth = mock.Mock()
-        handlers.fix_s3_host('foo', endpoint, request, auth)
+        signature_version = 's3'
+        region_name = 'us-west-2'
+        handlers.fix_s3_host(
+            request=request, signature_version=signature_version,
+            region_name=region_name)
         # The request url should not have been modified because this is
         # a request for GetBucketLocation.
         self.assertEqual(request.url, original_url)
diff --git a/tests/unit/test_s3_addressing.py b/tests/unit/test_s3_addressing.py
index bfb06e7cc..e7545e452 100644
--- a/tests/unit/test_s3_addressing.py
+++ b/tests/unit/test_s3_addressing.py
@@ -22,6 +22,7 @@ import botocore.session
 from botocore import auth
 from botocore import credentials
 from botocore.exceptions import ServiceNotInRegionError
+from botocore.handlers import fix_s3_host
 
 
 class TestS3Addressing(BaseSessionTest):
@@ -29,6 +30,7 @@ class TestS3Addressing(BaseSessionTest):
     def setUp(self):
         super(TestS3Addressing, self).setUp()
         self.s3 = self.session.get_service('s3')
+        self.signature_version = 's3'
 
     @patch('botocore.response.get_response', Mock())
     def get_prepared_request(self, op, param, force_hmacv1=False):
@@ -36,10 +38,12 @@ class TestS3Addressing(BaseSessionTest):
         if force_hmacv1:
             self.endpoint.auth = auth.HmacV1Auth(
                 credentials.Credentials('foo', 'bar'))
-        self.endpoint._send_request = lambda prepared_request, operation: \
-                request.append(prepared_request)
-        self.endpoint.make_request(op.model, param)
-        return request[0]
+        def prepare_request(request, **kwargs):
+            fix_s3_host(request, self.signature_version,
+                        self.endpoint.region_name)
+            return request
+        self.endpoint.prepare_request = prepare_request
+        return self.endpoint.create_request(param, op)
 
     def test_list_objects_dns_name(self):
         self.endpoint = self.s3.get_endpoint('us-east-1')
@@ -48,7 +52,7 @@ class TestS3Addressing(BaseSessionTest):
         prepared_request = self.get_prepared_request(op, params,
                                                      force_hmacv1=True)
         self.assertEqual(prepared_request.url,
-                         'https://safename.s3.amazonaws.com/')
+                         'https://safename.s3.amazonaws.com')
 
     def test_list_objects_non_dns_name(self):
         self.endpoint = self.s3.get_endpoint('us-east-1')
@@ -65,9 +69,10 @@ class TestS3Addressing(BaseSessionTest):
         prepared_request = self.get_prepared_request(op, params,
                                                      force_hmacv1=True)
         self.assertEqual(prepared_request.url,
-                         'https://safename.s3.amazonaws.com/')
+                         'https://safename.s3.amazonaws.com')
 
     def test_list_objects_unicode_query_string_eu_central_1(self):
+        self.signature_version = 's3v4'
         self.endpoint = self.s3.get_endpoint('eu-central-1')
         op = self.s3.get_operation('ListObjects')
         params = op.build_parameters(bucket='safename',
diff --git a/tests/unit/test_service.py b/tests/unit/test_service.py
index b4a84a786..62c734fe3 100644
--- a/tests/unit/test_service.py
+++ b/tests/unit/test_service.py
@@ -61,13 +61,6 @@ class TestService(BaseSessionTest):
         self.assertEqual(endpoint.host, 'https://wherever.i.want.com')
         self.assertIsNone(endpoint.region_name)
 
-    def test_region_required_for_sigv4(self):
-        # However, if the service uses siv4 auth, then an exception
-        # is raised if we call get_endpoint without a region name.
-        service = self.session.get_service('cloudformation')
-        with self.assertRaises(botocore.exceptions.NoRegionError):
-            service.get_endpoint(endpoint_url='https://wherever.i.want.com')
-
     def test_region_required_for_non_global_endpoint(self):
         # If you don't provide an endpoint_url, than you need to
         # provide a region_name.
diff --git a/tests/unit/test_session.py b/tests/unit/test_session.py
index 67bd8e0d3..95eb0954e 100644
--- a/tests/unit/test_session.py
+++ b/tests/unit/test_session.py
@@ -367,6 +367,16 @@ class TestCreateClient(BaseSessionTest):
                          "explicit credentials were provided to the "
                          "create_client call.")
 
+class TestPerformOperation(BaseSessionTest):
+    def test_s3(self):
+        service = self.session.get_service('s3')
+        operation = service.get_operation('ListBuckets')
+        endpoint = service.get_endpoint('us-west-2')
+        endpoint._send_request = mock.Mock()
+        endpoint._send_request.return_value = [{}, {}]
+        response = operation.call(endpoint)
+        self.assertEqual(response, endpoint._send_request.return_value)
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tests/unit/test_signers.py b/tests/unit/test_signers.py
index 6d6445bbf..a9a95f9f1 100644
--- a/tests/unit/test_signers.py
+++ b/tests/unit/test_signers.py
@@ -27,15 +27,14 @@ class TestSigner(unittest.TestCase):
         self.credentials = Credentials('key', 'secret')
         self.emitter = mock.Mock()
         self.emitter.emit_until_response.return_value = (None, None)
-        self.config = {}
         self.signer = RequestSigner(
             'service_name', 'region_name', 'signing_name',
-            'v4', self.credentials, self.emitter, self.config)
+            'v4', self.credentials, self.emitter)
 
     def test_region_required_for_sigv4(self):
         self.signer = RequestSigner(
             'service_name', None, 'signing_name', 'v4', self.credentials,
-            self.emitter, self.config)
+            self.emitter)
 
         with self.assertRaises(NoRegionError):
             self.signer.sign('operation_name', mock.Mock())
@@ -87,7 +86,7 @@ class TestSigner(unittest.TestCase):
         self.emitter.emit_until_response.assert_called_with(
             'choose-signer.service_name.operation_name',
             signing_name='signing_name', region_name='region_name',
-            signature_version='v4', config=self.config)
+            signature_version='v4')
 
     def test_choose_signer_override(self):
         request = mock.Mock()