Skip to content

Commit 1ffbeaa

Browse files
committed
Refresh OAuth2 tokens when expired
The importer was raising 403 errors when the OAuth2 token expired. This patch refreshes the token and retries to fetch again the data. Signed-off-by: Santiago Dueñas <sduenas@bitergia.com>
1 parent 303b56a commit 1ffbeaa

2 files changed

Lines changed: 51 additions & 6 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
title: OAuth2 token refreshing
3+
category: added
4+
author: Santiago Dueñas <sduenas@bitergia.com>
5+
issue: null
6+
notes: >
7+
OAuth2 token will be refreshed when they expired.

sortinghat/core/importer/backends/eclipse.py

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,12 @@ class EclipseFoundationAPIClient:
206206
ECLIPSE_API_URL = "https://api.eclipse.org"
207207
ECLIPSE_ACCOUNTS_URL = "https://accounts.eclipse.org"
208208
OAUTH_TOKEN_ENDPOINT = "https://accounts.eclipse.org/oauth2/token"
209+
ECLIPSE_SCOPE = "eclipsefdn_view_all_profiles"
209210

210211
def __init__(self):
211212
self.token = None
213+
self.user_id = None
214+
self.password = None
212215

213216
def login(self, user_id, password):
214217
"""Login on the Eclipse platform.
@@ -217,10 +220,12 @@ def login(self, user_id, password):
217220
"eclipsefdn_view_all_profiles" that will allow us to
218221
fetch all the info about profiles/identities.
219222
"""
223+
self.user_id = user_id
224+
self.password = password
220225
self.token = self._authenticate(
221-
user_id,
222-
password,
223-
"eclipsefdn_view_all_profiles",
226+
self.user_id,
227+
self.password,
228+
self.ECLIPSE_SCOPE,
224229
)
225230

226231
def logout(self):
@@ -281,8 +286,7 @@ def _fetch(self, url, params=None):
281286
"""Generic query to Eclipse usr API."""
282287

283288
try:
284-
response = requests.get(url, params=params, auth=self.token)
285-
response.raise_for_status()
289+
data = self._fetch_retry(url, params)
286290
except requests.exceptions.HTTPError as error:
287291
# Ignore 5xx errors
288292
if 500 <= error.response.status_code < 600:
@@ -296,7 +300,41 @@ def _fetch(self, url, params=None):
296300
else:
297301
raise error
298302

299-
return response.json()
303+
return data
304+
305+
def _fetch_retry(self, url, params=None):
306+
"""Fetch URL retrying in case of 403 or 500 errors.
307+
308+
When getting a 403 error, the method will try to authenticate
309+
again in case the OAuth2 token has expired.
310+
"""
311+
retries = 0
312+
max_retries = 3
313+
314+
while retries < max_retries:
315+
response = requests.get(url, params=params, auth=self.token)
316+
317+
if response.status_code == 200:
318+
return response.json()
319+
elif response.status_code == 403:
320+
# Refresh token if needed and try again
321+
if self.token_oauth.expires_at <= datetime_utcnow():
322+
self.token = self._authenticate(
323+
self.user_id,
324+
self.password,
325+
self.ECLIPSE_SCOPE,
326+
)
327+
retries += 1
328+
elif 500 <= response.status_code < 600:
329+
# Errors could have been related to server overloading
330+
retries += 1
331+
else:
332+
response.raise_for_status()
333+
334+
response = requests.get(url, params=params, auth=self.token)
335+
response.raise_for_status()
336+
337+
return response
300338

301339
def _authenticate(self, client_id, client_secret, scope):
302340
"""Authenticate using OAuth2.

0 commit comments

Comments
 (0)