retry HTTP requests 3 times (fixes #21783)

Retry is applied to access token request and user info requests (through
OAuth2Session). There is a small exponential backoff of 0.5 and 1s.

Also decrease log level of message for failure of retrieval of the
access token or the user info to the level WARNING, that's never been a
problem for the user, as he was correctly redirected to its origin
(usually and IdP endpoint).
This commit is contained in:
Benjamin Dauvergne 2018-02-11 22:09:36 +01:00
parent 738066a5d9
commit c701e61043
2 changed files with 34 additions and 7 deletions

View File

@ -5,6 +5,10 @@ import json
import datetime
import uuid
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
from django.core.urlresolvers import reverse
from django.conf import settings
from django.shortcuts import resolve_url
@ -158,3 +162,24 @@ def apply_user_info_mappings(user, user_info):
tags.add(mapping['tag'])
if save_user:
user.save()
def requests_retry_session(
retries=3,
backoff_factor=0.5,
status_forcelist=(500, 502, 504),
session=None,
):
'''Create a requests session which retries after 0.5s then 1s'''
session = session or requests.Session()
retry = Retry(
total=retries,
read=retries,
connect=retries,
backoff_factor=backoff_factor,
status_forcelist=status_forcelist,
)
adapter = HTTPAdapter(max_retries=retry)
session.mount('http://', adapter)
session.mount('https://', adapter)
return session

View File

@ -1,9 +1,9 @@
import uuid
import requests
import logging
import json
import urlparse
import urllib
import requests
from requests_oauthlib import OAuth2Session
@ -86,10 +86,11 @@ def resolve_access_token(authorization_code, redirect_uri, logger):
}
logger.debug('access token request %s', data)
try:
response = requests.post(
session = utils.requests_retry_session()
response = session.post(
app_settings.token_url, data=data,
verify=app_settings.verify_certificate,
allow_redirects=False, timeout=10)
allow_redirects=False, timeout=3)
if response.status_code != 200:
try:
data = response.json()
@ -99,7 +100,7 @@ def resolve_access_token(authorization_code, redirect_uri, logger):
logger.warning(u'oauth2 error on access token retrieval: %r', response.content)
return
except requests.exceptions.RequestException as e:
logger.error(u'unable to retrieve access token {}'.format(e))
logger.warning(u'unable to retrieve access token {}'.format(e))
else:
try:
response = response.json()
@ -193,7 +194,7 @@ class FcOAuthSessionViewMixin(LoggerMixin):
data = self.oauth_session().get(url, verify=verify, allow_redirects=False, timeout=3)
data.raise_for_status()
except requests.exceptions.RequestException as e:
self.logger.error(u'unable to retrieve ressource from {} due to {}'.format(url, e))
self.logger.warning(u'unable to retrieve ressource from {} due to {}'.format(url, e))
else:
try:
data = data.json()
@ -270,8 +271,9 @@ class FcOAuthSessionViewMixin(LoggerMixin):
self.logger.debug('fc id_token %s', self.id_token)
for key in self.id_token:
setattr(self, key, self.id_token[key])
self.oauth_session = lambda: OAuth2Session(
app_settings.client_id, token=self.token)
self.oauth_session = lambda: utils.requests_retry_session(
session=OAuth2Session(
app_settings.client_id, token=self.token))
self.user_info = self.get_user_info()
if not self.user_info:
msg = 'userinfo resolution failed : {}'.format(self.token)