diff --git a/keystone/auth/controllers.py b/keystone/auth/controllers.py index fb2c9f1ba4..3e6af80f19 100644 --- a/keystone/auth/controllers.py +++ b/keystone/auth/controllers.py @@ -559,13 +559,23 @@ class Auth(controller.V3Controller): def revocation_list(self, context, auth=None): if not CONF.token.revoke_by_id: raise exception.Gone() + + audit_id_only = ('audit_id_only' in context['query_string']) + tokens = self.token_provider_api.list_revoked_tokens() for t in tokens: expires = t['expires'] if not (expires and isinstance(expires, six.text_type)): t['expires'] = utils.isotime(expires) + if audit_id_only: + t.pop('id', None) data = {'revoked': tokens} + + if audit_id_only: + # No need to obfuscate if no token IDs. + return data + json_data = jsonutils.dumps(data) signed_text = cms.cms_sign_text(json_data, CONF.signing.certfile, diff --git a/keystone/tests/unit/test_v3_auth.py b/keystone/tests/unit/test_v3_auth.py index dd738bb74f..e37ecb30f4 100644 --- a/keystone/tests/unit/test_v3_auth.py +++ b/keystone/tests/unit/test_v3_auth.py @@ -4857,3 +4857,35 @@ class TestFetchRevocationList(test_v3.RestfulTestCase): } self.assertEqual({'revoked': [exp_token_revoke_data]}, payload) + + def test_audit_id_only_no_tokens(self): + # When there's no revoked tokens and ?audit_id_only is used, the + # response is an empty list and is not signed. + res = self.get('/auth/tokens/OS-PKI/revoked?audit_id_only') + self.assertEqual({'revoked': []}, res.json) + + def test_audit_id_only_token(self): + # When there's a revoked token and ?audit_id_only is used, the + # response contains the audit_id of the token and is not signed. + token_res = self.v3_create_token( + self.build_authentication_request( + user_id=self.user['id'], + password=self.user['password'], + project_id=self.project['id'])) + + token_id = token_res.headers.get('X-Subject-Token') + token_data = token_res.json['token'] + + self.delete('/auth/tokens', headers={'X-Subject-Token': token_id}) + + res = self.get('/auth/tokens/OS-PKI/revoked?audit_id_only') + + def truncate(ts_str): + return ts_str[:19] + 'Z' # 2016-01-21T15:53:52 == 19 chars. + + exp_token_revoke_data = { + 'audit_id': token_data['audit_ids'][0], + 'expires': truncate(token_data['expires_at']), + } + + self.assertEqual({'revoked': [exp_token_revoke_data]}, res.json)