Skip to content

Commit a06a66f

Browse files
committed
Merge pull request #4 from zalando-stups/add-ignore-expire-feature
Added ignore_expire in manage() to continue using expired tokens in error cases
2 parents 4450c15 + 24a5e77 commit a06a66f

File tree

2 files changed

+55
-4
lines changed

2 files changed

+55
-4
lines changed

tests/test_tokens.py

+48-1
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,55 @@ def test_get_refresh_failure(monkeypatch, tmpdir):
138138
assert tok == 'oldtok'
139139
logger.warn.assert_called_with('Failed to refresh access token "%s" (but it is still valid): %s', 'mytok', exc)
140140

141-
tokens.TOKENS = {'mytok': {'scopes': ['myscope']}}
141+
tokens.TOKENS = {'mytok': {'scopes': ['myscope'], 'expires_at': 0}}
142142
with pytest.raises(Exception) as exc_info:
143143
tok = tokens.get('mytok')
144144
assert exc_info.value == exc
145145

146+
147+
def test_get_refresh_failure_ignore_expiration_no_access_token(monkeypatch, tmpdir):
148+
tokens.configure(dir=str(tmpdir), url='https://example.org')
149+
150+
with open(os.path.join(str(tmpdir), 'user.json'), 'w') as fd:
151+
json.dump({'application_username': 'app', 'application_password': 'pass'}, fd)
152+
153+
with open(os.path.join(str(tmpdir), 'client.json'), 'w') as fd:
154+
json.dump({'client_id': 'cid', 'client_secret': 'sec'}, fd)
155+
156+
exc = Exception('FAIL')
157+
response = MagicMock()
158+
response.raise_for_status.side_effect = exc
159+
monkeypatch.setattr('requests.post', lambda url, **kwargs: response)
160+
# we never got any access token
161+
tokens.TOKENS = {'mytok': {'ignore_expiration': True,
162+
'scopes': ['myscope'],
163+
# expired a long time ago..
164+
'expires_at': 0}}
165+
with pytest.raises(Exception) as exc_info:
166+
tok = tokens.get('mytok')
167+
assert exc_info.value == exc
168+
169+
170+
def test_get_refresh_failure_ignore_expiration(monkeypatch, tmpdir):
171+
tokens.configure(dir=str(tmpdir), url='https://example.org')
172+
173+
with open(os.path.join(str(tmpdir), 'user.json'), 'w') as fd:
174+
json.dump({'application_username': 'app', 'application_password': 'pass'}, fd)
175+
176+
with open(os.path.join(str(tmpdir), 'client.json'), 'w') as fd:
177+
json.dump({'client_id': 'cid', 'client_secret': 'sec'}, fd)
178+
179+
exc = Exception('FAIL')
180+
response = MagicMock()
181+
response.raise_for_status.side_effect = exc
182+
monkeypatch.setattr('requests.post', lambda url, **kwargs: response)
183+
logger = MagicMock()
184+
monkeypatch.setattr('tokens.logger', logger)
185+
tokens.TOKENS = {'mytok': {'access_token': 'expired-token',
186+
'ignore_expiration': True,
187+
'scopes': ['myscope'],
188+
# expired a long time ago..
189+
'expires_at': 0}}
190+
tok = tokens.get('mytok')
191+
assert tok == 'expired-token'
192+
logger.warn.assert_called_with('Failed to refresh access token "%s" (ignoring expiration): %s', 'mytok', exc)

tokens/__init__.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,10 @@ def configure(**kwargs):
5555
CONFIG.update(kwargs)
5656

5757

58-
def manage(token_name, scopes):
59-
TOKENS[token_name] = {'scopes': scopes}
58+
def manage(token_name, scopes, ignore_expiration=False):
59+
""" ignore_expiration will enable using expired tokens in get()
60+
in cases where you token service does not yield a new token """
61+
TOKENS[token_name] = {'scopes': scopes, 'ignore_expiration': ignore_expiration}
6062
init_fixed_tokens_from_env()
6163

6264

@@ -124,12 +126,14 @@ def get(token_name):
124126
access_token = token.get('access_token')
125127
if not access_token or time.time() > token['expires_at'] - REFRESH_BEFORE_SECS_LEFT:
126128
try:
127-
token = refresh(token_name)
129+
refresh(token_name)
128130
access_token = token.get('access_token')
129131
except Exception as e:
130132
if access_token and time.time() < token['expires_at'] + EXPIRATION_TOLERANCE_SECS:
131133
# apply some tolerance, still try our old token if it's still valid
132134
logger.warn('Failed to refresh access token "%s" (but it is still valid): %s', token_name, e)
135+
elif access_token and token.get('ignore_expiration'):
136+
logger.warn('Failed to refresh access token "%s" (ignoring expiration): %s', token_name, e)
133137
else:
134138
raise
135139

0 commit comments

Comments
 (0)