Beispiel #1
0
 def do_fetch():
   # client_secret is not really a secret in that case. So an attacker can
   # impersonate service's identity in OAuth2 flow. But that's generally
   # fine as long as a list of allowed redirect_uri's associated with client_id
   # is limited to 'localhost' or 'urn:ietf:wg:oauth:2.0:oob'. In that case
   # attacker needs some process running on user's machine to successfully
   # complete the flow and grab access_token. When you have malicious code
   # running on your machine you're screwed anyway.
   response = requests.get(
       '%s/auth/api/v1/server/oauth_config' % urlhost.rstrip('/'),
       verify=tools.get_cacerts_bundle())
   if response.status_code == 200:
     try:
       config = response.json()
       if not isinstance(config, dict):
         raise ValueError()
       return _ServiceConfig(
           config['client_id'],
           config['client_not_so_secret'],
           config.get('primary_url'))
     except (KeyError, ValueError) as err:
       logging.error('Invalid response from the service: %s', err)
   else:
     logging.warning(
         'Error when fetching oauth_config, HTTP status code %d',
         response.status_code)
   return None
Beispiel #2
0
 def __init__(self):
   super(RequestsLibEngine, self).__init__()
   self.session = requests.Session()
   # Configure session.
   self.session.trust_env = False
   self.session.verify = tools.get_cacerts_bundle()
   # Configure connection pools.
   for protocol in ('https://', 'http://'):
     self.session.mount(protocol, adapters.HTTPAdapter(
         pool_connections=64,
         pool_maxsize=64,
         max_retries=0,
         pool_block=False))
Beispiel #3
0
 def __init__(self):
   super(RequestsLibEngine, self).__init__()
   self.session = requests.Session()
   # Configure session.
   self.session.trust_env = False
   self.session.verify = tools.get_cacerts_bundle()
   # Configure connection pools.
   for protocol in ('https://', 'http://'):
     self.session.mount(protocol, adapters.HTTPAdapter(
         pool_connections=64,
         pool_maxsize=64,
         max_retries=0,
         pool_block=False))
Beispiel #4
0
def authenticated_http_request(service_account, *args, **kwargs):
  """Sends an OAuth2-authenticated HTTP request.

  Args:
    service_account: Service account to use. For GCE, the name of the service
      account, otherwise the path to the service account JSON file.

  Raises:
    AuthenticatedHttpRequestFailure
  """
  scopes = kwargs.pop('scopes', [])
  kwargs['headers'] = kwargs.get('headers', {}).copy()
  http = httplib2.Http(ca_certs=tools.get_cacerts_bundle())

  # Authorize the request. In general, we need to produce an OAuth2 bearer token
  # using a service account JSON file. However on GCE there is a shortcut: it
  # can fetch the current bearer token right from the instance metadata without
  # the need for the oauth2client.client library.
  if platforms.is_gce():
    try:
      gce_bearer_token, _ = platforms.gce.oauth2_access_token_with_expiration(
          account=service_account)
    except (IOError, urllib2.HTTPError) as e:
      raise AuthenticatedHttpRequestFailure(e)
    kwargs['headers']['Authorization'] = 'Bearer %s' % gce_bearer_token
  else:
    try:
      oauth2client = get_oauth2_client(service_account, scopes)
    except (IOError, OSError, ValueError) as e:
      raise AuthenticatedHttpRequestFailure(e)
    http = oauth2client.authorize(http)

  try:
    return http.request(*args, **kwargs)
  except client.Error as e:
    raise AuthenticatedHttpRequestFailure(e)
