Skip to content

Commit

Permalink
Merge pull request #4 from zalando-stups/add-ignore-expire-feature
Browse files Browse the repository at this point in the history
Added ignore_expire in manage() to continue using expired tokens in error cases
  • Loading branch information
hjacobs committed Feb 9, 2016
2 parents 4450c15 + 24a5e77 commit a06a66f
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 4 deletions.
49 changes: 48 additions & 1 deletion tests/test_tokens.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,55 @@ def test_get_refresh_failure(monkeypatch, tmpdir):
assert tok == 'oldtok'
logger.warn.assert_called_with('Failed to refresh access token "%s" (but it is still valid): %s', 'mytok', exc)

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


def test_get_refresh_failure_ignore_expiration_no_access_token(monkeypatch, tmpdir):
tokens.configure(dir=str(tmpdir), url='https://example.org')

with open(os.path.join(str(tmpdir), 'user.json'), 'w') as fd:
json.dump({'application_username': 'app', 'application_password': 'pass'}, fd)

with open(os.path.join(str(tmpdir), 'client.json'), 'w') as fd:
json.dump({'client_id': 'cid', 'client_secret': 'sec'}, fd)

exc = Exception('FAIL')
response = MagicMock()
response.raise_for_status.side_effect = exc
monkeypatch.setattr('requests.post', lambda url, **kwargs: response)
# we never got any access token
tokens.TOKENS = {'mytok': {'ignore_expiration': True,
'scopes': ['myscope'],
# expired a long time ago..
'expires_at': 0}}
with pytest.raises(Exception) as exc_info:
tok = tokens.get('mytok')
assert exc_info.value == exc


def test_get_refresh_failure_ignore_expiration(monkeypatch, tmpdir):
tokens.configure(dir=str(tmpdir), url='https://example.org')

with open(os.path.join(str(tmpdir), 'user.json'), 'w') as fd:
json.dump({'application_username': 'app', 'application_password': 'pass'}, fd)

with open(os.path.join(str(tmpdir), 'client.json'), 'w') as fd:
json.dump({'client_id': 'cid', 'client_secret': 'sec'}, fd)

exc = Exception('FAIL')
response = MagicMock()
response.raise_for_status.side_effect = exc
monkeypatch.setattr('requests.post', lambda url, **kwargs: response)
logger = MagicMock()
monkeypatch.setattr('tokens.logger', logger)
tokens.TOKENS = {'mytok': {'access_token': 'expired-token',
'ignore_expiration': True,
'scopes': ['myscope'],
# expired a long time ago..
'expires_at': 0}}
tok = tokens.get('mytok')
assert tok == 'expired-token'
logger.warn.assert_called_with('Failed to refresh access token "%s" (ignoring expiration): %s', 'mytok', exc)
10 changes: 7 additions & 3 deletions tokens/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@ def configure(**kwargs):
CONFIG.update(kwargs)


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


Expand Down Expand Up @@ -124,12 +126,14 @@ def get(token_name):
access_token = token.get('access_token')
if not access_token or time.time() > token['expires_at'] - REFRESH_BEFORE_SECS_LEFT:
try:
token = refresh(token_name)
refresh(token_name)
access_token = token.get('access_token')
except Exception as e:
if access_token and time.time() < token['expires_at'] + EXPIRATION_TOLERANCE_SECS:
# apply some tolerance, still try our old token if it's still valid
logger.warn('Failed to refresh access token "%s" (but it is still valid): %s', token_name, e)
elif access_token and token.get('ignore_expiration'):
logger.warn('Failed to refresh access token "%s" (ignoring expiration): %s', token_name, e)
else:
raise

Expand Down

0 comments on commit a06a66f

Please sign in to comment.