transport.requests: make credential refresh robust (#220)

add refresh_timeout parameter to AuthorizedSession constructor
set the retry adapter
diff --git a/google/auth/transport/requests.py b/google/auth/transport/requests.py
index a49d3de..2268243 100644
--- a/google/auth/transport/requests.py
+++ b/google/auth/transport/requests.py
@@ -16,6 +16,7 @@
 
 from __future__ import absolute_import
 
+import functools
 import logging
 
 try:
@@ -29,6 +30,7 @@
         ),
         caught_exc,
     )
+import requests.adapters  # pylint: disable=ungrouped-imports
 import requests.exceptions  # pylint: disable=ungrouped-imports
 import six  # pylint: disable=ungrouped-imports
 
@@ -146,22 +148,35 @@
             retried.
         max_refresh_attempts (int): The maximum number of times to attempt to
             refresh the credentials and retry the request.
+        refresh_timeout (Optional[int]): The timeout value in seconds for
+            credential refresh HTTP requests.
         kwargs: Additional arguments passed to the :class:`requests.Session`
             constructor.
     """
     def __init__(self, credentials,
                  refresh_status_codes=transport.DEFAULT_REFRESH_STATUS_CODES,
                  max_refresh_attempts=transport.DEFAULT_MAX_REFRESH_ATTEMPTS,
+                 refresh_timeout=None,
                  **kwargs):
         super(AuthorizedSession, self).__init__(**kwargs)
         self.credentials = credentials
         self._refresh_status_codes = refresh_status_codes
         self._max_refresh_attempts = max_refresh_attempts
+        self._refresh_timeout = refresh_timeout
+
+        auth_request_session = requests.Session()
+
+        # Using an adapter to make HTTP requests robust to network errors.
+        # This adapter retrys HTTP requests when network errors occur
+        # and the requests seems safely retryable.
+        retry_adapter = requests.adapters.HTTPAdapter(max_retries=3)
+        auth_request_session.mount("https://", retry_adapter)
+
         # Request instance used by internal methods (for example,
         # credentials.refresh).
         # Do not pass `self` as the session here, as it can lead to infinite
         # recursion.
-        self._auth_request = Request()
+        self._auth_request = Request(auth_request_session)
 
     def request(self, method, url, data=None, headers=None, **kwargs):
         """Implementation of Requests' request."""
@@ -198,7 +213,9 @@
                 response.status_code, _credential_refresh_attempt + 1,
                 self._max_refresh_attempts)
 
-            self.credentials.refresh(self._auth_request)
+            auth_request_with_timeout = functools.partial(
+                self._auth_request, timeout=self._refresh_timeout)
+            self.credentials.refresh(auth_request_with_timeout)
 
             # Recurse. Pass in the original headers, not our modified set.
             return self.request(