summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/source/admin/identity-use-trusts.rst9
-rw-r--r--doc/source/cli/commands.rst1
-rw-r--r--keystone/cmd/cli.py34
-rw-r--r--keystone/tests/unit/test_cli.py44
-rw-r--r--keystone/tests/unit/trust/test_backends.py228
-rw-r--r--keystone/trust/backends/sql.py15
-rw-r--r--releasenotes/notes/bug-1473292-c21481e6aec29ec2.yaml20
7 files changed, 349 insertions, 2 deletions
diff --git a/doc/source/admin/identity-use-trusts.rst b/doc/source/admin/identity-use-trusts.rst
index 077e2e9..a4e12f3 100644
--- a/doc/source/admin/identity-use-trusts.rst
+++ b/doc/source/admin/identity-use-trusts.rst
@@ -54,3 +54,12 @@ The delegation parameters are:
54 54
55**Duration** 55**Duration**
56 (Optional) Comprised of the start time and end time for the trust. 56 (Optional) Comprised of the start time and end time for the trust.
57
58
59Removing Expired Trusts
60===========================================================
61
62In the SQL trust stores expired trusts are not automatically
63removed. These trusts can be removed with::
64
65 $ keystone-manage trust_flush
diff --git a/doc/source/cli/commands.rst b/doc/source/cli/commands.rst
index b44f646..593bf6e 100644
--- a/doc/source/cli/commands.rst
+++ b/doc/source/cli/commands.rst
@@ -22,3 +22,4 @@ Available commands:
22* ``mapping_engine``: Test your federation mapping rules. 22* ``mapping_engine``: Test your federation mapping rules.
23* ``saml_idp_metadata``: Generate identity provider metadata. 23* ``saml_idp_metadata``: Generate identity provider metadata.
24* ``token_flush``: Purge expired tokens. 24* ``token_flush``: Purge expired tokens.
25* ``trust_flush``: Purge expired trusts. \ No newline at end of file
diff --git a/keystone/cmd/cli.py b/keystone/cmd/cli.py
index ba699ca..6c6b0b9 100644
--- a/keystone/cmd/cli.py
+++ b/keystone/cmd/cli.py
@@ -41,7 +41,6 @@ from keystone.federation import utils as mapping_engine
41from keystone.i18n import _ 41from keystone.i18n import _
42from keystone.server import backends 42from keystone.server import backends
43 43
44
45CONF = keystone.conf.CONF 44CONF = keystone.conf.CONF
46LOG = log.getLogger(__name__) 45LOG = log.getLogger(__name__)
47 46
@@ -676,6 +675,36 @@ class TokenFlush(BaseApp):
676 ) 675 )
677 676
678 677
678class TrustFlush(BaseApp):
679 """Flush expired trusts from the backend."""
680
681 name = 'trust_flush'
682
683 @classmethod
684 def add_argument_parser(cls, subparsers):
685 parser = super(TrustFlush, cls).add_argument_parser(subparsers)
686
687 parser.add_argument('--project-id', default=None,
688 help=('The id of the project of which the expired '
689 'trusts is to be purged'))
690 parser.add_argument('--trustor-user-id', default=None,
691 help=('The id of the trustor of which the expired '
692 'trusts is to be purged'))
693 parser.add_argument('--trustee-user-id', default=None,
694 help=('The id of the trustee of which the expired '
695 'trusts is to be purged'))
696 return parser
697
698 @classmethod
699 def main(cls):
700 drivers = backends.load_backends()
701 trust_manager = drivers['trust_api']
702 trust_manager.flush_expired_trusts(
703 project_id=CONF.command.project_id,
704 trustor_user_id=CONF.command.trustor_user_id,
705 trustee_user_id=CONF.command.trustee_user_id)
706
707
679class MappingPurge(BaseApp): 708class MappingPurge(BaseApp):
680 """Purge the mapping table.""" 709 """Purge the mapping table."""
681 710
@@ -1158,7 +1187,8 @@ CMDS = [
1158 SamlIdentityProviderMetadata, 1187 SamlIdentityProviderMetadata,
1159 TokenFlush, 1188 TokenFlush,
1160 TokenRotate, 1189 TokenRotate,
1161 TokenSetup 1190 TokenSetup,
1191 TrustFlush
1162] 1192]
1163 1193
1164 1194
diff --git a/keystone/tests/unit/test_cli.py b/keystone/tests/unit/test_cli.py
index 5cccc7d..8706633 100644
--- a/keystone/tests/unit/test_cli.py
+++ b/keystone/tests/unit/test_cli.py
@@ -1638,3 +1638,47 @@ class TestTokenFlush(unit.TestCase):
1638 tf = cli.TokenFlush() 1638 tf = cli.TokenFlush()
1639 tf.main() 1639 tf.main()
1640 self.assertThat(logging.output, matchers.Contains(expected_msg)) 1640 self.assertThat(logging.output, matchers.Contains(expected_msg))
1641
1642
1643class TestTrustFlush(unit.SQLDriverOverrides, unit.BaseTestCase):
1644
1645 class FakeConfCommand(object):
1646 def __init__(self, parent):
1647 self.extension = False
1648 self.project_id = parent.command_project_id
1649 self.trustor_user_id = parent.command_trustor_user_id
1650 self.trustee_user_id = parent.command_trustee_user_id
1651
1652 def setUp(self):
1653 # Set up preset cli options and a parser
1654 super(TestTrustFlush, self).setUp()
1655 self.useFixture(database.Database())
1656 self.config_fixture = self.useFixture(oslo_config.fixture.Config(CONF))
1657 self.config_fixture.register_cli_opt(cli.command_opt)
1658 # For unit tests that should not throw any erorrs,
1659 # Use the argument parser to test that the combinations work
1660 parser_test = argparse.ArgumentParser()
1661 subparsers = parser_test.add_subparsers()
1662 self.parser = cli.TrustFlush.add_argument_parser(subparsers)
1663
1664 def config_files(self):
1665 config_files = super(TestTrustFlush, self).config_files()
1666 config_files.append(unit.dirs.tests_conf('backend_sql.conf'))
1667 return config_files
1668
1669 def test_trust_flush(self):
1670 self.command_project_id = None
1671 self.command_trustor_user_id = None
1672 self.command_trustee_user_id = None
1673 self.useFixture(fixtures.MockPatchObject(
1674 CONF, 'command', self.FakeConfCommand(self)))
1675
1676 def fake_load_backends():
1677 return dict(
1678 trust_api=keystone.trust.core.Manager())
1679
1680 self.useFixture(fixtures.MockPatch(
1681 'keystone.server.backends.load_backends',
1682 side_effect=fake_load_backends))
1683 trust = cli.TrustFlush()
1684 trust.main()
diff --git a/keystone/tests/unit/trust/test_backends.py b/keystone/tests/unit/trust/test_backends.py
index 102c9b0..07e4753 100644
--- a/keystone/tests/unit/trust/test_backends.py
+++ b/keystone/tests/unit/trust/test_backends.py
@@ -18,6 +18,7 @@ from six.moves import range
18 18
19from keystone.common import provider_api 19from keystone.common import provider_api
20from keystone import exception 20from keystone import exception
21from keystone.tests.unit import core
21 22
22PROVIDERS = provider_api.ProviderAPIs 23PROVIDERS = provider_api.ProviderAPIs
23 24
@@ -182,3 +183,230 @@ class TrustTests(object):
182 uuid.uuid4().hex, 183 uuid.uuid4().hex,
183 trust_data, 184 trust_data,
184 roles) 185 roles)
186
187 def test_flush_expired_trusts(self):
188 roles = [{"id": "member"},
189 {"id": "other"},
190 {"id": "browser"}]
191 trust_ref1 = core.new_trust_ref(
192 self.user_foo['id'], self.user_two['id'],
193 project_id=self.tenant_bar['id'])
194 trust_ref1['expires_at'] = \
195 timeutils.utcnow() - datetime.timedelta(minutes=1)
196 trust_ref2 = core.new_trust_ref(
197 self.user_foo['id'], self.user_two['id'],
198 project_id=self.tenant_bar['id'])
199 trust_ref2['expires_at'] = \
200 timeutils.utcnow() + datetime.timedelta(minutes=1)
201
202 trust_data = PROVIDERS.trust_api.create_trust(trust_ref1['id'],
203 trust_ref1, roles)
204 self.assertIsNotNone(trust_data)
205 trust_data = PROVIDERS.trust_api.create_trust(trust_ref2['id'],
206 trust_ref2, roles)
207 self.assertIsNotNone(trust_data)
208
209 PROVIDERS.trust_api.flush_expired_trusts()
210 trusts = self.trust_api.list_trusts()
211 self.assertEqual(len(trusts), 1)
212 self.assertEqual(trust_ref2['id'], trusts[0]['id'])
213
214 def test_flush_expired_trusts_with_all_id(self):
215 roles = [{"id": "member"},
216 {"id": "other"},
217 {"id": "browser"}]
218 trust_ref1 = core.new_trust_ref(
219 self.user_foo['id'], self.user_foo['id'],
220 project_id=self.tenant_bar['id'])
221 trust_ref1['expires_at'] = \
222 timeutils.utcnow() - datetime.timedelta(minutes=1)
223 trust_ref2 = core.new_trust_ref(
224 self.user_foo['id'], self.user_two['id'],
225 project_id=self.tenant_bar['id'])
226 trust_ref2['expires_at'] = \
227 timeutils.utcnow() - datetime.timedelta(minutes=5)
228
229 trust_data = PROVIDERS.trust_api.create_trust(trust_ref1['id'],
230 trust_ref1, roles)
231 self.assertIsNotNone(trust_data)
232 trust_data = PROVIDERS.trust_api.create_trust(trust_ref2['id'],
233 trust_ref2, roles)
234 self.assertIsNotNone(trust_data)
235
236 PROVIDERS.trust_api.flush_expired_trusts(
237 project_id=self.tenant_bar['id'],
238 trustor_user_id=self.user_foo['id'],
239 trustee_user_id=self.user_two['id'])
240 trusts = self.trust_api.list_trusts()
241 self.assertEqual(len(trusts), 1)
242 self.assertEqual(trust_ref1['id'], trusts[0]['id'])
243
244 def test_flush_expired_trusts_with_no_project_id(self):
245 roles = [{"id": "member"},
246 {"id": "other"},
247 {"id": "browser"}]
248 trust_ref1 = core.new_trust_ref(
249 self.user_foo['id'], self.user_two['id'],
250 project_id=self.tenant_bar['id'])
251 trust_ref1['expires_at'] = \
252 timeutils.utcnow() - datetime.timedelta(minutes=1)
253 trust_ref2 = core.new_trust_ref(
254 self.user_foo['id'], self.user_two['id'],
255 project_id=self.tenant_bar['id'])
256 trust_ref2['expires_at'] = \
257 timeutils.utcnow() + datetime.timedelta(minutes=1)
258
259 trust_data = PROVIDERS.trust_api.create_trust(trust_ref1['id'],
260 trust_ref1, roles)
261 self.assertIsNotNone(trust_data)
262 trust_data = PROVIDERS.trust_api.create_trust(trust_ref2['id'],
263 trust_ref2, roles)
264 self.assertIsNotNone(trust_data)
265
266 PROVIDERS.trust_api.flush_expired_trusts(
267 trustor_user_id=self.user_foo['id'],
268 trustee_user_id=self.user_two['id'])
269 trusts = self.trust_api.list_trusts()
270 self.assertEqual(len(trusts), 1)
271 self.assertEqual(trust_ref2['id'], trusts[0]['id'])
272
273 def test_flush_expired_trusts_with_no_trustor_id(self):
274 roles = [{"id": "member"},
275 {"id": "other"},
276 {"id": "browser"}]
277 trust_ref1 = core.new_trust_ref(
278 self.user_foo['id'], self.user_two['id'],
279 project_id=self.tenant_bar['id'])
280 trust_ref1['expires_at'] = \
281 timeutils.utcnow() - datetime.timedelta(minutes=1)
282 trust_ref2 = core.new_trust_ref(
283 self.user_foo['id'], self.user_two['id'],
284 project_id=self.tenant_bar['id'])
285 trust_ref2['expires_at'] = \
286 timeutils.utcnow() + datetime.timedelta(minutes=1)
287
288 trust_data = PROVIDERS.trust_api.create_trust(trust_ref1['id'],
289 trust_ref1, roles)
290 self.assertIsNotNone(trust_data)
291 trust_data = PROVIDERS.trust_api.create_trust(trust_ref2['id'],
292 trust_ref2, roles)
293 self.assertIsNotNone(trust_data)
294
295 PROVIDERS.trust_api.flush_expired_trusts(
296 project_id=self.tenant_bar['id'],
297 trustee_user_id=self.user_two['id'])
298 trusts = self.trust_api.list_trusts()
299 self.assertEqual(len(trusts), 1)
300 self.assertEqual(trust_ref2['id'], trusts[0]['id'])
301
302 def test_flush_expired_trusts_with_no_trustee_id(self):
303 roles = [{"id": "member"},
304 {"id": "other"},
305 {"id": "browser"}]
306 trust_ref1 = core.new_trust_ref(
307 self.user_foo['id'], self.user_two['id'],
308 project_id=self.tenant_bar['id'])
309 trust_ref1['expires_at'] = \
310 timeutils.utcnow() - datetime.timedelta(minutes=1)
311 trust_ref2 = core.new_trust_ref(
312 self.user_foo['id'], self.user_two['id'],
313 project_id=self.tenant_bar['id'])
314 trust_ref2['expires_at'] = \
315 timeutils.utcnow() + datetime.timedelta(minutes=1)
316
317 trust_data = PROVIDERS.trust_api.create_trust(trust_ref1['id'],
318 trust_ref1, roles)
319 self.assertIsNotNone(trust_data)
320 trust_data = PROVIDERS.trust_api.create_trust(trust_ref2['id'],
321 trust_ref2, roles)
322 self.assertIsNotNone(trust_data)
323
324 PROVIDERS.trust_api.flush_expired_trusts(
325 project_id=self.tenant_bar['id'],
326 trustor_user_id=self.user_foo['id'])
327 trusts = self.trust_api.list_trusts()
328 self.assertEqual(len(trusts), 1)
329 self.assertEqual(trust_ref2['id'], trusts[0]['id'])
330
331 def test_flush_expired_trusts_with_project_id(self):
332 roles = [{"id": "member"},
333 {"id": "other"},
334 {"id": "browser"}]
335 trust_ref1 = core.new_trust_ref(
336 self.user_foo['id'], self.user_two['id'],
337 project_id=self.tenant_bar['id'])
338 trust_ref1['expires_at'] = \
339 timeutils.utcnow() - datetime.timedelta(minutes=1)
340 trust_ref2 = core.new_trust_ref(
341 self.user_foo['id'], self.user_two['id'],
342 project_id=self.user_foo['id'])
343 trust_ref2['expires_at'] = \
344 timeutils.utcnow() - datetime.timedelta(minutes=5)
345
346 trust_data = PROVIDERS.trust_api.create_trust(trust_ref1['id'],
347 trust_ref1, roles)
348 self.assertIsNotNone(trust_data)
349 trust_data = PROVIDERS.trust_api.create_trust(trust_ref2['id'],
350 trust_ref2, roles)
351 self.assertIsNotNone(trust_data)
352
353 PROVIDERS.trust_api.flush_expired_trusts(
354 project_id=self.tenant_bar['id'])
355 trusts = self.trust_api.list_trusts()
356 self.assertEqual(len(trusts), 1)
357 self.assertEqual(trust_ref2['id'], trusts[0]['id'])
358
359 def test_flush_expired_trusts_with_trustee_id(self):
360 roles = [{"id": "member"},
361 {"id": "other"},
362 {"id": "browser"}]
363 trust_ref1 = core.new_trust_ref(
364 self.user_foo['id'], self.user_two['id'],
365 project_id=self.tenant_bar['id'])
366 trust_ref1['expires_at'] = \
367 timeutils.utcnow() - datetime.timedelta(minutes=1)
368 trust_ref2 = core.new_trust_ref(
369 self.user_foo['id'], self.user_foo['id'],
370 project_id=self.tenant_bar['id'])
371 trust_ref2['expires_at'] = \
372 timeutils.utcnow() - datetime.timedelta(minutes=5)
373
374 trust_data = PROVIDERS.trust_api.create_trust(trust_ref1['id'],
375 trust_ref1, roles)
376 self.assertIsNotNone(trust_data)
377 trust_data = PROVIDERS.trust_api.create_trust(trust_ref2['id'],
378 trust_ref2, roles)
379 self.assertIsNotNone(trust_data)
380 PROVIDERS.trust_api.flush_expired_trusts(
381 trustee_user_id=self.user_two['id'])
382 trusts = self.trust_api.list_trusts()
383 self.assertEqual(len(trusts), 1)
384 self.assertEqual(trust_ref2['id'], trusts[0]['id'])
385
386 def test_flush_expired_trusts_with_trustor_id(self):
387 roles = [{"id": "member"},
388 {"id": "other"},
389 {"id": "browser"}]
390 trust_ref1 = core.new_trust_ref(
391 self.user_foo['id'], self.user_two['id'],
392 project_id=self.tenant_bar['id'])
393 trust_ref1['expires_at'] = \
394 timeutils.utcnow() - datetime.timedelta(minutes=1)
395 trust_ref2 = core.new_trust_ref(
396 self.user_two['id'], self.user_two['id'],
397 project_id=self.tenant_bar['id'])
398 trust_ref2['expires_at'] = \
399 timeutils.utcnow() - datetime.timedelta(minutes=5)
400
401 trust_data = PROVIDERS.trust_api.create_trust(trust_ref1['id'],
402 trust_ref1, roles)
403 self.assertIsNotNone(trust_data)
404 trust_data = PROVIDERS.trust_api.create_trust(trust_ref2['id'],
405 trust_ref2, roles)
406 self.assertIsNotNone(trust_data)
407
408 PROVIDERS.trust_api.flush_expired_trusts(
409 trustor_user_id=self.user_foo['id'])
410 trusts = self.trust_api.list_trusts()
411 self.assertEqual(len(trusts), 1)
412 self.assertEqual(trust_ref2['id'], trusts[0]['id'])
diff --git a/keystone/trust/backends/sql.py b/keystone/trust/backends/sql.py
index a4b3470..2713c51 100644
--- a/keystone/trust/backends/sql.py
+++ b/keystone/trust/backends/sql.py
@@ -188,3 +188,18 @@ class Trust(base.TrustDriverBase):
188 trusts = query.filter_by(project_id=project_id) 188 trusts = query.filter_by(project_id=project_id)
189 for trust_ref in trusts: 189 for trust_ref in trusts:
190 trust_ref.deleted_at = timeutils.utcnow() 190 trust_ref.deleted_at = timeutils.utcnow()
191
192 def flush_expired_trusts(self, project_id=None, trustor_user_id=None,
193 trustee_user_id=None):
194 with sql.session_for_write() as session:
195 query = session.query(TrustModel)
196 if project_id:
197 query = query.filter_by(project_id=project_id)
198 if trustor_user_id:
199 query = query.filter_by(trustor_user_id=trustor_user_id)
200 if trustee_user_id:
201 query = query.filter_by(trustee_user_id=trustee_user_id)
202 for ref in query:
203 if ref.expires_at is not None:
204 if ref.expires_at < timeutils.utcnow():
205 session.delete(ref)
diff --git a/releasenotes/notes/bug-1473292-c21481e6aec29ec2.yaml b/releasenotes/notes/bug-1473292-c21481e6aec29ec2.yaml
new file mode 100644
index 0000000..888c435
--- /dev/null
+++ b/releasenotes/notes/bug-1473292-c21481e6aec29ec2.yaml
@@ -0,0 +1,20 @@
1---
2feature:
3 - |
4 [`Bug 1473292 <https://bugs.launchpad.net/keystone/+bug/1473292>`_]
5 As trusts created by user are stored in database resulting db it to grow
6 larger as trusts that are expired are not automatically purged by keystone.
7 Thus this implements TrustFlush via keystone-manage to delete expired trusts.
8
9 Command:
10
11 $ keystone-manage trust-flush [Options]
12
13 Options:
14
15 project-id <string>: To purge expired trusts of given project-id.
16 trustor-user-id <string>: To purge expired trusts of given trustor-id.
17 trustee-user-id <string>: To purge expired trusts of given trustee-id.
18
19
20