Beispiel #5
0
def authenticated_http_request(service_account, *args, **kwargs):
  """Sends an OAuth2-authenticated HTTP request.

  Args:
    service_account: Service account to use. For GCE, the name of the service
      account, otherwise the path to the service account JSON file.

  Raises:
    AuthenticatedHttpRequestFailure
  """
  scopes = kwargs.pop('scopes', [])
  kwargs['headers'] = kwargs.get('headers', {}).copy()
  http = httplib2.Http(ca_certs=tools.get_cacerts_bundle())

  # Authorize the request. In general, we need to produce an OAuth2 bearer token
  # using a service account JSON file. However on GCE there is a shortcut: it
  # can fetch the current bearer token right from the instance metadata without
  # the need for the oauth2client.client library.
  if platforms.is_gce():
    try:
      gce_bearer_token = platforms.gce.oauth2_access_token(
          account=service_account)
    except (IOError, urllib2.HTTPError) as e:
      raise AuthenticatedHttpRequestFailure(e)
    kwargs['headers']['Authorization'] = 'Bearer %s' % gce_bearer_token
  else:
    try:
      oauth2client = get_oauth2_client(service_account, scopes)
    except (IOError, OSError, ValueError) as e:
      raise AuthenticatedHttpRequestFailure(e)
    http = oauth2client.authorize(http)

  try:
    return http.request(*args, **kwargs)
  except client.Error as e:
    raise AuthenticatedHttpRequestFailure(e)
Beispiel #6
0
def create_access_token(urlhost, config, allow_user_interaction):
  """Mints and caches new access_token, launching OAuth2 dance if necessary.

  Args:
    urlhost: base URL of a host to make OAuth2 token for.
    config: OAuthConfig instance.
    allow_user_interaction: if False, do not use interactive browser based
        flow (return None instead if it is required).

  Returns:
    AccessToken on success.
    None on error or if OAuth2 flow was interrupted.
  """
  assert isinstance(config, OAuthConfig)
  if config.disabled:
    return None
  auth_service_url = _fetch_auth_service_url(urlhost)
  if not auth_service_url:
    return None

  storage = _get_storage(auth_service_url, config)
  credentials = None

  if config.service_account_json:
    # 2-legged flow that uses service account credentials.
    try:
      service_account = _load_service_account_json(config.service_account_json)
    except BadServiceAccountCredentials as e:
      logging.error('Bad service account credentials: %s', e)
      return None

    # Body of token refresh request (with JWT assertion signed with secret key).
    body = urllib.urlencode({
      'assertion': _make_assertion_jwt(service_account),
      'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
    })

    # Exchange it for access_token.
    http = httplib2.Http(ca_certs=tools.get_cacerts_bundle())
    resp, content = http.request(
        uri=OAUTH_TOKEN_ENDPOINT,
        method='POST',
        body=body,
        headers={'Content-Type': 'application/x-www-form-urlencoded'})
    if resp.status != 200:
      logging.error(
          'Failed to grab access token for service account: %r', content)
      return None

    try:
      token = json.loads(content)
      access_token = token['access_token']
      expires_at = None
      if 'expires_in' in token:
        expires_at = datetime.datetime.utcnow()
        expires_at += datetime.timedelta(seconds=int(token['expires_in']))
    except (KeyError, ValueError) as e:
      logging.error('Unexpected access token response format: %s', e)
      return None

    credentials = client.OAuth2Credentials(
        access_token=access_token,
        client_id=service_account.client_id,
        client_secret=None,
        refresh_token=None,
        token_expiry=expires_at,
        token_uri=None,
        user_agent=None)
  else:
    # 3-legged flow with (perhaps cached) refresh token.
    credentials = storage.get()
    refreshed = False
    if credentials and not credentials.invalid:
      try:
        credentials.refresh(httplib2.Http(ca_certs=tools.get_cacerts_bundle()))
        refreshed = True
      except client.Error as err:
        logging.error('OAuth error: %s', err)

    # Refresh token is missing or invalid, go through full flow.
    if not refreshed:
      if not allow_user_interaction:
        return None
      credentials = _run_oauth_dance(auth_service_url, config)
      if not credentials:
        return None

  # Success.
  logging.info('OAuth access_token refreshed. Expires in %s.',
      credentials.token_expiry - datetime.datetime.utcnow())
  credentials.set_store(storage)
  storage.put(credentials)
  return AccessToken(credentials.access_token, credentials.token_expiry)