Merge lp:~yolanda.robla/ubuntu/precise/keystone/essex-sru into lp:ubuntu/precise-updates/keystone

Proposed by Yolanda Robla on 2012-12-18
Status: Merged
Merge reported by: James Page
Merged at revision: not available
Proposed branch: lp:~yolanda.robla/ubuntu/precise/keystone/essex-sru
Merge into: lp:ubuntu/precise-updates/keystone
Diff against target: 33638 lines (+30158/-3073)
34 files modified
.pc/applied-patches (+0/-3)
.pc/fix-ubuntu-tests.patch/tests/test_keystoneclient.py (+9/-9)
.pc/keystone-CVE-2012-3542.patch/keystone/identity/core.py (+0/-625)
.pc/keystone-CVE-2012-4413.patch/keystone/identity/core.py (+0/-626)
.pc/keystone-CVE-2012-4413.patch/keystone/token/core.py (+0/-107)
.pc/keystone-CVE-2012-4413.patch/tests/test_keystoneclient.py (+0/-970)
.pc/keystone-CVE-2012-5571.patch/keystone/contrib/ec2/core.py (+0/-347)
ChangeLog (+29735/-0)
PKG-INFO (+10/-0)
debian/changelog (+29/-0)
debian/keystone.logrotate (+3/-0)
debian/patches/fix-ubuntu-tests.patch (+10/-12)
debian/patches/keystone-CVE-2012-3542.patch (+0/-18)
debian/patches/keystone-CVE-2012-4413.patch (+0/-147)
debian/patches/keystone-CVE-2012-5571.patch (+0/-62)
debian/patches/series (+0/-3)
doc/keystone_compat_flows.sdx (+0/-99)
keystone.egg-info/PKG-INFO (+10/-0)
keystone.egg-info/SOURCES.txt (+176/-0)
keystone.egg-info/dependency_links.txt (+1/-0)
keystone.egg-info/not-zip-safe (+1/-0)
keystone.egg-info/requires.txt (+11/-0)
keystone.egg-info/top_level.txt (+1/-0)
keystone/identity/core.py (+4/-4)
keystone/token/backends/kvs.py (+13/-8)
keystone/token/backends/memcache.py (+31/-1)
keystone/token/backends/sql.py (+6/-1)
keystone/token/core.py (+11/-5)
setup.cfg (+8/-11)
setup.py (+1/-1)
tests/test_backend.py (+56/-5)
tests/test_backend_memcache.py (+29/-6)
tests/test_keystoneclient.py (+1/-1)
tools/pip-requires (+2/-2)
To merge this branch: bzr merge lp:~yolanda.robla/ubuntu/precise/keystone/essex-sru
Reviewer Review Type Date Requested Status
James Page 2012-12-18 Approve on 2012-12-18
Review via email: mp+140450@code.launchpad.net

This proposal supersedes a proposal from 2012-12-18.

To post a comment you must log in.
James Page (james-page) wrote : Posted in a previous version of this proposal

Yolanda

Minor nitpick; this branch drops an empty line from the changelog;

Other than that builds OK.

review: Needs Fixing
James Page (james-page) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
</
=== modified file '.pc/applied-patches'
--- .pc/applied-patches 2012-11-26 14:07:34 +0000
+++ .pc/applied-patches 2012-12-18 14:06:26 +0000
@@ -1,5 +1,2 @@
1fix-ubuntu-tests.patch1fix-ubuntu-tests.patch
2sql_connection.patch2sql_connection.patch
3keystone-CVE-2012-3542.patch
4keystone-CVE-2012-4413.patch
5keystone-CVE-2012-5571.patch
63
=== modified file '.pc/fix-ubuntu-tests.patch/tests/test_keystoneclient.py'
--- .pc/fix-ubuntu-tests.patch/tests/test_keystoneclient.py 2012-08-24 03:34:59 +0000
+++ .pc/fix-ubuntu-tests.patch/tests/test_keystoneclient.py 2012-12-18 14:06:26 +0000
@@ -769,15 +769,15 @@
769 def test_tenant_add_and_remove_user(self):769 def test_tenant_add_and_remove_user(self):
770 client = self.get_client(admin=True)770 client = self.get_client(admin=True)
771 client.roles.add_user_role(tenant=self.tenant_baz['id'],771 client.roles.add_user_role(tenant=self.tenant_baz['id'],
772 user=self.user_foo['id'],772 user=self.user_two['id'],
773 role=self.role_useless['id'])773 role=self.role_useless['id'])
774 user_refs = client.tenants.list_users(tenant=self.tenant_baz['id'])774 user_refs = client.tenants.list_users(tenant=self.tenant_baz['id'])
775 self.assert_(self.user_foo['id'] in [x.id for x in user_refs])775 self.assert_(self.user_two['id'] in [x.id for x in user_refs])
776 client.roles.remove_user_role(tenant=self.tenant_baz['id'],776 client.roles.remove_user_role(tenant=self.tenant_baz['id'],
777 user=self.user_foo['id'],777 user=self.user_two['id'],
778 role=self.role_useless['id'])778 role=self.role_useless['id'])
779 user_refs = client.tenants.list_users(tenant=self.tenant_baz['id'])779 user_refs = client.tenants.list_users(tenant=self.tenant_baz['id'])
780 self.assert_(self.user_foo['id'] not in [x.id for x in user_refs])780 self.assert_(self.user_two['id'] not in [x.id for x in user_refs])
781781
782 def test_user_role_add_404(self):782 def test_user_role_add_404(self):
783 from keystoneclient import exceptions as client_exceptions783 from keystoneclient import exceptions as client_exceptions
@@ -890,16 +890,16 @@
890 def test_tenant_add_and_remove_user(self):890 def test_tenant_add_and_remove_user(self):
891 client = self.get_client(admin=True)891 client = self.get_client(admin=True)
892 client.roles.add_user_to_tenant(tenant_id=self.tenant_baz['id'],892 client.roles.add_user_to_tenant(tenant_id=self.tenant_baz['id'],
893 user_id=self.user_foo['id'],893 user_id=self.user_two['id'],
894 role_id=self.role_useless['id'])894 role_id=self.role_useless['id'])
895 role_refs = client.roles.get_user_role_refs(895 role_refs = client.roles.get_user_role_refs(
896 user_id=self.user_foo['id'])896 user_id=self.user_two['id'])
897 self.assert_(self.tenant_baz['id'] in [x.tenantId for x in role_refs])897 self.assert_(self.tenant_baz['id'] in [x.tenantId for x in role_refs])
898898
899 # get the "role_refs" so we get the proper id, this is how the clients899 # get the "role_refs" so we get the proper id, this is how the clients
900 # do it900 # do it
901 roleref_refs = client.roles.get_user_role_refs(901 roleref_refs = client.roles.get_user_role_refs(
902 user_id=self.user_foo['id'])902 user_id=self.user_two['id'])
903 for roleref_ref in roleref_refs:903 for roleref_ref in roleref_refs:
904 if (roleref_ref.roleId == self.role_useless['id']904 if (roleref_ref.roleId == self.role_useless['id']
905 and roleref_ref.tenantId == self.tenant_baz['id']):905 and roleref_ref.tenantId == self.tenant_baz['id']):
@@ -907,11 +907,11 @@
907 break907 break
908908
909 client.roles.remove_user_from_tenant(tenant_id=self.tenant_baz['id'],909 client.roles.remove_user_from_tenant(tenant_id=self.tenant_baz['id'],
910 user_id=self.user_foo['id'],910 user_id=self.user_two['id'],
911 role_id=roleref_ref.id)911 role_id=roleref_ref.id)
912912
913 role_refs = client.roles.get_user_role_refs(913 role_refs = client.roles.get_user_role_refs(
914 user_id=self.user_foo['id'])914 user_id=self.user_two['id'])
915 self.assert_(self.tenant_baz['id'] not in915 self.assert_(self.tenant_baz['id'] not in
916 [x.tenantId for x in role_refs])916 [x.tenantId for x in role_refs])
917917
918918
=== removed directory '.pc/keystone-CVE-2012-3542.patch'
=== removed directory '.pc/keystone-CVE-2012-3542.patch/keystone'
=== removed directory '.pc/keystone-CVE-2012-3542.patch/keystone/identity'
=== removed file '.pc/keystone-CVE-2012-3542.patch/keystone/identity/core.py'
--- .pc/keystone-CVE-2012-3542.patch/keystone/identity/core.py 2012-08-30 15:10:26 +0000
+++ .pc/keystone-CVE-2012-3542.patch/keystone/identity/core.py 1970-01-01 00:00:00 +0000
@@ -1,625 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2012 OpenStack LLC
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
17"""Main entry point into the Identity service."""
18
19import uuid
20import urllib
21import urlparse
22
23from keystone import config
24from keystone import exception
25from keystone import policy
26from keystone import token
27from keystone.common import logging
28from keystone.common import manager
29from keystone.common import wsgi
30
31
32CONF = config.CONF
33
34LOG = logging.getLogger(__name__)
35
36
37class Manager(manager.Manager):
38 """Default pivot point for the Identity backend.
39
40 See :mod:`keystone.common.manager.Manager` for more details on how this
41 dynamically calls the backend.
42
43 """
44
45 def __init__(self):
46 super(Manager, self).__init__(CONF.identity.driver)
47
48
49class Driver(object):
50 """Interface description for an Identity driver."""
51
52 def authenticate(self, user_id=None, tenant_id=None, password=None):
53 """Authenticate a given user, tenant and password.
54
55 Returns: (user, tenant, metadata).
56
57 """
58 raise exception.NotImplemented()
59
60 def get_tenant(self, tenant_id):
61 """Get a tenant by id.
62
63 Returns: tenant_ref or None.
64
65 """
66 raise exception.NotImplemented()
67
68 def get_tenant_by_name(self, tenant_name):
69 """Get a tenant by name.
70
71 Returns: tenant_ref or None.
72
73 """
74 raise exception.NotImplemented()
75
76 def get_user(self, user_id):
77 """Get a user by id.
78
79 Returns: user_ref or None.
80
81 """
82 raise exception.NotImplemented()
83
84 def get_user_by_name(self, user_name):
85 """Get a user by name.
86
87 Returns: user_ref or None.
88
89 """
90 raise exception.NotImplemented()
91
92 def get_role(self, role_id):
93 """Get a role by id.
94
95 Returns: role_ref or None.
96
97 """
98 raise exception.NotImplemented()
99
100 def list_users(self):
101 """List all users in the system.
102
103 NOTE(termie): I'd prefer if this listed only the users for a given
104 tenant.
105
106 Returns: a list of user_refs or an empty list.
107
108 """
109 raise exception.NotImplemented()
110
111 def list_roles(self):
112 """List all roles in the system.
113
114 Returns: a list of role_refs or an empty list.
115
116 """
117 raise exception.NotImplemented()
118
119 # NOTE(termie): seven calls below should probably be exposed by the api
120 # more clearly when the api redesign happens
121 def add_user_to_tenant(self, tenant_id, user_id):
122 raise exception.NotImplemented()
123
124 def remove_user_from_tenant(self, tenant_id, user_id):
125 raise exception.NotImplemented()
126
127 def get_all_tenants(self):
128 raise exception.NotImplemented()
129
130 def get_tenants_for_user(self, user_id):
131 """Get the tenants associated with a given user.
132
133 Returns: a list of tenant ids.
134
135 """
136 raise exception.NotImplemented()
137
138 def get_roles_for_user_and_tenant(self, user_id, tenant_id):
139 """Get the roles associated with a user within given tenant.
140
141 Returns: a list of role ids.
142
143 """
144 raise exception.NotImplemented()
145
146 def add_role_to_user_and_tenant(self, user_id, tenant_id, role_id):
147 """Add a role to a user within given tenant."""
148 raise exception.NotImplemented()
149
150 def remove_role_from_user_and_tenant(self, user_id, tenant_id, role_id):
151 """Remove a role from a user within given tenant."""
152 raise exception.NotImplemented()
153
154 # user crud
155 def create_user(self, user_id, user):
156 raise exception.NotImplemented()
157
158 def update_user(self, user_id, user):
159 raise exception.NotImplemented()
160
161 def delete_user(self, user_id):
162 raise exception.NotImplemented()
163
164 # tenant crud
165 def create_tenant(self, tenant_id, tenant):
166 raise exception.NotImplemented()
167
168 def update_tenant(self, tenant_id, tenant):
169 raise exception.NotImplemented()
170
171 def delete_tenant(self, tenant_id, tenant):
172 raise exception.NotImplemented()
173
174 # metadata crud
175
176 def get_metadata(self, user_id, tenant_id):
177 raise exception.NotImplemented()
178
179 def create_metadata(self, user_id, tenant_id, metadata):
180 raise exception.NotImplemented()
181
182 def update_metadata(self, user_id, tenant_id, metadata):
183 raise exception.NotImplemented()
184
185 def delete_metadata(self, user_id, tenant_id, metadata):
186 raise exception.NotImplemented()
187
188 # role crud
189 def create_role(self, role_id, role):
190 raise exception.NotImplemented()
191
192 def update_role(self, role_id, role):
193 raise exception.NotImplemented()
194
195 def delete_role(self, role_id):
196 raise exception.NotImplemented()
197
198
199class PublicRouter(wsgi.ComposableRouter):
200 def add_routes(self, mapper):
201 tenant_controller = TenantController()
202 mapper.connect('/tenants',
203 controller=tenant_controller,
204 action='get_tenants_for_token',
205 conditions=dict(methods=['GET']))
206
207
208class AdminRouter(wsgi.ComposableRouter):
209 def add_routes(self, mapper):
210 # Tenant Operations
211 tenant_controller = TenantController()
212 mapper.connect('/tenants',
213 controller=tenant_controller,
214 action='get_all_tenants',
215 conditions=dict(method=['GET']))
216 mapper.connect('/tenants/{tenant_id}',
217 controller=tenant_controller,
218 action='get_tenant',
219 conditions=dict(method=['GET']))
220
221 # User Operations
222 user_controller = UserController()
223 mapper.connect('/users/{user_id}',
224 controller=user_controller,
225 action='get_user',
226 conditions=dict(method=['GET']))
227
228 # Role Operations
229 roles_controller = RoleController()
230 mapper.connect('/tenants/{tenant_id}/users/{user_id}/roles',
231 controller=roles_controller,
232 action='get_user_roles',
233 conditions=dict(method=['GET']))
234 mapper.connect('/users/{user_id}/roles',
235 controller=user_controller,
236 action='get_user_roles',
237 conditions=dict(method=['GET']))
238
239
240class TenantController(wsgi.Application):
241 def __init__(self):
242 self.identity_api = Manager()
243 self.policy_api = policy.Manager()
244 self.token_api = token.Manager()
245 super(TenantController, self).__init__()
246
247 def get_all_tenants(self, context, **kw):
248 """Gets a list of all tenants for an admin user."""
249 self.assert_admin(context)
250 tenant_refs = self.identity_api.get_tenants(context)
251 params = {
252 'limit': context['query_string'].get('limit'),
253 'marker': context['query_string'].get('marker'),
254 }
255 return self._format_tenant_list(tenant_refs, **params)
256
257 def get_tenants_for_token(self, context, **kw):
258 """Get valid tenants for token based on token used to authenticate.
259
260 Pulls the token from the context, validates it and gets the valid
261 tenants for the user in the token.
262
263 Doesn't care about token scopedness.
264
265 """
266 try:
267 token_ref = self.token_api.get_token(context=context,
268 token_id=context['token_id'])
269 except exception.NotFound:
270 raise exception.Unauthorized()
271
272 user_ref = token_ref['user']
273 tenant_ids = self.identity_api.get_tenants_for_user(
274 context, user_ref['id'])
275 tenant_refs = []
276 for tenant_id in tenant_ids:
277 tenant_refs.append(self.identity_api.get_tenant(
278 context=context,
279 tenant_id=tenant_id))
280 params = {
281 'limit': context['query_string'].get('limit'),
282 'marker': context['query_string'].get('marker'),
283 }
284 return self._format_tenant_list(tenant_refs, **params)
285
286 def get_tenant(self, context, tenant_id):
287 # TODO(termie): this stuff should probably be moved to middleware
288 self.assert_admin(context)
289 tenant = self.identity_api.get_tenant(context, tenant_id)
290 if tenant is None:
291 raise exception.TenantNotFound(tenant_id=tenant_id)
292
293 return {'tenant': tenant}
294
295 # CRUD Extension
296 def create_tenant(self, context, tenant):
297 tenant_ref = self._normalize_dict(tenant)
298 self.assert_admin(context)
299 tenant_id = (tenant_ref.get('id')
300 and tenant_ref.get('id')
301 or uuid.uuid4().hex)
302 tenant_ref['id'] = tenant_id
303
304 tenant = self.identity_api.create_tenant(
305 context, tenant_id, tenant_ref)
306 return {'tenant': tenant}
307
308 def update_tenant(self, context, tenant_id, tenant):
309 self.assert_admin(context)
310 if self.identity_api.get_tenant(context, tenant_id) is None:
311 raise exception.TenantNotFound(tenant_id=tenant_id)
312
313 tenant_ref = self.identity_api.update_tenant(
314 context, tenant_id, tenant)
315 return {'tenant': tenant_ref}
316
317 def delete_tenant(self, context, tenant_id, **kw):
318 self.assert_admin(context)
319 if self.identity_api.get_tenant(context, tenant_id) is None:
320 raise exception.TenantNotFound(tenant_id=tenant_id)
321
322 self.identity_api.delete_tenant(context, tenant_id)
323
324 def get_tenant_users(self, context, tenant_id, **kw):
325 self.assert_admin(context)
326 if self.identity_api.get_tenant(context, tenant_id) is None:
327 raise exception.TenantNotFound(tenant_id=tenant_id)
328
329 user_refs = self.identity_api.get_tenant_users(context, tenant_id)
330 return {'users': user_refs}
331
332 def _format_tenant_list(self, tenant_refs, **kwargs):
333 marker = kwargs.get('marker')
334 page_idx = 0
335 if marker is not None:
336 for (marker_idx, tenant) in enumerate(tenant_refs):
337 if tenant['id'] == marker:
338 # we start pagination after the marker
339 page_idx = marker_idx + 1
340 break
341 else:
342 msg = 'Marker could not be found'
343 raise exception.ValidationError(message=msg)
344
345 limit = kwargs.get('limit')
346 if limit is not None:
347 try:
348 limit = int(limit)
349 if limit < 0:
350 raise AssertionError()
351 except (ValueError, AssertionError):
352 msg = 'Invalid limit value'
353 raise exception.ValidationError(message=msg)
354
355 tenant_refs = tenant_refs[page_idx:limit]
356
357 for x in tenant_refs:
358 if 'enabled' not in x:
359 x['enabled'] = True
360 o = {'tenants': tenant_refs,
361 'tenants_links': []}
362 return o
363
364
365class UserController(wsgi.Application):
366 def __init__(self):
367 self.identity_api = Manager()
368 self.policy_api = policy.Manager()
369 self.token_api = token.Manager()
370 super(UserController, self).__init__()
371
372 def get_user(self, context, user_id):
373 self.assert_admin(context)
374 user_ref = self.identity_api.get_user(context, user_id)
375 if not user_ref:
376 raise exception.UserNotFound(user_id=user_id)
377
378 return {'user': user_ref}
379
380 def get_users(self, context):
381 # NOTE(termie): i can't imagine that this really wants all the data
382 # about every single user in the system...
383 self.assert_admin(context)
384 user_refs = self.identity_api.list_users(context)
385 return {'users': user_refs}
386
387 # CRUD extension
388 def create_user(self, context, user):
389 user = self._normalize_dict(user)
390 self.assert_admin(context)
391 tenant_id = user.get('tenantId', None)
392 if (tenant_id is not None
393 and self.identity_api.get_tenant(context, tenant_id) is None):
394 raise exception.TenantNotFound(tenant_id=tenant_id)
395 user_id = uuid.uuid4().hex
396 user_ref = user.copy()
397 user_ref['id'] = user_id
398 new_user_ref = self.identity_api.create_user(
399 context, user_id, user_ref)
400 if tenant_id:
401 self.identity_api.add_user_to_tenant(context, tenant_id, user_id)
402 return {'user': new_user_ref}
403
404 def update_user(self, context, user_id, user):
405 # NOTE(termie): this is really more of a patch than a put
406 self.assert_admin(context)
407 if self.identity_api.get_user(context, user_id) is None:
408 raise exception.UserNotFound(user_id=user_id)
409
410 user_ref = self.identity_api.update_user(context, user_id, user)
411
412 # If the password was changed or the user was disabled we clear tokens
413 if user.get('password') or user.get('enabled', True) == False:
414 try:
415 for token_id in self.token_api.list_tokens(context, user_id):
416 self.token_api.delete_token(context, token_id)
417 except exception.NotImplemented:
418 # The users status has been changed but tokens remain valid for
419 # backends that can't list tokens for users
420 LOG.warning('User %s status has changed, but existing tokens '
421 'remain valid' % user_id)
422 return {'user': user_ref}
423
424 def delete_user(self, context, user_id):
425 self.assert_admin(context)
426 if self.identity_api.get_user(context, user_id) is None:
427 raise exception.UserNotFound(user_id=user_id)
428
429 self.identity_api.delete_user(context, user_id)
430
431 def set_user_enabled(self, context, user_id, user):
432 return self.update_user(context, user_id, user)
433
434 def set_user_password(self, context, user_id, user):
435 return self.update_user(context, user_id, user)
436
437 def update_user_tenant(self, context, user_id, user):
438 """Update the default tenant."""
439 # ensure that we're a member of that tenant
440 tenant_id = user.get('tenantId')
441 self.identity_api.add_user_to_tenant(context, tenant_id, user_id)
442 return self.update_user(context, user_id, user)
443
444
445class RoleController(wsgi.Application):
446 def __init__(self):
447 self.identity_api = Manager()
448 self.token_api = token.Manager()
449 self.policy_api = policy.Manager()
450 super(RoleController, self).__init__()
451
452 # COMPAT(essex-3)
453 def get_user_roles(self, context, user_id, tenant_id=None):
454 """Get the roles for a user and tenant pair.
455
456 Since we're trying to ignore the idea of user-only roles we're
457 not implementing them in hopes that the idea will die off.
458
459 """
460 self.assert_admin(context)
461 if tenant_id is None:
462 raise exception.NotImplemented(message='User roles not supported: '
463 'tenant ID required')
464
465 user = self.identity_api.get_user(context, user_id)
466 if user is None:
467 raise exception.UserNotFound(user_id=user_id)
468 tenant = self.identity_api.get_tenant(context, tenant_id)
469 if tenant is None:
470 raise exception.TenantNotFound(tenant_id=tenant_id)
471
472 roles = self.identity_api.get_roles_for_user_and_tenant(
473 context, user_id, tenant_id)
474 return {'roles': [self.identity_api.get_role(context, x)
475 for x in roles]}
476
477 # CRUD extension
478 def get_role(self, context, role_id):
479 self.assert_admin(context)
480 role_ref = self.identity_api.get_role(context, role_id)
481 if not role_ref:
482 raise exception.RoleNotFound(role_id=role_id)
483 return {'role': role_ref}
484
485 def create_role(self, context, role):
486 role = self._normalize_dict(role)
487 self.assert_admin(context)
488 role_id = uuid.uuid4().hex
489 role['id'] = role_id
490 role_ref = self.identity_api.create_role(context, role_id, role)
491 return {'role': role_ref}
492
493 def delete_role(self, context, role_id):
494 self.assert_admin(context)
495 self.get_role(context, role_id)
496 self.identity_api.delete_role(context, role_id)
497
498 def get_roles(self, context):
499 self.assert_admin(context)
500 roles = self.identity_api.list_roles(context)
501 # TODO(termie): probably inefficient at some point
502 return {'roles': roles}
503
504 def add_role_to_user(self, context, user_id, role_id, tenant_id=None):
505 """Add a role to a user and tenant pair.
506
507 Since we're trying to ignore the idea of user-only roles we're
508 not implementing them in hopes that the idea will die off.
509
510 """
511 self.assert_admin(context)
512 if tenant_id is None:
513 raise exception.NotImplemented(message='User roles not supported: '
514 'tenant_id required')
515 if self.identity_api.get_user(context, user_id) is None:
516 raise exception.UserNotFound(user_id=user_id)
517 if self.identity_api.get_tenant(context, tenant_id) is None:
518 raise exception.TenantNotFound(tenant_id=tenant_id)
519 if self.identity_api.get_role(context, role_id) is None:
520 raise exception.RoleNotFound(role_id=role_id)
521
522 # This still has the weird legacy semantics that adding a role to
523 # a user also adds them to a tenant
524 self.identity_api.add_user_to_tenant(context, tenant_id, user_id)
525 self.identity_api.add_role_to_user_and_tenant(
526 context, user_id, tenant_id, role_id)
527 role_ref = self.identity_api.get_role(context, role_id)
528 return {'role': role_ref}
529
530 def remove_role_from_user(self, context, user_id, role_id, tenant_id=None):
531 """Remove a role from a user and tenant pair.
532
533 Since we're trying to ignore the idea of user-only roles we're
534 not implementing them in hopes that the idea will die off.
535
536 """
537 self.assert_admin(context)
538 if tenant_id is None:
539 raise exception.NotImplemented(message='User roles not supported: '
540 'tenant_id required')
541 if self.identity_api.get_user(context, user_id) is None:
542 raise exception.UserNotFound(user_id=user_id)
543 if self.identity_api.get_tenant(context, tenant_id) is None:
544 raise exception.TenantNotFound(tenant_id=tenant_id)
545 if self.identity_api.get_role(context, role_id) is None:
546 raise exception.RoleNotFound(role_id=role_id)
547
548 # This still has the weird legacy semantics that adding a role to
549 # a user also adds them to a tenant, so we must follow up on that
550 self.identity_api.remove_role_from_user_and_tenant(
551 context, user_id, tenant_id, role_id)
552 roles = self.identity_api.get_roles_for_user_and_tenant(
553 context, user_id, tenant_id)
554 if not roles:
555 self.identity_api.remove_user_from_tenant(
556 context, tenant_id, user_id)
557 return
558
559 # COMPAT(diablo): CRUD extension
560 def get_role_refs(self, context, user_id):
561 """Ultimate hack to get around having to make role_refs first-class.
562
563 This will basically iterate over the various roles the user has in
564 all tenants the user is a member of and create fake role_refs where
565 the id encodes the user-tenant-role information so we can look
566 up the appropriate data when we need to delete them.
567
568 """
569 self.assert_admin(context)
570 user_ref = self.identity_api.get_user(context, user_id)
571 tenant_ids = self.identity_api.get_tenants_for_user(context, user_id)
572 o = []
573 for tenant_id in tenant_ids:
574 role_ids = self.identity_api.get_roles_for_user_and_tenant(
575 context, user_id, tenant_id)
576 for role_id in role_ids:
577 ref = {'roleId': role_id,
578 'tenantId': tenant_id,
579 'userId': user_id}
580 ref['id'] = urllib.urlencode(ref)
581 o.append(ref)
582 return {'roles': o}
583
584 # COMPAT(diablo): CRUD extension
585 def create_role_ref(self, context, user_id, role):
586 """This is actually used for adding a user to a tenant.
587
588 In the legacy data model adding a user to a tenant required setting
589 a role.
590
591 """
592 self.assert_admin(context)
593 # TODO(termie): for now we're ignoring the actual role
594 tenant_id = role.get('tenantId')
595 role_id = role.get('roleId')
596 self.identity_api.add_user_to_tenant(context, tenant_id, user_id)
597 self.identity_api.add_role_to_user_and_tenant(
598 context, user_id, tenant_id, role_id)
599 role_ref = self.identity_api.get_role(context, role_id)
600 return {'role': role_ref}
601
602 # COMPAT(diablo): CRUD extension
603 def delete_role_ref(self, context, user_id, role_ref_id):
604 """This is actually used for deleting a user from a tenant.
605
606 In the legacy data model removing a user from a tenant required
607 deleting a role.
608
609 To emulate this, we encode the tenant and role in the role_ref_id,
610 and if this happens to be the last role for the user-tenant pair,
611 we remove the user from the tenant.
612
613 """
614 self.assert_admin(context)
615 # TODO(termie): for now we're ignoring the actual role
616 role_ref_ref = urlparse.parse_qs(role_ref_id)
617 tenant_id = role_ref_ref.get('tenantId')[0]
618 role_id = role_ref_ref.get('roleId')[0]
619 self.identity_api.remove_role_from_user_and_tenant(
620 context, user_id, tenant_id, role_id)
621 roles = self.identity_api.get_roles_for_user_and_tenant(
622 context, user_id, tenant_id)
623 if not roles:
624 self.identity_api.remove_user_from_tenant(
625 context, tenant_id, user_id)
6260
=== removed directory '.pc/keystone-CVE-2012-4413.patch'
=== removed directory '.pc/keystone-CVE-2012-4413.patch/keystone'
=== removed directory '.pc/keystone-CVE-2012-4413.patch/keystone/identity'
=== removed file '.pc/keystone-CVE-2012-4413.patch/keystone/identity/core.py'
--- .pc/keystone-CVE-2012-4413.patch/keystone/identity/core.py 2012-09-12 09:47:55 +0000
+++ .pc/keystone-CVE-2012-4413.patch/keystone/identity/core.py 1970-01-01 00:00:00 +0000
@@ -1,626 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2012 OpenStack LLC
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
17"""Main entry point into the Identity service."""
18
19import uuid
20import urllib
21import urlparse
22
23from keystone import config
24from keystone import exception
25from keystone import policy
26from keystone import token
27from keystone.common import logging
28from keystone.common import manager
29from keystone.common import wsgi
30
31
32CONF = config.CONF
33
34LOG = logging.getLogger(__name__)
35
36
37class Manager(manager.Manager):
38 """Default pivot point for the Identity backend.
39
40 See :mod:`keystone.common.manager.Manager` for more details on how this
41 dynamically calls the backend.
42
43 """
44
45 def __init__(self):
46 super(Manager, self).__init__(CONF.identity.driver)
47
48
49class Driver(object):
50 """Interface description for an Identity driver."""
51
52 def authenticate(self, user_id=None, tenant_id=None, password=None):
53 """Authenticate a given user, tenant and password.
54
55 Returns: (user, tenant, metadata).
56
57 """
58 raise exception.NotImplemented()
59
60 def get_tenant(self, tenant_id):
61 """Get a tenant by id.
62
63 Returns: tenant_ref or None.
64
65 """
66 raise exception.NotImplemented()
67
68 def get_tenant_by_name(self, tenant_name):
69 """Get a tenant by name.
70
71 Returns: tenant_ref or None.
72
73 """
74 raise exception.NotImplemented()
75
76 def get_user(self, user_id):
77 """Get a user by id.
78
79 Returns: user_ref or None.
80
81 """
82 raise exception.NotImplemented()
83
84 def get_user_by_name(self, user_name):
85 """Get a user by name.
86
87 Returns: user_ref or None.
88
89 """
90 raise exception.NotImplemented()
91
92 def get_role(self, role_id):
93 """Get a role by id.
94
95 Returns: role_ref or None.
96
97 """
98 raise exception.NotImplemented()
99
100 def list_users(self):
101 """List all users in the system.
102
103 NOTE(termie): I'd prefer if this listed only the users for a given
104 tenant.
105
106 Returns: a list of user_refs or an empty list.
107
108 """
109 raise exception.NotImplemented()
110
111 def list_roles(self):
112 """List all roles in the system.
113
114 Returns: a list of role_refs or an empty list.
115
116 """
117 raise exception.NotImplemented()
118
119 # NOTE(termie): seven calls below should probably be exposed by the api
120 # more clearly when the api redesign happens
121 def add_user_to_tenant(self, tenant_id, user_id):
122 raise exception.NotImplemented()
123
124 def remove_user_from_tenant(self, tenant_id, user_id):
125 raise exception.NotImplemented()
126
127 def get_all_tenants(self):
128 raise exception.NotImplemented()
129
130 def get_tenants_for_user(self, user_id):
131 """Get the tenants associated with a given user.
132
133 Returns: a list of tenant ids.
134
135 """
136 raise exception.NotImplemented()
137
138 def get_roles_for_user_and_tenant(self, user_id, tenant_id):
139 """Get the roles associated with a user within given tenant.
140
141 Returns: a list of role ids.
142
143 """
144 raise exception.NotImplemented()
145
146 def add_role_to_user_and_tenant(self, user_id, tenant_id, role_id):
147 """Add a role to a user within given tenant."""
148 raise exception.NotImplemented()
149
150 def remove_role_from_user_and_tenant(self, user_id, tenant_id, role_id):
151 """Remove a role from a user within given tenant."""
152 raise exception.NotImplemented()
153
154 # user crud
155 def create_user(self, user_id, user):
156 raise exception.NotImplemented()
157
158 def update_user(self, user_id, user):
159 raise exception.NotImplemented()
160
161 def delete_user(self, user_id):
162 raise exception.NotImplemented()
163
164 # tenant crud
165 def create_tenant(self, tenant_id, tenant):
166 raise exception.NotImplemented()
167
168 def update_tenant(self, tenant_id, tenant):
169 raise exception.NotImplemented()
170
171 def delete_tenant(self, tenant_id, tenant):
172 raise exception.NotImplemented()
173
174 # metadata crud
175
176 def get_metadata(self, user_id, tenant_id):
177 raise exception.NotImplemented()
178
179 def create_metadata(self, user_id, tenant_id, metadata):
180 raise exception.NotImplemented()
181
182 def update_metadata(self, user_id, tenant_id, metadata):
183 raise exception.NotImplemented()
184
185 def delete_metadata(self, user_id, tenant_id, metadata):
186 raise exception.NotImplemented()
187
188 # role crud
189 def create_role(self, role_id, role):
190 raise exception.NotImplemented()
191
192 def update_role(self, role_id, role):
193 raise exception.NotImplemented()
194
195 def delete_role(self, role_id):
196 raise exception.NotImplemented()
197
198
199class PublicRouter(wsgi.ComposableRouter):
200 def add_routes(self, mapper):
201 tenant_controller = TenantController()
202 mapper.connect('/tenants',
203 controller=tenant_controller,
204 action='get_tenants_for_token',
205 conditions=dict(methods=['GET']))
206
207
208class AdminRouter(wsgi.ComposableRouter):
209 def add_routes(self, mapper):
210 # Tenant Operations
211 tenant_controller = TenantController()
212 mapper.connect('/tenants',
213 controller=tenant_controller,
214 action='get_all_tenants',
215 conditions=dict(method=['GET']))
216 mapper.connect('/tenants/{tenant_id}',
217 controller=tenant_controller,
218 action='get_tenant',
219 conditions=dict(method=['GET']))
220
221 # User Operations
222 user_controller = UserController()
223 mapper.connect('/users/{user_id}',
224 controller=user_controller,
225 action='get_user',
226 conditions=dict(method=['GET']))
227
228 # Role Operations
229 roles_controller = RoleController()
230 mapper.connect('/tenants/{tenant_id}/users/{user_id}/roles',
231 controller=roles_controller,
232 action='get_user_roles',
233 conditions=dict(method=['GET']))
234 mapper.connect('/users/{user_id}/roles',
235 controller=user_controller,
236 action='get_user_roles',
237 conditions=dict(method=['GET']))
238
239
240class TenantController(wsgi.Application):
241 def __init__(self):
242 self.identity_api = Manager()
243 self.policy_api = policy.Manager()
244 self.token_api = token.Manager()
245 super(TenantController, self).__init__()
246
247 def get_all_tenants(self, context, **kw):
248 """Gets a list of all tenants for an admin user."""
249 self.assert_admin(context)
250 tenant_refs = self.identity_api.get_tenants(context)
251 params = {
252 'limit': context['query_string'].get('limit'),
253 'marker': context['query_string'].get('marker'),
254 }
255 return self._format_tenant_list(tenant_refs, **params)
256
257 def get_tenants_for_token(self, context, **kw):
258 """Get valid tenants for token based on token used to authenticate.
259
260 Pulls the token from the context, validates it and gets the valid
261 tenants for the user in the token.
262
263 Doesn't care about token scopedness.
264
265 """
266 try:
267 token_ref = self.token_api.get_token(context=context,
268 token_id=context['token_id'])
269 except exception.NotFound:
270 raise exception.Unauthorized()
271
272 user_ref = token_ref['user']
273 tenant_ids = self.identity_api.get_tenants_for_user(
274 context, user_ref['id'])
275 tenant_refs = []
276 for tenant_id in tenant_ids:
277 tenant_refs.append(self.identity_api.get_tenant(
278 context=context,
279 tenant_id=tenant_id))
280 params = {
281 'limit': context['query_string'].get('limit'),
282 'marker': context['query_string'].get('marker'),
283 }
284 return self._format_tenant_list(tenant_refs, **params)
285
286 def get_tenant(self, context, tenant_id):
287 # TODO(termie): this stuff should probably be moved to middleware
288 self.assert_admin(context)
289 tenant = self.identity_api.get_tenant(context, tenant_id)
290 if tenant is None:
291 raise exception.TenantNotFound(tenant_id=tenant_id)
292
293 return {'tenant': tenant}
294
295 # CRUD Extension
296 def create_tenant(self, context, tenant):
297 tenant_ref = self._normalize_dict(tenant)
298 self.assert_admin(context)
299 tenant_id = (tenant_ref.get('id')
300 and tenant_ref.get('id')
301 or uuid.uuid4().hex)
302 tenant_ref['id'] = tenant_id
303
304 tenant = self.identity_api.create_tenant(
305 context, tenant_id, tenant_ref)
306 return {'tenant': tenant}
307
308 def update_tenant(self, context, tenant_id, tenant):
309 self.assert_admin(context)
310 if self.identity_api.get_tenant(context, tenant_id) is None:
311 raise exception.TenantNotFound(tenant_id=tenant_id)
312
313 tenant_ref = self.identity_api.update_tenant(
314 context, tenant_id, tenant)
315 return {'tenant': tenant_ref}
316
317 def delete_tenant(self, context, tenant_id, **kw):
318 self.assert_admin(context)
319 if self.identity_api.get_tenant(context, tenant_id) is None:
320 raise exception.TenantNotFound(tenant_id=tenant_id)
321
322 self.identity_api.delete_tenant(context, tenant_id)
323
324 def get_tenant_users(self, context, tenant_id, **kw):
325 self.assert_admin(context)
326 if self.identity_api.get_tenant(context, tenant_id) is None:
327 raise exception.TenantNotFound(tenant_id=tenant_id)
328
329 user_refs = self.identity_api.get_tenant_users(context, tenant_id)
330 return {'users': user_refs}
331
332 def _format_tenant_list(self, tenant_refs, **kwargs):
333 marker = kwargs.get('marker')
334 page_idx = 0
335 if marker is not None:
336 for (marker_idx, tenant) in enumerate(tenant_refs):
337 if tenant['id'] == marker:
338 # we start pagination after the marker
339 page_idx = marker_idx + 1
340 break
341 else:
342 msg = 'Marker could not be found'
343 raise exception.ValidationError(message=msg)
344
345 limit = kwargs.get('limit')
346 if limit is not None:
347 try:
348 limit = int(limit)
349 if limit < 0:
350 raise AssertionError()
351 except (ValueError, AssertionError):
352 msg = 'Invalid limit value'
353 raise exception.ValidationError(message=msg)
354
355 tenant_refs = tenant_refs[page_idx:limit]
356
357 for x in tenant_refs:
358 if 'enabled' not in x:
359 x['enabled'] = True
360 o = {'tenants': tenant_refs,
361 'tenants_links': []}
362 return o
363
364
365class UserController(wsgi.Application):
366 def __init__(self):
367 self.identity_api = Manager()
368 self.policy_api = policy.Manager()
369 self.token_api = token.Manager()
370 super(UserController, self).__init__()
371
372 def get_user(self, context, user_id):
373 self.assert_admin(context)
374 user_ref = self.identity_api.get_user(context, user_id)
375 if not user_ref:
376 raise exception.UserNotFound(user_id=user_id)
377
378 return {'user': user_ref}
379
380 def get_users(self, context):
381 # NOTE(termie): i can't imagine that this really wants all the data
382 # about every single user in the system...
383 self.assert_admin(context)
384 user_refs = self.identity_api.list_users(context)
385 return {'users': user_refs}
386
387 # CRUD extension
388 def create_user(self, context, user):
389 user = self._normalize_dict(user)
390 self.assert_admin(context)
391 tenant_id = user.get('tenantId', None)
392 if (tenant_id is not None
393 and self.identity_api.get_tenant(context, tenant_id) is None):
394 raise exception.TenantNotFound(tenant_id=tenant_id)
395 user_id = uuid.uuid4().hex
396 user_ref = user.copy()
397 user_ref['id'] = user_id
398 new_user_ref = self.identity_api.create_user(
399 context, user_id, user_ref)
400 if tenant_id:
401 self.identity_api.add_user_to_tenant(context, tenant_id, user_id)
402 return {'user': new_user_ref}
403
404 def update_user(self, context, user_id, user):
405 # NOTE(termie): this is really more of a patch than a put
406 self.assert_admin(context)
407 if self.identity_api.get_user(context, user_id) is None:
408 raise exception.UserNotFound(user_id=user_id)
409
410 user_ref = self.identity_api.update_user(context, user_id, user)
411
412 # If the password was changed or the user was disabled we clear tokens
413 if user.get('password') or user.get('enabled', True) == False:
414 try:
415 for token_id in self.token_api.list_tokens(context, user_id):
416 self.token_api.delete_token(context, token_id)
417 except exception.NotImplemented:
418 # The users status has been changed but tokens remain valid for
419 # backends that can't list tokens for users
420 LOG.warning('User %s status has changed, but existing tokens '
421 'remain valid' % user_id)
422 return {'user': user_ref}
423
424 def delete_user(self, context, user_id):
425 self.assert_admin(context)
426 if self.identity_api.get_user(context, user_id) is None:
427 raise exception.UserNotFound(user_id=user_id)
428
429 self.identity_api.delete_user(context, user_id)
430
431 def set_user_enabled(self, context, user_id, user):
432 return self.update_user(context, user_id, user)
433
434 def set_user_password(self, context, user_id, user):
435 return self.update_user(context, user_id, user)
436
437 def update_user_tenant(self, context, user_id, user):
438 """Update the default tenant."""
439 self.assert_admin(context)
440 # ensure that we're a member of that tenant
441 tenant_id = user.get('tenantId')
442 self.identity_api.add_user_to_tenant(context, tenant_id, user_id)
443 return self.update_user(context, user_id, user)
444
445
446class RoleController(wsgi.Application):
447 def __init__(self):
448 self.identity_api = Manager()
449 self.token_api = token.Manager()
450 self.policy_api = policy.Manager()
451 super(RoleController, self).__init__()
452
453 # COMPAT(essex-3)
454 def get_user_roles(self, context, user_id, tenant_id=None):
455 """Get the roles for a user and tenant pair.
456
457 Since we're trying to ignore the idea of user-only roles we're
458 not implementing them in hopes that the idea will die off.
459
460 """
461 self.assert_admin(context)
462 if tenant_id is None:
463 raise exception.NotImplemented(message='User roles not supported: '
464 'tenant ID required')
465
466 user = self.identity_api.get_user(context, user_id)
467 if user is None:
468 raise exception.UserNotFound(user_id=user_id)
469 tenant = self.identity_api.get_tenant(context, tenant_id)
470 if tenant is None:
471 raise exception.TenantNotFound(tenant_id=tenant_id)
472
473 roles = self.identity_api.get_roles_for_user_and_tenant(
474 context, user_id, tenant_id)
475 return {'roles': [self.identity_api.get_role(context, x)
476 for x in roles]}
477
478 # CRUD extension
479 def get_role(self, context, role_id):
480 self.assert_admin(context)
481 role_ref = self.identity_api.get_role(context, role_id)
482 if not role_ref:
483 raise exception.RoleNotFound(role_id=role_id)
484 return {'role': role_ref}
485
486 def create_role(self, context, role):
487 role = self._normalize_dict(role)
488 self.assert_admin(context)
489 role_id = uuid.uuid4().hex
490 role['id'] = role_id
491 role_ref = self.identity_api.create_role(context, role_id, role)
492 return {'role': role_ref}
493
494 def delete_role(self, context, role_id):
495 self.assert_admin(context)
496 self.get_role(context, role_id)
497 self.identity_api.delete_role(context, role_id)
498
499 def get_roles(self, context):
500 self.assert_admin(context)
501 roles = self.identity_api.list_roles(context)
502 # TODO(termie): probably inefficient at some point
503 return {'roles': roles}
504
505 def add_role_to_user(self, context, user_id, role_id, tenant_id=None):
506 """Add a role to a user and tenant pair.
507
508 Since we're trying to ignore the idea of user-only roles we're
509 not implementing them in hopes that the idea will die off.
510
511 """
512 self.assert_admin(context)
513 if tenant_id is None:
514 raise exception.NotImplemented(message='User roles not supported: '
515 'tenant_id required')
516 if self.identity_api.get_user(context, user_id) is None:
517 raise exception.UserNotFound(user_id=user_id)
518 if self.identity_api.get_tenant(context, tenant_id) is None:
519 raise exception.TenantNotFound(tenant_id=tenant_id)
520 if self.identity_api.get_role(context, role_id) is None:
521 raise exception.RoleNotFound(role_id=role_id)
522
523 # This still has the weird legacy semantics that adding a role to
524 # a user also adds them to a tenant
525 self.identity_api.add_user_to_tenant(context, tenant_id, user_id)
526 self.identity_api.add_role_to_user_and_tenant(
527 context, user_id, tenant_id, role_id)
528 role_ref = self.identity_api.get_role(context, role_id)
529 return {'role': role_ref}
530
531 def remove_role_from_user(self, context, user_id, role_id, tenant_id=None):
532 """Remove a role from a user and tenant pair.
533
534 Since we're trying to ignore the idea of user-only roles we're
535 not implementing them in hopes that the idea will die off.
536
537 """
538 self.assert_admin(context)
539 if tenant_id is None:
540 raise exception.NotImplemented(message='User roles not supported: '
541 'tenant_id required')
542 if self.identity_api.get_user(context, user_id) is None:
543 raise exception.UserNotFound(user_id=user_id)
544 if self.identity_api.get_tenant(context, tenant_id) is None:
545 raise exception.TenantNotFound(tenant_id=tenant_id)
546 if self.identity_api.get_role(context, role_id) is None:
547 raise exception.RoleNotFound(role_id=role_id)
548
549 # This still has the weird legacy semantics that adding a role to
550 # a user also adds them to a tenant, so we must follow up on that
551 self.identity_api.remove_role_from_user_and_tenant(
552 context, user_id, tenant_id, role_id)
553 roles = self.identity_api.get_roles_for_user_and_tenant(
554 context, user_id, tenant_id)
555 if not roles:
556 self.identity_api.remove_user_from_tenant(
557 context, tenant_id, user_id)
558 return
559
560 # COMPAT(diablo): CRUD extension
561 def get_role_refs(self, context, user_id):
562 """Ultimate hack to get around having to make role_refs first-class.
563
564 This will basically iterate over the various roles the user has in
565 all tenants the user is a member of and create fake role_refs where
566 the id encodes the user-tenant-role information so we can look
567 up the appropriate data when we need to delete them.
568
569 """
570 self.assert_admin(context)
571 user_ref = self.identity_api.get_user(context, user_id)
572 tenant_ids = self.identity_api.get_tenants_for_user(context, user_id)
573 o = []
574 for tenant_id in tenant_ids:
575 role_ids = self.identity_api.get_roles_for_user_and_tenant(
576 context, user_id, tenant_id)
577 for role_id in role_ids:
578 ref = {'roleId': role_id,
579 'tenantId': tenant_id,
580 'userId': user_id}
581 ref['id'] = urllib.urlencode(ref)
582 o.append(ref)
583 return {'roles': o}
584
585 # COMPAT(diablo): CRUD extension
586 def create_role_ref(self, context, user_id, role):
587 """This is actually used for adding a user to a tenant.
588
589 In the legacy data model adding a user to a tenant required setting
590 a role.
591
592 """
593 self.assert_admin(context)
594 # TODO(termie): for now we're ignoring the actual role
595 tenant_id = role.get('tenantId')
596 role_id = role.get('roleId')
597 self.identity_api.add_user_to_tenant(context, tenant_id, user_id)
598 self.identity_api.add_role_to_user_and_tenant(
599 context, user_id, tenant_id, role_id)
600 role_ref = self.identity_api.get_role(context, role_id)
601 return {'role': role_ref}
602
603 # COMPAT(diablo): CRUD extension
604 def delete_role_ref(self, context, user_id, role_ref_id):
605 """This is actually used for deleting a user from a tenant.
606
607 In the legacy data model removing a user from a tenant required
608 deleting a role.
609
610 To emulate this, we encode the tenant and role in the role_ref_id,
611 and if this happens to be the last role for the user-tenant pair,
612 we remove the user from the tenant.
613
614 """
615 self.assert_admin(context)
616 # TODO(termie): for now we're ignoring the actual role
617 role_ref_ref = urlparse.parse_qs(role_ref_id)
618 tenant_id = role_ref_ref.get('tenantId')[0]
619 role_id = role_ref_ref.get('roleId')[0]
620 self.identity_api.remove_role_from_user_and_tenant(
621 context, user_id, tenant_id, role_id)
622 roles = self.identity_api.get_roles_for_user_and_tenant(
623 context, user_id, tenant_id)
624 if not roles:
625 self.identity_api.remove_user_from_tenant(
626 context, tenant_id, user_id)
6270
=== removed directory '.pc/keystone-CVE-2012-4413.patch/keystone/token'
=== removed file '.pc/keystone-CVE-2012-4413.patch/keystone/token/core.py'
--- .pc/keystone-CVE-2012-4413.patch/keystone/token/core.py 2012-09-12 09:47:55 +0000
+++ .pc/keystone-CVE-2012-4413.patch/keystone/token/core.py 1970-01-01 00:00:00 +0000
@@ -1,107 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2012 OpenStack LLC
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
17"""Main entry point into the Token service."""
18
19import datetime
20
21from keystone import config
22from keystone import exception
23from keystone.common import manager
24
25
26CONF = config.CONF
27config.register_int('expiration', group='token', default=86400)
28
29
30class Manager(manager.Manager):
31 """Default pivot point for the Token backend.
32
33 See :mod:`keystone.common.manager.Manager` for more details on how this
34 dynamically calls the backend.
35
36 """
37
38 def __init__(self):
39 super(Manager, self).__init__(CONF.token.driver)
40
41
42class Driver(object):
43 """Interface description for a Token driver."""
44
45 def get_token(self, token_id):
46 """Get a token by id.
47
48 :param token_id: identity of the token
49 :type token_id: string
50 :returns: token_ref
51 :raises: keystone.exception.TokenNotFound
52
53 """
54 raise exception.NotImplemented()
55
56 def create_token(self, token_id, data):
57 """Create a token by id and data.
58
59 :param token_id: identity of the token
60 :type token_id: string
61 :param data: dictionary with additional reference information
62
63 ::
64
65 {
66 expires=''
67 id=token_id,
68 user=user_ref,
69 tenant=tenant_ref,
70 metadata=metadata_ref
71 }
72
73 :type data: dict
74 :returns: token_ref or None.
75
76 """
77 raise exception.NotImplemented()
78
79 def delete_token(self, token_id):
80 """Deletes a token by id.
81
82 :param token_id: identity of the token
83 :type token_id: string
84 :returns: None.
85 :raises: keystone.exception.TokenNotFound
86
87 """
88 raise exception.NotImplemented()
89
90 def list_tokens(self, user_id):
91 """Returns a list of current token_id's for a user
92
93 :param user_id: identity of the user
94 :type user_id: string
95 :returns: list of token_id's
96
97 """
98 raise exception.NotImplemented()
99
100 def _get_default_expire_time(self):
101 """Determine when a token should expire based on the config.
102
103 :returns: a naive utc datetime.datetime object
104
105 """
106 expire_delta = datetime.timedelta(seconds=CONF.token.expiration)
107 return datetime.datetime.utcnow() + expire_delta
1080
=== removed directory '.pc/keystone-CVE-2012-4413.patch/tests'
=== removed file '.pc/keystone-CVE-2012-4413.patch/tests/test_keystoneclient.py'
--- .pc/keystone-CVE-2012-4413.patch/tests/test_keystoneclient.py 2012-09-12 09:47:55 +0000
+++ .pc/keystone-CVE-2012-4413.patch/tests/test_keystoneclient.py 1970-01-01 00:00:00 +0000
@@ -1,970 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2012 OpenStack LLC
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
17import time
18import uuid
19
20import nose.exc
21
22from keystone import test
23
24import default_fixtures
25
26OPENSTACK_REPO = 'https://review.openstack.org/p/openstack'
27KEYSTONECLIENT_REPO = '%s/python-keystoneclient.git' % OPENSTACK_REPO
28
29
30class CompatTestCase(test.TestCase):
31 def setUp(self):
32 super(CompatTestCase, self).setUp()
33
34 self.load_backends()
35 self.load_fixtures(default_fixtures)
36
37 self.public_server = self.serveapp('keystone', name='main')
38 self.admin_server = self.serveapp('keystone', name='admin')
39
40 # TODO(termie): is_admin is being deprecated once the policy stuff
41 # is all working
42 # TODO(termie): add an admin user to the fixtures and use that user
43 # override the fixtures, for now
44 self.metadata_foobar = self.identity_api.update_metadata(
45 self.user_foo['id'], self.tenant_bar['id'],
46 dict(roles=['keystone_admin'], is_admin='1'))
47
48 def tearDown(self):
49 self.public_server.kill()
50 self.admin_server.kill()
51 self.public_server = None
52 self.admin_server = None
53 super(CompatTestCase, self).tearDown()
54
55 def _public_url(self):
56 public_port = self.public_server.socket_info['socket'][1]
57 return "http://localhost:%s/v2.0" % public_port
58
59 def _admin_url(self):
60 admin_port = self.admin_server.socket_info['socket'][1]
61 return "http://localhost:%s/v2.0" % admin_port
62
63 def _client(self, admin=False, **kwargs):
64 from keystoneclient.v2_0 import client as ks_client
65
66 url = self._admin_url() if admin else self._public_url()
67 kc = ks_client.Client(endpoint=url,
68 auth_url=self._public_url(),
69 **kwargs)
70 kc.authenticate()
71 # have to manually overwrite the management url after authentication
72 kc.management_url = url
73 return kc
74
75 def get_client(self, user_ref=None, tenant_ref=None, admin=False):
76 if user_ref is None:
77 user_ref = self.user_foo
78 if tenant_ref is None:
79 for user in default_fixtures.USERS:
80 if user['id'] == user_ref['id']:
81 tenant_id = user['tenants'][0]
82 else:
83 tenant_id = tenant_ref['id']
84
85 return self._client(username=user_ref['name'],
86 password=user_ref['password'],
87 tenant_id=tenant_id,
88 admin=admin)
89
90
91class KeystoneClientTests(object):
92 """Tests for all versions of keystoneclient."""
93
94 def test_authenticate_tenant_name_and_tenants(self):
95 client = self.get_client()
96 tenants = client.tenants.list()
97 self.assertEquals(tenants[0].id, self.tenant_bar['id'])
98
99 def test_authenticate_tenant_id_and_tenants(self):
100 client = self._client(username=self.user_foo['name'],
101 password=self.user_foo['password'],
102 tenant_id='bar')
103 tenants = client.tenants.list()
104 self.assertEquals(tenants[0].id, self.tenant_bar['id'])
105
106 def test_authenticate_invalid_tenant_id(self):
107 from keystoneclient import exceptions as client_exceptions
108 self.assertRaises(client_exceptions.Unauthorized,
109 self._client,
110 username=self.user_foo['name'],
111 password=self.user_foo['password'],
112 tenant_id='baz')
113
114 def test_authenticate_token_no_tenant(self):
115 client = self.get_client()
116 token = client.auth_token
117 token_client = self._client(token=token)
118 tenants = token_client.tenants.list()
119 self.assertEquals(tenants[0].id, self.tenant_bar['id'])
120
121 def test_authenticate_token_tenant_id(self):
122 client = self.get_client()
123 token = client.auth_token
124 token_client = self._client(token=token, tenant_id='bar')
125 tenants = token_client.tenants.list()
126 self.assertEquals(tenants[0].id, self.tenant_bar['id'])
127
128 def test_authenticate_token_invalid_tenant_id(self):
129 from keystoneclient import exceptions as client_exceptions
130 client = self.get_client()
131 token = client.auth_token
132 self.assertRaises(client_exceptions.AuthorizationFailure,
133 self._client, token=token, tenant_id='baz')
134
135 def test_authenticate_token_tenant_name(self):
136 client = self.get_client()
137 token = client.auth_token
138 token_client = self._client(token=token, tenant_name='BAR')
139 tenants = token_client.tenants.list()
140 self.assertEquals(tenants[0].id, self.tenant_bar['id'])
141 self.assertEquals(tenants[0].id, self.tenant_bar['id'])
142
143 def test_authenticate_and_delete_token(self):
144 from keystoneclient import exceptions as client_exceptions
145
146 client = self.get_client(admin=True)
147 token = client.auth_token
148 token_client = self._client(token=token)
149 tenants = token_client.tenants.list()
150 self.assertEquals(tenants[0].id, self.tenant_bar['id'])
151
152 client.tokens.delete(token_client.auth_token)
153
154 self.assertRaises(client_exceptions.Unauthorized,
155 token_client.tenants.list)
156
157 def test_authenticate_no_password(self):
158 from keystoneclient import exceptions as client_exceptions
159
160 user_ref = self.user_foo.copy()
161 user_ref['password'] = None
162 self.assertRaises(client_exceptions.AuthorizationFailure,
163 self.get_client,
164 user_ref)
165
166 def test_authenticate_no_username(self):
167 from keystoneclient import exceptions as client_exceptions
168
169 user_ref = self.user_foo.copy()
170 user_ref['name'] = None
171 self.assertRaises(client_exceptions.AuthorizationFailure,
172 self.get_client,
173 user_ref)
174
175 def test_authenticate_disabled_tenant(self):
176 from keystoneclient import exceptions as client_exceptions
177
178 admin_client = self.get_client(admin=True)
179
180 tenant = {
181 'name': uuid.uuid4().hex,
182 'description': uuid.uuid4().hex,
183 'enabled': False,
184 }
185 tenant_ref = admin_client.tenants.create(
186 tenant_name=tenant['name'],
187 description=tenant['description'],
188 enabled=tenant['enabled'])
189 tenant['id'] = tenant_ref.id
190
191 user = {
192 'name': uuid.uuid4().hex,
193 'password': uuid.uuid4().hex,
194 'email': uuid.uuid4().hex,
195 'tenant_id': tenant['id'],
196 }
197 user_ref = admin_client.users.create(
198 name=user['name'],
199 password=user['password'],
200 email=user['email'],
201 tenant_id=user['tenant_id'])
202 user['id'] = user_ref.id
203
204 # password authentication
205 self.assertRaises(
206 client_exceptions.Unauthorized,
207 self._client,
208 username=user['name'],
209 password=user['password'],
210 tenant_id=tenant['id'])
211
212 # token authentication
213 client = self._client(
214 username=user['name'],
215 password=user['password'])
216 self.assertRaises(
217 client_exceptions.Unauthorized,
218 self._client,
219 token=client.auth_token,
220 tenant_id=tenant['id'])
221
222 # FIXME(ja): this test should require the "keystone:admin" roled
223 # (probably the role set via --keystone_admin_role flag)
224 # FIXME(ja): add a test that admin endpoint is only sent to admin user
225 # FIXME(ja): add a test that admin endpoint returns unauthorized if not
226 # admin
227 def test_tenant_create_update_and_delete(self):
228 from keystoneclient import exceptions as client_exceptions
229
230 tenant_name = 'original_tenant'
231 tenant_description = 'My original tenant!'
232 tenant_enabled = True
233 client = self.get_client(admin=True)
234
235 # create, get, and list a tenant
236 tenant = client.tenants.create(tenant_name=tenant_name,
237 description=tenant_description,
238 enabled=tenant_enabled)
239 self.assertEquals(tenant.name, tenant_name)
240 self.assertEquals(tenant.description, tenant_description)
241 self.assertEquals(tenant.enabled, tenant_enabled)
242
243 tenant = client.tenants.get(tenant_id=tenant.id)
244 self.assertEquals(tenant.name, tenant_name)
245 self.assertEquals(tenant.description, tenant_description)
246 self.assertEquals(tenant.enabled, tenant_enabled)
247
248 tenant = [t for t in client.tenants.list() if t.id == tenant.id].pop()
249 self.assertEquals(tenant.name, tenant_name)
250 self.assertEquals(tenant.description, tenant_description)
251 self.assertEquals(tenant.enabled, tenant_enabled)
252
253 # update, get, and list a tenant
254 tenant_name = 'updated_tenant'
255 tenant_description = 'Updated tenant!'
256 tenant_enabled = False
257 tenant = client.tenants.update(tenant_id=tenant.id,
258 tenant_name=tenant_name,
259 enabled=tenant_enabled,
260 description=tenant_description)
261 self.assertEquals(tenant.name, tenant_name)
262 self.assertEquals(tenant.description, tenant_description)
263 self.assertEquals(tenant.enabled, tenant_enabled)
264
265 tenant = client.tenants.get(tenant_id=tenant.id)
266 self.assertEquals(tenant.name, tenant_name)
267 self.assertEquals(tenant.description, tenant_description)
268 self.assertEquals(tenant.enabled, tenant_enabled)
269
270 tenant = [t for t in client.tenants.list() if t.id == tenant.id].pop()
271 self.assertEquals(tenant.name, tenant_name)
272 self.assertEquals(tenant.description, tenant_description)
273 self.assertEquals(tenant.enabled, tenant_enabled)
274
275 # delete, get, and list a tenant
276 client.tenants.delete(tenant=tenant.id)
277 self.assertRaises(client_exceptions.NotFound, client.tenants.get,
278 tenant.id)
279 self.assertFalse([t for t in client.tenants.list()
280 if t.id == tenant.id])
281
282 def test_tenant_delete_404(self):
283 from keystoneclient import exceptions as client_exceptions
284 client = self.get_client(admin=True)
285 self.assertRaises(client_exceptions.NotFound,
286 client.tenants.delete,
287 tenant=uuid.uuid4().hex)
288
289 def test_tenant_get_404(self):
290 from keystoneclient import exceptions as client_exceptions
291 client = self.get_client(admin=True)
292 self.assertRaises(client_exceptions.NotFound,
293 client.tenants.get,
294 tenant_id=uuid.uuid4().hex)
295
296 def test_tenant_update_404(self):
297 from keystoneclient import exceptions as client_exceptions
298 client = self.get_client(admin=True)
299 self.assertRaises(client_exceptions.NotFound,
300 client.tenants.update,
301 tenant_id=uuid.uuid4().hex)
302
303 def test_tenant_list(self):
304 client = self.get_client()
305 tenants = client.tenants.list()
306 self.assertEquals(len(tenants), 1)
307
308 # Admin endpoint should return *all* tenants
309 client = self.get_client(admin=True)
310 tenants = client.tenants.list()
311 self.assertEquals(len(tenants), len(default_fixtures.TENANTS))
312
313 def test_invalid_password(self):
314 from keystoneclient import exceptions as client_exceptions
315
316 good_client = self._client(username=self.user_foo['name'],
317 password=self.user_foo['password'])
318 good_client.tenants.list()
319
320 self.assertRaises(client_exceptions.Unauthorized,
321 self._client,
322 username=self.user_foo['name'],
323 password='invalid')
324
325 def test_invalid_user_password(self):
326 from keystoneclient import exceptions as client_exceptions
327
328 self.assertRaises(client_exceptions.Unauthorized,
329 self._client,
330 username='blah',
331 password='blah')
332
333 def test_change_password_invalidates_token(self):
334 from keystoneclient import exceptions as client_exceptions
335
336 client = self.get_client(admin=True)
337
338 username = uuid.uuid4().hex
339 passwd = uuid.uuid4().hex
340 user = client.users.create(name=username, password=passwd,
341 email=uuid.uuid4().hex)
342
343 token_id = client.tokens.authenticate(username=username,
344 password=passwd).id
345
346 # authenticate with a token should work before a password change
347 client.tokens.authenticate(token=token_id)
348
349 client.users.update_password(user=user.id, password=uuid.uuid4().hex)
350
351 # authenticate with a token should not work after a password change
352 self.assertRaises(client_exceptions.Unauthorized,
353 client.tokens.authenticate,
354 token=token_id)
355
356 def test_disable_user_invalidates_token(self):
357 from keystoneclient import exceptions as client_exceptions
358
359 admin_client = self.get_client(admin=True)
360 foo_client = self.get_client(self.user_foo)
361
362 admin_client.users.update_enabled(user=self.user_foo['id'],
363 enabled=False)
364
365 self.assertRaises(client_exceptions.Unauthorized,
366 foo_client.tokens.authenticate,
367 token=foo_client.auth_token)
368
369 self.assertRaises(client_exceptions.Unauthorized,
370 self.get_client,
371 self.user_foo)
372
373 def test_token_expiry_maintained(self):
374 foo_client = self.get_client(self.user_foo)
375 orig_token = foo_client.service_catalog.catalog['token']
376
377 time.sleep(1.01)
378 reauthenticated_token = foo_client.tokens.authenticate(
379 token=foo_client.auth_token)
380
381 self.assertEquals(orig_token['expires'],
382 reauthenticated_token.expires)
383
384 def test_user_create_update_delete(self):
385 from keystoneclient import exceptions as client_exceptions
386
387 test_username = 'new_user'
388 client = self.get_client(admin=True)
389 user = client.users.create(name=test_username,
390 password='password',
391 email='user1@test.com')
392 self.assertEquals(user.name, test_username)
393
394 user = client.users.get(user=user.id)
395 self.assertEquals(user.name, test_username)
396
397 user = client.users.update(user=user,
398 name=test_username,
399 email='user2@test.com')
400 self.assertEquals(user.email, 'user2@test.com')
401
402 # NOTE(termie): update_enabled doesn't return anything, probably a bug
403 client.users.update_enabled(user=user, enabled=False)
404 user = client.users.get(user.id)
405 self.assertFalse(user.enabled)
406
407 self.assertRaises(client_exceptions.Unauthorized,
408 self._client,
409 username=test_username,
410 password='password')
411 client.users.update_enabled(user, True)
412
413 user = client.users.update_password(user=user, password='password2')
414
415 self._client(username=test_username,
416 password='password2')
417
418 user = client.users.update_tenant(user=user, tenant='bar')
419 # TODO(ja): once keystonelight supports default tenant
420 # when you login without specifying tenant, the
421 # token should be scoped to tenant 'bar'
422
423 client.users.delete(user.id)
424 self.assertRaises(client_exceptions.NotFound, client.users.get,
425 user.id)
426
427 # Test creating a user with a tenant (auto-add to tenant)
428 user2 = client.users.create(name=test_username,
429 password='password',
430 email='user1@test.com',
431 tenant_id='bar')
432 self.assertEquals(user2.name, test_username)
433
434 def test_user_create_404(self):
435 from keystoneclient import exceptions as client_exceptions
436 client = self.get_client(admin=True)
437 self.assertRaises(client_exceptions.NotFound,
438 client.users.create,
439 name=uuid.uuid4().hex,
440 password=uuid.uuid4().hex,
441 email=uuid.uuid4().hex,
442 tenant_id=uuid.uuid4().hex)
443
444 def test_user_get_404(self):
445 from keystoneclient import exceptions as client_exceptions
446 client = self.get_client(admin=True)
447 self.assertRaises(client_exceptions.NotFound,
448 client.users.get,
449 user=uuid.uuid4().hex)
450
451 def test_user_list_404(self):
452 from keystoneclient import exceptions as client_exceptions
453 client = self.get_client(admin=True)
454 self.assertRaises(client_exceptions.NotFound,
455 client.users.list,
456 tenant_id=uuid.uuid4().hex)
457
458 def test_user_update_404(self):
459 from keystoneclient import exceptions as client_exceptions
460 client = self.get_client(admin=True)
461 self.assertRaises(client_exceptions.NotFound,
462 client.users.update,
463 user=uuid.uuid4().hex)
464
465 def test_user_update_tenant_404(self):
466 raise nose.exc.SkipTest('N/A')
467 from keystoneclient import exceptions as client_exceptions
468 client = self.get_client(admin=True)
469 self.assertRaises(client_exceptions.NotFound,
470 client.users.update,
471 user=self.user_foo['id'],
472 tenant_id=uuid.uuid4().hex)
473
474 def test_user_update_password_404(self):
475 from keystoneclient import exceptions as client_exceptions
476 client = self.get_client(admin=True)
477 self.assertRaises(client_exceptions.NotFound,
478 client.users.update_password,
479 user=uuid.uuid4().hex,
480 password=uuid.uuid4().hex)
481
482 def test_user_delete_404(self):
483 from keystoneclient import exceptions as client_exceptions
484 client = self.get_client(admin=True)
485 self.assertRaises(client_exceptions.NotFound,
486 client.users.delete,
487 user=uuid.uuid4().hex)
488
489 def test_user_list(self):
490 client = self.get_client(admin=True)
491 users = client.users.list()
492 self.assertTrue(len(users) > 0)
493 user = users[0]
494 self.assertRaises(AttributeError, lambda: user.password)
495
496 def test_user_get(self):
497 client = self.get_client(admin=True)
498 user = client.users.get(user=self.user_foo['id'])
499 self.assertRaises(AttributeError, lambda: user.password)
500
501 def test_role_get(self):
502 client = self.get_client(admin=True)
503 role = client.roles.get(role='keystone_admin')
504 self.assertEquals(role.id, 'keystone_admin')
505
506 def test_role_crud(self):
507 from keystoneclient import exceptions as client_exceptions
508
509 test_role = 'new_role'
510 client = self.get_client(admin=True)
511 role = client.roles.create(name=test_role)
512 self.assertEquals(role.name, test_role)
513
514 role = client.roles.get(role=role.id)
515 self.assertEquals(role.name, test_role)
516
517 client.roles.delete(role=role.id)
518
519 self.assertRaises(client_exceptions.NotFound,
520 client.roles.delete,
521 role=role.id)
522 self.assertRaises(client_exceptions.NotFound,
523 client.roles.get,
524 role=role.id)
525
526 def test_role_get_404(self):
527 from keystoneclient import exceptions as client_exceptions
528 client = self.get_client(admin=True)
529 self.assertRaises(client_exceptions.NotFound,
530 client.roles.get,
531 role=uuid.uuid4().hex)
532
533 def test_role_delete_404(self):
534 from keystoneclient import exceptions as client_exceptions
535 client = self.get_client(admin=True)
536 self.assertRaises(client_exceptions.NotFound,
537 client.roles.delete,
538 role=uuid.uuid4().hex)
539
540 def test_role_list_404(self):
541 from keystoneclient import exceptions as client_exceptions
542 client = self.get_client(admin=True)
543 self.assertRaises(client_exceptions.NotFound,
544 client.roles.roles_for_user,
545 user=uuid.uuid4().hex,
546 tenant=uuid.uuid4().hex)
547 self.assertRaises(client_exceptions.NotFound,
548 client.roles.roles_for_user,
549 user=self.user_foo['id'],
550 tenant=uuid.uuid4().hex)
551 self.assertRaises(client_exceptions.NotFound,
552 client.roles.roles_for_user,
553 user=uuid.uuid4().hex,
554 tenant=self.tenant_bar['id'])
555
556 def test_role_list(self):
557 client = self.get_client(admin=True)
558 roles = client.roles.list()
559 # TODO(devcamcar): This assert should be more specific.
560 self.assertTrue(len(roles) > 0)
561
562 def test_ec2_credential_crud(self):
563 client = self.get_client()
564 creds = client.ec2.list(user_id=self.user_foo['id'])
565 self.assertEquals(creds, [])
566
567 cred = client.ec2.create(user_id=self.user_foo['id'],
568 tenant_id=self.tenant_bar['id'])
569 creds = client.ec2.list(user_id=self.user_foo['id'])
570 self.assertEquals(creds, [cred])
571
572 got = client.ec2.get(user_id=self.user_foo['id'], access=cred.access)
573 self.assertEquals(cred, got)
574
575 client.ec2.delete(user_id=self.user_foo['id'], access=cred.access)
576 creds = client.ec2.list(user_id=self.user_foo['id'])
577 self.assertEquals(creds, [])
578
579 def test_ec2_credentials_create_404(self):
580 from keystoneclient import exceptions as client_exceptions
581 client = self.get_client()
582 self.assertRaises(client_exceptions.NotFound,
583 client.ec2.create,
584 user_id=uuid.uuid4().hex,
585 tenant_id=self.tenant_bar['id'])
586 self.assertRaises(client_exceptions.NotFound,
587 client.ec2.create,
588 user_id=self.user_foo['id'],
589 tenant_id=uuid.uuid4().hex)
590
591 def test_ec2_credentials_delete_404(self):
592 from keystoneclient import exceptions as client_exceptions
593 client = self.get_client()
594 self.assertRaises(client_exceptions.NotFound,
595 client.ec2.delete,
596 user_id=uuid.uuid4().hex,
597 access=uuid.uuid4().hex)
598
599 def test_ec2_credentials_get_404(self):
600 from keystoneclient import exceptions as client_exceptions
601 client = self.get_client()
602 self.assertRaises(client_exceptions.NotFound,
603 client.ec2.get,
604 user_id=uuid.uuid4().hex,
605 access=uuid.uuid4().hex)
606
607 def test_ec2_credentials_list_404(self):
608 from keystoneclient import exceptions as client_exceptions
609 client = self.get_client()
610 self.assertRaises(client_exceptions.NotFound,
611 client.ec2.list,
612 user_id=uuid.uuid4().hex)
613
614 def test_ec2_credentials_list_user_forbidden(self):
615 from keystoneclient import exceptions as client_exceptions
616
617 two = self.get_client(self.user_two)
618 self.assertRaises(client_exceptions.Forbidden, two.ec2.list,
619 user_id=self.user_foo['id'])
620
621 def test_ec2_credentials_get_user_forbidden(self):
622 from keystoneclient import exceptions as client_exceptions
623
624 foo = self.get_client()
625 cred = foo.ec2.create(user_id=self.user_foo['id'],
626 tenant_id=self.tenant_bar['id'])
627
628 two = self.get_client(self.user_two)
629 self.assertRaises(client_exceptions.Forbidden, two.ec2.get,
630 user_id=self.user_foo['id'], access=cred.access)
631
632 foo.ec2.delete(user_id=self.user_foo['id'], access=cred.access)
633
634 def test_ec2_credentials_delete_user_forbidden(self):
635 from keystoneclient import exceptions as client_exceptions
636
637 foo = self.get_client()
638 cred = foo.ec2.create(user_id=self.user_foo['id'],
639 tenant_id=self.tenant_bar['id'])
640
641 two = self.get_client(self.user_two)
642 self.assertRaises(client_exceptions.Forbidden, two.ec2.delete,
643 user_id=self.user_foo['id'], access=cred.access)
644
645 foo.ec2.delete(user_id=self.user_foo['id'], access=cred.access)
646
647 def test_service_create_and_delete(self):
648 from keystoneclient import exceptions as client_exceptions
649
650 test_service = 'new_service'
651 client = self.get_client(admin=True)
652 service = client.services.create(name=test_service,
653 service_type='test',
654 description='test')
655 self.assertEquals(service.name, test_service)
656
657 service = client.services.get(id=service.id)
658 self.assertEquals(service.name, test_service)
659
660 client.services.delete(id=service.id)
661 self.assertRaises(client_exceptions.NotFound, client.services.get,
662 id=service.id)
663
664 def test_service_list(self):
665 client = self.get_client(admin=True)
666 test_service = 'new_service'
667 service = client.services.create(name=test_service,
668 service_type='test',
669 description='test')
670 services = client.services.list()
671 # TODO(devcamcar): This assert should be more specific.
672 self.assertTrue(len(services) > 0)
673
674 def test_service_delete_404(self):
675 from keystoneclient import exceptions as client_exceptions
676 client = self.get_client(admin=True)
677 self.assertRaises(client_exceptions.NotFound,
678 client.services.delete,
679 id=uuid.uuid4().hex)
680
681 def test_service_get_404(self):
682 from keystoneclient import exceptions as client_exceptions
683 client = self.get_client(admin=True)
684 self.assertRaises(client_exceptions.NotFound,
685 client.services.get,
686 id=uuid.uuid4().hex)
687
688 def test_endpoint_create_404(self):
689 from keystoneclient import exceptions as client_exceptions
690 client = self.get_client(admin=True)
691 self.assertRaises(client_exceptions.NotFound,
692 client.endpoints.create,
693 region=uuid.uuid4().hex,
694 service_id=uuid.uuid4().hex,
695 publicurl=uuid.uuid4().hex,
696 adminurl=uuid.uuid4().hex,
697 internalurl=uuid.uuid4().hex)
698
699 def test_endpoint_delete_404(self):
700 # the catalog backend is expected to return Not Implemented
701 from keystoneclient import exceptions as client_exceptions
702 client = self.get_client(admin=True)
703 self.assertRaises(client_exceptions.HTTPNotImplemented,
704 client.endpoints.delete,
705 id=uuid.uuid4().hex)
706
707 def test_admin_requires_adminness(self):
708 from keystoneclient import exceptions as client_exceptions
709 # FIXME(ja): this should be Unauthorized
710 exception = client_exceptions.ClientException
711
712 two = self.get_client(self.user_two, admin=True) # non-admin user
713
714 # USER CRUD
715 self.assertRaises(exception,
716 two.users.list)
717 self.assertRaises(exception,
718 two.users.get,
719 user=self.user_two['id'])
720 self.assertRaises(exception,
721 two.users.create,
722 name='oops',
723 password='password',
724 email='oops@test.com')
725 self.assertRaises(exception,
726 two.users.delete,
727 user=self.user_foo['id'])
728
729 # TENANT CRUD
730 self.assertRaises(exception,
731 two.tenants.list)
732 self.assertRaises(exception,
733 two.tenants.get,
734 tenant_id=self.tenant_bar['id'])
735 self.assertRaises(exception,
736 two.tenants.create,
737 tenant_name='oops',
738 description="shouldn't work!",
739 enabled=True)
740 self.assertRaises(exception,
741 two.tenants.delete,
742 tenant=self.tenant_baz['id'])
743
744 # ROLE CRUD
745 self.assertRaises(exception,
746 two.roles.get,
747 role='keystone_admin')
748 self.assertRaises(exception,
749 two.roles.list)
750 self.assertRaises(exception,
751 two.roles.create,
752 name='oops')
753 self.assertRaises(exception,
754 two.roles.delete,
755 role='keystone_admin')
756
757 # TODO(ja): MEMBERSHIP CRUD
758 # TODO(ja): determine what else todo
759
760
761class KcMasterTestCase(CompatTestCase, KeystoneClientTests):
762 def test_tenant_add_and_remove_user(self):
763 client = self.get_client(admin=True)
764 client.roles.add_user_role(tenant=self.tenant_baz['id'],
765 user=self.user_foo['id'],
766 role=self.role_useless['id'])
767 user_refs = client.tenants.list_users(tenant=self.tenant_baz['id'])
768 self.assert_(self.user_foo['id'] in [x.id for x in user_refs])
769 client.roles.remove_user_role(tenant=self.tenant_baz['id'],
770 user=self.user_foo['id'],
771 role=self.role_useless['id'])
772 user_refs = client.tenants.list_users(tenant=self.tenant_baz['id'])
773 self.assert_(self.user_foo['id'] not in [x.id for x in user_refs])
774
775 def test_user_role_add_404(self):
776 from keystoneclient import exceptions as client_exceptions
777 client = self.get_client(admin=True)
778 self.assertRaises(client_exceptions.NotFound,
779 client.roles.add_user_role,
780 tenant=uuid.uuid4().hex,
781 user=self.user_foo['id'],
782 role=self.role_useless['id'])
783 self.assertRaises(client_exceptions.NotFound,
784 client.roles.add_user_role,
785 tenant=self.tenant_baz['id'],
786 user=uuid.uuid4().hex,
787 role=self.role_useless['id'])
788 self.assertRaises(client_exceptions.NotFound,
789 client.roles.add_user_role,
790 tenant=self.tenant_baz['id'],
791 user=self.user_foo['id'],
792 role=uuid.uuid4().hex)
793
794 def test_user_role_remove_404(self):
795 from keystoneclient import exceptions as client_exceptions
796 client = self.get_client(admin=True)
797 self.assertRaises(client_exceptions.NotFound,
798 client.roles.remove_user_role,
799 tenant=uuid.uuid4().hex,
800 user=self.user_foo['id'],
801 role=self.role_useless['id'])
802 self.assertRaises(client_exceptions.NotFound,
803 client.roles.remove_user_role,
804 tenant=self.tenant_baz['id'],
805 user=uuid.uuid4().hex,
806 role=self.role_useless['id'])
807 self.assertRaises(client_exceptions.NotFound,
808 client.roles.remove_user_role,
809 tenant=self.tenant_baz['id'],
810 user=self.user_foo['id'],
811 role=uuid.uuid4().hex)
812 self.assertRaises(client_exceptions.NotFound,
813 client.roles.remove_user_role,
814 tenant=self.tenant_baz['id'],
815 user=self.user_foo['id'],
816 role=self.role_useless['id'])
817
818 def test_tenant_list_marker(self):
819 client = self.get_client()
820
821 # Add two arbitrary tenants to user for testing purposes
822 for i in range(2):
823 tenant_id = uuid.uuid4().hex
824 tenant = {'name': 'tenant-%s' % tenant_id, 'id': tenant_id}
825 self.identity_api.create_tenant(tenant_id, tenant)
826 self.identity_api.add_user_to_tenant(tenant_id,
827 self.user_foo['id'])
828
829 tenants = client.tenants.list()
830 self.assertEqual(len(tenants), 3)
831
832 tenants_marker = client.tenants.list(marker=tenants[0].id)
833 self.assertEqual(len(tenants_marker), 2)
834 self.assertEqual(tenants[1].name, tenants_marker[0].name)
835 self.assertEqual(tenants[2].name, tenants_marker[1].name)
836
837 def test_tenant_list_marker_not_found(self):
838 from keystoneclient import exceptions as client_exceptions
839
840 client = self.get_client()
841 self.assertRaises(client_exceptions.BadRequest,
842 client.tenants.list, marker=uuid.uuid4().hex)
843
844 def test_tenant_list_limit(self):
845 client = self.get_client()
846
847 # Add two arbitrary tenants to user for testing purposes
848 for i in range(2):
849 tenant_id = uuid.uuid4().hex
850 tenant = {'name': 'tenant-%s' % tenant_id, 'id': tenant_id}
851 self.identity_api.create_tenant(tenant_id, tenant)
852 self.identity_api.add_user_to_tenant(tenant_id,
853 self.user_foo['id'])
854
855 tenants = client.tenants.list()
856 self.assertEqual(len(tenants), 3)
857
858 tenants_limited = client.tenants.list(limit=2)
859 self.assertEqual(len(tenants_limited), 2)
860 self.assertEqual(tenants[0].name, tenants_limited[0].name)
861 self.assertEqual(tenants[1].name, tenants_limited[1].name)
862
863 def test_tenant_list_limit_bad_value(self):
864 from keystoneclient import exceptions as client_exceptions
865
866 client = self.get_client()
867 self.assertRaises(client_exceptions.BadRequest,
868 client.tenants.list, limit='a')
869 self.assertRaises(client_exceptions.BadRequest,
870 client.tenants.list, limit=-1)
871
872 def test_roles_get_by_user(self):
873 client = self.get_client(admin=True)
874 roles = client.roles.roles_for_user(user=self.user_foo['id'],
875 tenant=self.tenant_bar['id'])
876 self.assertTrue(len(roles) > 0)
877
878
879class KcEssex3TestCase(CompatTestCase, KeystoneClientTests):
880 def test_tenant_add_and_remove_user(self):
881 raise nose.exc.SkipTest('Keystoneclient Essex 3 tests disabled.')
882 client = self.get_client(admin=True)
883 client.roles.add_user_to_tenant(tenant_id=self.tenant_baz['id'],
884 user_id=self.user_foo['id'],
885 role_id=self.role_useless['id'])
886 role_refs = client.roles.get_user_role_refs(
887 user_id=self.user_foo['id'])
888 self.assert_(self.tenant_baz['id'] in [x.tenantId for x in role_refs])
889
890 # get the "role_refs" so we get the proper id, this is how the clients
891 # do it
892 roleref_refs = client.roles.get_user_role_refs(
893 user_id=self.user_foo['id'])
894 for roleref_ref in roleref_refs:
895 if (roleref_ref.roleId == self.role_useless['id']
896 and roleref_ref.tenantId == self.tenant_baz['id']):
897 # use python's scope fall through to leave roleref_ref set
898 break
899
900 client.roles.remove_user_from_tenant(tenant_id=self.tenant_baz['id'],
901 user_id=self.user_foo['id'],
902 role_id=roleref_ref.id)
903
904 role_refs = client.roles.get_user_role_refs(
905 user_id=self.user_foo['id'])
906 self.assert_(self.tenant_baz['id'] not in
907 [x.tenantId for x in role_refs])
908
909 def test_roles_get_by_user(self):
910 raise nose.exc.SkipTest('Keystoneclient Essex 3 tests disabled.')
911 client = self.get_client(admin=True)
912 roles = client.roles.get_user_role_refs(user_id='foo')
913 self.assertTrue(len(roles) > 0)
914
915 def test_role_list_404(self):
916 raise nose.exc.SkipTest('N/A')
917
918 def test_authenticate_and_delete_token(self):
919 raise nose.exc.SkipTest('N/A')
920
921 def test_user_create_update_delete(self):
922 raise nose.exc.SkipTest('Keystoneclient Essex 3 tests disabled.')
923 from keystoneclient import exceptions as client_exceptions
924
925 test_username = 'new_user'
926 client = self.get_client(admin=True)
927 user = client.users.create(name=test_username,
928 password='password',
929 email='user1@test.com')
930 self.assertEquals(user.name, test_username)
931
932 user = client.users.get(user=user.id)
933 self.assertEquals(user.name, test_username)
934
935 user = client.users.update_email(user=user, email='user2@test.com')
936 self.assertEquals(user.email, 'user2@test.com')
937
938 # NOTE(termie): update_enabled doesn't return anything, probably a bug
939 client.users.update_enabled(user=user, enabled=False)
940 user = client.users.get(user.id)
941 self.assertFalse(user.enabled)
942
943 self.assertRaises(client_exceptions.Unauthorized,
944 self._client,
945 username=test_username,
946 password='password')
947 client.users.update_enabled(user, True)
948
949 user = client.users.update_password(user=user, password='password2')
950
951 self._client(username=test_username,
952 password='password2')
953
954 user = client.users.update_tenant(user=user, tenant='bar')
955 # TODO(ja): once keystonelight supports default tenant
956 # when you login without specifying tenant, the
957 # token should be scoped to tenant 'bar'
958
959 client.users.delete(user.id)
960 self.assertRaises(client_exceptions.NotFound, client.users.get,
961 user.id)
962
963 def test_user_update_404(self):
964 raise nose.exc.SkipTest('N/A')
965
966 def test_endpoint_create_404(self):
967 raise nose.exc.SkipTest('N/A')
968
969 def test_endpoint_delete_404(self):
970 raise nose.exc.SkipTest('N/A')
9710
=== removed directory '.pc/keystone-CVE-2012-5571.patch'
=== removed directory '.pc/keystone-CVE-2012-5571.patch/keystone'
=== removed directory '.pc/keystone-CVE-2012-5571.patch/keystone/contrib'
=== removed directory '.pc/keystone-CVE-2012-5571.patch/keystone/contrib/ec2'
=== removed file '.pc/keystone-CVE-2012-5571.patch/keystone/contrib/ec2/core.py'
--- .pc/keystone-CVE-2012-5571.patch/keystone/contrib/ec2/core.py 2012-11-26 14:07:34 +0000
+++ .pc/keystone-CVE-2012-5571.patch/keystone/contrib/ec2/core.py 1970-01-01 00:00:00 +0000
@@ -1,347 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2012 OpenStack LLC
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
17"""Main entry point into the EC2 Credentials service.
18
19This service allows the creation of access/secret credentials used for
20the ec2 interop layer of OpenStack.
21
22A user can create as many access/secret pairs, each of which map to a
23specific tenant. This is required because OpenStack supports a user
24belonging to multiple tenants, whereas the signatures created on ec2-style
25requests don't allow specification of which tenant the user wishs to act
26upon.
27
28To complete the cycle, we provide a method that OpenStack services can
29use to validate a signature and get a corresponding openstack token. This
30token allows method calls to other services within the context the
31access/secret was created. As an example, nova requests keystone to validate
32the signature of a request, receives a token, and then makes a request to
33glance to list images needed to perform the requested task.
34
35"""
36
37import uuid
38
39from keystone import catalog
40from keystone import config
41from keystone import exception
42from keystone import identity
43from keystone import policy
44from keystone import service
45from keystone import token
46from keystone.common import manager
47from keystone.common import utils
48from keystone.common import wsgi
49
50
51CONF = config.CONF
52
53
54class Manager(manager.Manager):
55 """Default pivot point for the EC2 Credentials backend.
56
57 See :mod:`keystone.common.manager.Manager` for more details on how this
58 dynamically calls the backend.
59
60 """
61
62 def __init__(self):
63 super(Manager, self).__init__(CONF.ec2.driver)
64
65
66class Ec2Extension(wsgi.ExtensionRouter):
67 def add_routes(self, mapper):
68 ec2_controller = Ec2Controller()
69 # validation
70 mapper.connect('/ec2tokens',
71 controller=ec2_controller,
72 action='authenticate',
73 conditions=dict(method=['POST']))
74
75 # crud
76 mapper.connect('/users/{user_id}/credentials/OS-EC2',
77 controller=ec2_controller,
78 action='create_credential',
79 conditions=dict(method=['POST']))
80 mapper.connect('/users/{user_id}/credentials/OS-EC2',
81 controller=ec2_controller,
82 action='get_credentials',
83 conditions=dict(method=['GET']))
84 mapper.connect('/users/{user_id}/credentials/OS-EC2/{credential_id}',
85 controller=ec2_controller,
86 action='get_credential',
87 conditions=dict(method=['GET']))
88 mapper.connect('/users/{user_id}/credentials/OS-EC2/{credential_id}',
89 controller=ec2_controller,
90 action='delete_credential',
91 conditions=dict(method=['DELETE']))
92
93
94class Ec2Controller(wsgi.Application):
95 def __init__(self):
96 self.catalog_api = catalog.Manager()
97 self.identity_api = identity.Manager()
98 self.token_api = token.Manager()
99 self.policy_api = policy.Manager()
100 self.ec2_api = Manager()
101 super(Ec2Controller, self).__init__()
102
103 def check_signature(self, creds_ref, credentials):
104 signer = utils.Ec2Signer(creds_ref['secret'])
105 signature = signer.generate(credentials)
106 if utils.auth_str_equal(credentials['signature'], signature):
107 return
108 # NOTE(vish): Some libraries don't use the port when signing
109 # requests, so try again without port.
110 elif ':' in credentials['signature']:
111 hostname, _port = credentials['host'].split(':')
112 credentials['host'] = hostname
113 signature = signer.generate(credentials)
114 if not utils.auth_str_equal(credentials.signature, signature):
115 raise exception.Unauthorized(message='Invalid EC2 signature.')
116 else:
117 raise exception.Unauthorized(message='EC2 signature not supplied.')
118
119 def authenticate(self, context, credentials=None,
120 ec2Credentials=None):
121 """Validate a signed EC2 request and provide a token.
122
123 Other services (such as Nova) use this **admin** call to determine
124 if a request they signed received is from a valid user.
125
126 If it is a valid signature, an openstack token that maps
127 to the user/tenant is returned to the caller, along with
128 all the other details returned from a normal token validation
129 call.
130
131 The returned token is useful for making calls to other
132 OpenStack services within the context of the request.
133
134 :param context: standard context
135 :param credentials: dict of ec2 signature
136 :param ec2Credentials: DEPRECATED dict of ec2 signature
137 :returns: token: openstack token equivalent to access key along
138 with the corresponding service catalog and roles
139 """
140
141 # FIXME(ja): validate that a service token was used!
142
143 # NOTE(termie): backwards compat hack
144 if not credentials and ec2Credentials:
145 credentials = ec2Credentials
146
147 if not 'access' in credentials:
148 raise exception.Unauthorized(message='EC2 signature not supplied.')
149
150 creds_ref = self._get_credentials(context,
151 credentials['access'])
152 self.check_signature(creds_ref, credentials)
153
154 # TODO(termie): don't create new tokens every time
155 # TODO(termie): this is copied from TokenController.authenticate
156 token_id = uuid.uuid4().hex
157 tenant_ref = self.identity_api.get_tenant(
158 context=context,
159 tenant_id=creds_ref['tenant_id'])
160 user_ref = self.identity_api.get_user(
161 context=context,
162 user_id=creds_ref['user_id'])
163 metadata_ref = self.identity_api.get_metadata(
164 context=context,
165 user_id=user_ref['id'],
166 tenant_id=tenant_ref['id'])
167 catalog_ref = self.catalog_api.get_catalog(
168 context=context,
169 user_id=user_ref['id'],
170 tenant_id=tenant_ref['id'],
171 metadata=metadata_ref)
172
173 token_ref = self.token_api.create_token(
174 context, token_id, dict(id=token_id,
175 user=user_ref,
176 tenant=tenant_ref,
177 metadata=metadata_ref))
178
179 # TODO(termie): optimize this call at some point and put it into the
180 # the return for metadata
181 # fill out the roles in the metadata
182 roles_ref = []
183 for role_id in metadata_ref.get('roles', []):
184 roles_ref.append(self.identity_api.get_role(context, role_id))
185
186 # TODO(termie): make this a util function or something
187 # TODO(termie): i don't think the ec2 middleware currently expects a
188 # full return, but it contains a note saying that it
189 # would be better to expect a full return
190 token_controller = service.TokenController()
191 return token_controller._format_authenticate(
192 token_ref, roles_ref, catalog_ref)
193
194 def create_credential(self, context, user_id, tenant_id):
195 """Create a secret/access pair for use with ec2 style auth.
196
197 Generates a new set of credentials that map the the user/tenant
198 pair.
199
200 :param context: standard context
201 :param user_id: id of user
202 :param tenant_id: id of tenant
203 :returns: credential: dict of ec2 credential
204 """
205 if not self._is_admin(context):
206 self._assert_identity(context, user_id)
207
208 self._assert_valid_user_id(context, user_id)
209 self._assert_valid_tenant_id(context, tenant_id)
210
211 cred_ref = {'user_id': user_id,
212 'tenant_id': tenant_id,
213 'access': uuid.uuid4().hex,
214 'secret': uuid.uuid4().hex}
215 self.ec2_api.create_credential(context, cred_ref['access'], cred_ref)
216 return {'credential': cred_ref}
217
218 def get_credentials(self, context, user_id):
219 """List all credentials for a user.
220
221 :param context: standard context
222 :param user_id: id of user
223 :returns: credentials: list of ec2 credential dicts
224 """
225 if not self._is_admin(context):
226 self._assert_identity(context, user_id)
227 self._assert_valid_user_id(context, user_id)
228 return {'credentials': self.ec2_api.list_credentials(context, user_id)}
229
230 def get_credential(self, context, user_id, credential_id):
231 """Retreive a user's access/secret pair by the access key.
232
233 Grab the full access/secret pair for a given access key.
234
235 :param context: standard context
236 :param user_id: id of user
237 :param credential_id: access key for credentials
238 :returns: credential: dict of ec2 credential
239 """
240 if not self._is_admin(context):
241 self._assert_identity(context, user_id)
242 self._assert_valid_user_id(context, user_id)
243 creds = self._get_credentials(context, credential_id)
244 return {'credential': creds}
245
246 def delete_credential(self, context, user_id, credential_id):
247 """Delete a user's access/secret pair.
248
249 Used to revoke a user's access/secret pair
250
251 :param context: standard context
252 :param user_id: id of user
253 :param credential_id: access key for credentials
254 :returns: bool: success
255 """
256 if not self._is_admin(context):
257 self._assert_identity(context, user_id)
258 self._assert_owner(context, user_id, credential_id)
259
260 self._assert_valid_user_id(context, user_id)
261 self._get_credentials(context, credential_id)
262 return self.ec2_api.delete_credential(context, credential_id)
263
264 def _get_credentials(self, context, credential_id):
265 """Return credentials from an ID.
266
267 :param context: standard context
268 :param credential_id: id of credential
269 :raises exception.Unauthorized: when credential id is invalid
270 :returns: credential: dict of ec2 credential.
271 """
272 creds = self.ec2_api.get_credential(context,
273 credential_id)
274 if not creds:
275 raise exception.Unauthorized(message='EC2 access key not found.')
276 return creds
277
278 def _assert_identity(self, context, user_id):
279 """Check that the provided token belongs to the user.
280
281 :param context: standard context
282 :param user_id: id of user
283 :raises exception.Forbidden: when token is invalid
284
285 """
286 try:
287 token_ref = self.token_api.get_token(context=context,
288 token_id=context['token_id'])
289 except exception.TokenNotFound:
290 raise exception.Unauthorized()
291 token_user_id = token_ref['user'].get('id')
292 if not token_user_id == user_id:
293 raise exception.Forbidden()
294
295 def _is_admin(self, context):
296 """Wrap admin assertion error return statement.
297
298 :param context: standard context
299 :returns: bool: success
300
301 """
302 try:
303 self.assert_admin(context)
304 return True
305 except exception.Forbidden:
306 return False
307
308 def _assert_owner(self, context, user_id, credential_id):
309 """Ensure the provided user owns the credential.
310
311 :param context: standard context
312 :param user_id: expected credential owner
313 :param credential_id: id of credential object
314 :raises exception.Forbidden: on failure
315
316 """
317 cred_ref = self.ec2_api.get_credential(context, credential_id)
318 if not user_id == cred_ref['user_id']:
319 raise exception.Forbidden()
320
321 def _assert_valid_user_id(self, context, user_id):
322 """Ensure a valid user id.
323
324 :param context: standard context
325 :param user_id: expected credential owner
326 :raises exception.UserNotFound: on failure
327
328 """
329 user_ref = self.identity_api.get_user(
330 context=context,
331 user_id=user_id)
332 if not user_ref:
333 raise exception.UserNotFound(user_id=user_id)
334
335 def _assert_valid_tenant_id(self, context, tenant_id):
336 """Ensure a valid tenant id.
337
338 :param context: standard context
339 :param user_id: expected credential owner
340 :raises exception.UserNotFound: on failure
341
342 """
343 tenant_ref = self.identity_api.get_tenant(
344 context=context,
345 tenant_id=tenant_id)
346 if not tenant_ref:
347 raise exception.TenantNotFound(tenant_id=tenant_id)
3480
=== added file 'ChangeLog'
--- ChangeLog 1970-01-01 00:00:00 +0000
+++ ChangeLog 2012-12-18 14:06:26 +0000
@@ -0,0 +1,29735 @@
1commit c17a9992c8a94c7728bd762115874f125c0905b7
2Merge: 025b1d5 8735009
3Author: Jenkins <jenkins@review.openstack.org>
4Date: Thu Nov 22 19:41:20 2012 +0000
5
6 Merge "Ensures User is member of tenant in ec2 validation" into stable/essex
7
8commit 025b1d52e61fff4dff913fc58d0de81712b808b6
9Author: Ionuț Arțăriși <iartarisi@suse.cz>
10Date: Wed Oct 31 14:32:04 2012 +0100
11
12 pin sqlalchemy to 0.7
13
14 sqlalchemy 0.8.0b1 breaks some dependencies such as sqlalchemy-migrate, pin the version until we fix them
15
16 Essex backport note: lower bound is not defined, Essex is known to work
17 with older sqlalchemy versions e.g. precise has 0.7.4
18
19 Fixes bug #1073569
20
21 Change-Id: I6620276bf8f0a7cbc1d51aa226cd33c512e59a48
22
23 tools/pip-requires | 4 ++--
24 1 file changed, 2 insertions(+), 2 deletions(-)
25
26commit 8735009dc5b895db265a1cd573f39f4acfca2a19
27Author: Vishvananda Ishaya <vishvananda@gmail.com>
28Date: Tue Nov 13 15:49:19 2012 -0800
29
30 Ensures User is member of tenant in ec2 validation
31
32 It is possible that a user is no longer a member of a tenant when
33 they attempt to use an ec2 token. This checks to make sure that
34 the user still has at least one valid role in the tenant before
35 authenticating them. This should automatically work for the s3
36 version as well since it is a subclass.
37
38 Fixes bug 1064914
39
40 Change-Id: Ieb237bae936a7b00ce7ba4d4c59aec6c7a69ec21
41
42 keystone/contrib/ec2/core.py | 23 +++++++++++++----------
43 1 file changed, 13 insertions(+), 10 deletions(-)
44
45commit ddb40198c9323ff8dc82a44a72e456a7bfe736b8
46Author: Mark McLoughlin <markmc@redhat.com>
47Date: Thu Oct 11 20:44:32 2012 +0100
48
49 Open 2012.1.4 development
50
51 Bump version to 2012.1.4 to formally open development after the release
52 of 2012.1.3.
53
54 See http://wiki.openstack.org/StableBranchRelease
55
56 Note - 2012.1.3 is expected to be the final official release of Essex.
57
58 Change-Id: I0de6fae1495deab60bd667e4653210b22b994b39
59
60 setup.py | 2 +-
61 1 file changed, 1 insertion(+), 1 deletion(-)
62
63commit 0e1f05e7a851f5fb72742e4d3e4978d76fe23b55
64Author: Dolph Mathews <dolph.mathews@gmail.com>
65Date: Tue Sep 25 19:04:50 2012 +0000
66
67 utf-8 encode user keys in memcache (bug 1056373)
68
69 (cherry picked from commit 431e50a7851d2e7dbb212d02647faeb958ed21e8)
70
71 Change-Id: I026dd4282742213e69c7aa02e109439b07a73c8e
72
73 keystone/token/backends/memcache.py | 8 ++++++--
74 tests/test_backend_memcache.py | 14 +++++++++++++-
75 2 files changed, 19 insertions(+), 3 deletions(-)
76
77commit 176ee9bce7557937710c8ec8086ff61cc751cf0f
78Author: Dolph Mathews <dolph.mathews@gmail.com>
79Date: Thu Sep 13 11:59:11 2012 -0500
80
81 Limit token revocation to tenant (bug 1050025)
82
83 Change-Id: I7ebe0192b4900ad9475119a6d582233b37b31fb4
84
85 keystone/identity/core.py | 8 ++++----
86 keystone/token/backends/kvs.py | 15 ++++++++++-----
87 keystone/token/backends/memcache.py | 11 ++++++++---
88 keystone/token/backends/sql.py | 7 ++++++-
89 keystone/token/core.py | 16 +++++++++++-----
90 tests/test_backend.py | 22 +++++++++++++++++++++-
91 6 files changed, 60 insertions(+), 19 deletions(-)
92
93commit 58ac6691a21675be9e2ffb0f84a05fc3cd4d2e2e
94Author: Dolph Mathews <dolph.mathews@gmail.com>
95Date: Fri Sep 7 14:55:31 2012 -0500
96
97 Delete user tokens after role grant/revoke
98
99 Delete user tokens when a new role is granted or revoked, in order to
100 prevent old tokens to continue to be valid for the original set of
101 roles for the remainder of the token's lifespan.
102
103 Addresses CVE-2012-4413.
104 Fixes bug 1041396.
105
106 Change-Id: Ib11b5b3a933c6000afe0c875c3f71f1f101bb202
107
108 keystone/identity/core.py | 7 ++++++-
109 keystone/token/core.py | 11 +++++++++++
110 tests/test_keystoneclient.py | 18 +++++++++---------
111 3 files changed, 26 insertions(+), 10 deletions(-)
112
113commit cd1e48a7d60497c528af6d311bd5048821dc1c07
114Author: Adam Young <ayoung@redhat.com>
115Date: Thu Sep 6 11:54:04 2012 -0400
116
117 List tokens for memcached backend
118
119 Creates and updates an index of tokens in a memcache entry keyed
120 by the user id
121
122 Bug 1046905
123
124 Change-Id: I114810297009331f491dc069d667f358092f1e34
125
126 keystone/token/backends/memcache.py | 23 +++++++++++++++++++-
127 tests/test_backend.py | 41 ++++++++++++++++++++++++++++++-----
128 tests/test_backend_memcache.py | 17 ++++++++++++---
129 3 files changed, 72 insertions(+), 9 deletions(-)
130
131commit 5438d3b5a219d7c8fa67e66e538d325a61617155
132Author: Dolph Mathews <dolph.mathews@gmail.com>
133Date: Thu Aug 23 07:39:20 2012 -0500
134
135 Require authz to update user's tenant (bug 1040626)
136
137 Change-Id: I82f80b84af2bc4db00b3dcb87a2ec338816a82e9
138
139 keystone/identity/core.py | 1 +
140 1 file changed, 1 insertion(+)
141
142commit a16a0ab997c3a406da2ccf0005534d5f9d81861f
143Merge: a130848 ff6df7c
144Author: Jenkins <jenkins@review.openstack.org>
145Date: Thu Aug 23 06:17:45 2012 +0000
146
147 Merge "Returning roles from authenticate in ldap backend" into stable/essex
148
149commit ff6df7cdbeaed6a8784955ba866332ec5f082ad5
150Author: Ryan Lane <rlane@wikimedia.org>
151Date: Thu Jul 26 11:41:16 2012 -0700
152
153 Returning roles from authenticate in ldap backend
154
155 Without this fix, the LDAP backend doesn't return
156 roles during the authentication phase.
157
158 lp 1035428
159
160 Change-Id: Ibd7e5a8f5475b56a4d3063c85ab634e4c0614e7e
161
162 AUTHORS | 1 +
163 keystone/identity/backends/ldap/core.py | 24 +++++++++++++++---------
164 tests/test_backend.py | 10 ++++++++++
165 3 files changed, 26 insertions(+), 9 deletions(-)
166
167commit a130848c71f1bc65dcf98c085dee0c4796748faa
168Author: Adam Young <ayoung@redhat.com>
169Date: Thu Jul 26 15:30:39 2012 -0400
170
171 Allow overloading of username and tenant name in the config files.
172
173 Includes documentation and sample config file values.
174
175 Bug 997700
176
177 Patchset adds DocImpact flag for notifying doc team about these new
178 config file values.
179
180 (cherry picked from commit 4f3dcb6c9b23867e6049f24c851b12904aee3b76)
181
182 Conflicts:
183
184 etc/keystone.conf.sample
185 keystone/config.py
186
187 Change-Id: I94a162be07c224c705333804a53910833df96b8e
188
189 doc/source/configuration.rst | 13 +++++++++++++
190 keystone/config.py | 2 ++
191 keystone/identity/backends/ldap/core.py | 2 ++
192 3 files changed, 17 insertions(+)
193
194commit 359c426f3009b6088efc364c035d104b089eb37a
195Author: Mark McLoughlin <markmc@redhat.com>
196Date: Fri Aug 10 06:54:48 2012 +0100
197
198 Open 2012.1.3 development
199
200 Bump version to 2012.1.3 to formally open development of the next
201 Essex stable update release.
202
203 See http://wiki.openstack.org/StableBranchRelease
204
205 Change-Id: Ie3a82ed9b26d25a83b284d57e3d58ab6f4c31b30
206
207 setup.py | 2 +-
208 1 file changed, 1 insertion(+), 1 deletion(-)
209
210commit afc37aeb10638807c9839fcc6f403b34029662a5
211Author: Mark McLoughlin <markmc@redhat.com>
212Date: Wed Aug 8 00:45:22 2012 +0100
213
214 Open 2012.1.2 development
215
216 Bump version to 2012.1.2 to formally open development of the next
217 Essex stable update release.
218
219 See http://wiki.openstack.org/StableBranchRelease
220
221 Change-Id: Id20de09f981f5389afbb9622ade9de7d4f3fd015
222
223 setup.py | 2 +-
224 1 file changed, 1 insertion(+), 1 deletion(-)
225
226commit f65604db7b504709fcb9aba2bcfd34a2aebffed3
227Merge: 46b3722 5373601
228Author: Jenkins <jenkins@review.openstack.org>
229Date: Tue Jul 31 10:31:57 2012 +0000
230
231 Merge "Raise unauthorized if tenant disabled (bug 988920)" into stable/essex
232
233commit 46b3722245283858017cf4df83e2e1ca2311211d
234Merge: d56a3fb 708c80e
235Author: Jenkins <jenkins@review.openstack.org>
236Date: Mon Jul 30 16:11:58 2012 +0000
237
238 Merge "fix variable names to coincide with the ones in common.ldap" into stable/essex
239
240commit 5373601bbdda10f879c08af1698852142b75f8d5
241Author: Dolph Mathews <dolph.mathews@gmail.com>
242Date: Mon Jul 16 16:08:32 2012 -0500
243
244 Raise unauthorized if tenant disabled (bug 988920)
245
246 If the client attempts to explicitly authenticate against a disabled
247 tenant, keystone should return HTTP 401 Unauthorized.
248
249 Change-Id: I49fe56b6ef8d9f2fc6b9357472dae8964bb9cb9c
250
251 keystone/service.py | 11 ++++++++++
252 tests/test_keystoneclient.py | 47 ++++++++++++++++++++++++++++++++++++++++++
253 2 files changed, 58 insertions(+)
254
255commit d56a3fb026268e87bdd54b862be388d69d5a1266
256Author: Dmitry Khovyakov <dkhovyakov@griddynamics.com>
257Date: Wed Jul 11 14:17:46 2012 +0300
258
259 Import ec2 credentials from old keystone db
260
261 Fix bug #1016056
262
263 Change-Id: Iebf31ccbdeff274b2c8f265911d3411963dd4844
264
265 AUTHORS | 1 +
266 keystone/common/sql/legacy.py | 19 +++++++++++++++++++
267 2 files changed, 20 insertions(+)
268
269commit 0b95c3cf66659a828de055b8d026c11e333cd8c8
270Author: J. Daniel Schmidt <jdsn@suse.de>
271Date: Thu Jul 12 11:22:33 2012 +0200
272
273 cleanup dependent data upon user/tenant deletion
274
275 fixes bug 974199
276 fixes bug 973243
277
278 * upon deletion of tenant also delete user tenant relations
279 * upon deletion of tenant or user also delete corresponding metadata
280 * add foreign keys in metadata to ensure consistency
281
282 see also: https://bugs.launchpad.net/keystone/+bug/959294/comments/16
283
284 Change-Id: I264714fe82b727e3e0f5273bcb781a580a3f3826
285
286 AUTHORS | 1 +
287 keystone/identity/backends/sql.py | 21 +++++++++++++++++++++
288 tests/test_backend_sql.py | 35 +++++++++++++++++++++++++++++++++++
289 3 files changed, 57 insertions(+)
290
291commit 708c80ea8e4ca1897b6815b559ad9437b36448ef
292Author: Ionuț Arțăriși <iartarisi@suse.cz>
293Date: Fri Jun 29 13:02:26 2012 +0200
294
295 fix variable names to coincide with the ones in common.ldap
296
297 Change-Id: I148d8d9b0a67b8c45d06227829d0105935216c4d
298
299 keystone/identity/backends/ldap/core.py | 6 +++---
300 1 file changed, 3 insertions(+), 3 deletions(-)
301
302commit f1762e6d81be38fc6f9b3e12735a868896ce931d
303Merge: d111d54 14b136a
304Author: Jenkins <jenkins@review.openstack.org>
305Date: Thu Jul 5 16:04:40 2012 +0000
306
307 Merge "Require authz for user role list (bug 1006815)" into stable/essex
308
309commit d111d548767bfed1d2c892e7bb443155c166fdc5
310Merge: 1428278 24df3ad
311Author: Jenkins <jenkins@review.openstack.org>
312Date: Thu Jul 5 15:43:54 2012 +0000
313
314 Merge "Require authz for service CRUD (bug 1006822)" into stable/essex
315
316commit 1428278b6202b7cb285f9e1bb278f894c05d31b0
317Merge: d8dbdbc 707b725
318Author: Jenkins <jenkins@review.openstack.org>
319Date: Thu Jun 28 14:16:31 2012 +0000
320
321 Merge "Set defaultbranch in .gitreview to stable/essex" into stable/essex
322
323commit d8dbdbced061fa4a4e42ec33c4b7e7752b0ebc04
324Author: Rafael Durán Castañeda <rafadurancastaneda@gmail.com>
325Date: Tue Jun 19 20:35:43 2012 +0200
326
327 Monkey patching 'thread'.
328
329 Fixes bug 1012381.
330
331 Change-Id: Icb7b2372df96d647fc6dcd4c4ebe72c8aa607f9d
332
333 AUTHORS | 1 +
334 keystone/common/wsgi.py | 2 +-
335 2 files changed, 2 insertions(+), 1 deletion(-)
336
337commit 14b136aed9d988f5a8f3e699bd4577c9b874d6c1
338Author: Dolph Mathews <dolph.mathews@gmail.com>
339Date: Sun Jun 3 12:24:07 2012 -0500
340
341 Require authz for user role list (bug 1006815)
342
343 Change-Id: I65f25dcca3e265f44746930917434b45e64de15e
344
345 keystone/identity/core.py | 1 +
346 tests/test_content_types.py | 11 +++++++++++
347 2 files changed, 12 insertions(+)
348
349commit 24df3adb3f50cbb5ada411bc67aba8a781e6a431
350Author: Dolph Mathews <dolph.mathews@gmail.com>
351Date: Sun Jun 3 11:00:54 2012 -0500
352
353 Require authz for service CRUD (bug 1006822)
354
355 Change-Id: Ia90f0aa2b856b9a9874d4865fb92ee913e8125c5
356
357 keystone/catalog/core.py | 7 +++++++
358 tests/test_content_types.py | 33 +++++++++++++++++++++++++++++++++
359 2 files changed, 40 insertions(+)
360
361commit 707b7259f9772e5f498990297c65b68116bdc3c1
362Author: Mark McLoughlin <markmc@redhat.com>
363Date: Fri Jun 22 21:16:26 2012 +0100
364
365 Set defaultbranch in .gitreview to stable/essex
366
367 This allows people run git-review without any arguments.
368
369 Change-Id: I3f1c7ce22cbe40ed34f084fd3dbc0941ba787bcf
370
371 .gitreview | 2 ++
372 1 file changed, 2 insertions(+)
373
374commit 29e74e73a6e51cffc0371b32354558391826a4aa
375Author: Derek Higgins <derekh@redhat.com>
376Date: Tue Jun 5 09:33:53 2012 +0100
377
378 Carrying over token expiry time when token chaining
379
380 Fixes bug #998185
381
382 This commit causes the token expiry time to be maintained when
383 one token is being created from another
384
385 Change-Id: I7b61692a60d9227423b93c267864a5abe939ca33
386
387 keystone/service.py | 3 ++-
388 tests/test_keystoneclient.py | 12 ++++++++++++
389 2 files changed, 14 insertions(+), 1 deletion(-)
390
391commit 9a841f3ba93d5a0bd1f56cc897415258ed6cf877
392Merge: 35d5ebd d960043
393Author: Jenkins <jenkins@review.openstack.org>
394Date: Thu Jun 14 19:56:21 2012 +0000
395
396 Merge "Invalidate user tokens when a user is disabled" into stable/essex
397
398commit 35d5ebd54e02e4b79515e882506f0a518548d273
399Merge: 9695b86 ea03d05
400Author: Jenkins <jenkins@review.openstack.org>
401Date: Thu Jun 14 16:58:30 2012 +0000
402
403 Merge "Invalidate user tokens when password is changed" into stable/essex
404
405commit 9695b8681801f3624b8f40dc06797aa171b5f30d
406Merge: 0dcfe7e f70505c
407Author: Jenkins <jenkins@review.openstack.org>
408Date: Thu Jun 14 16:15:39 2012 +0000
409
410 Merge "Fix expired token tests" into stable/essex
411
412commit 0dcfe7ec2df5a45271847914997cbba92fdda330
413Merge: 18513c3 4265499
414Author: Jenkins <jenkins@review.openstack.org>
415Date: Thu Jun 14 15:42:01 2012 +0000
416
417 Merge "Corrects url conversion in export_legacy_catalog" into stable/essex
418
419commit d9600434da14976463a0bd03abd8e0309f0db454
420Author: Derek Higgins <derekh@redhat.com>
421Date: Fri May 11 13:42:43 2012 +0100
422
423 Invalidate user tokens when a user is disabled
424
425 Fixes Bug 997194
426
427 Delete valid tokens for a user when they have been disabled
428
429 Moved logic to delete tokens into update_user, as this can be called
430 directly form the REST API.
431
432 Also checks if a user is enabled when creating a token from another
433 token, this helps in cases there the backend didn't support listing of
434 tokens (and as a result weren't deleted)
435
436 Change-Id: Ib5ed73a7873bfa66ef31bf6d0f0322f50e677688
437
438 keystone/identity/core.py | 22 ++++++++++++----------
439 keystone/service.py | 14 +++++++++++++-
440 tests/test_keystoneclient.py | 21 +++++++++++++++++++--
441 3 files changed, 44 insertions(+), 13 deletions(-)
442
443commit ea03d05ed5de0c015042876100d37a6a14bf56de
444Author: Derek Higgins <derekh@redhat.com>
445Date: Wed May 9 15:55:46 2012 +0100
446
447 Invalidate user tokens when password is changed
448
449 Fixes bug 996595
450
451 This commit will cause all valid tokens to be deleted for a user
452 who's password is changed (implemented for the sql and kvs backends)
453
454 Change-Id: I6ad7da8957b7041983a3fc91d9ba9368667d06ac
455
456 AUTHORS | 1 +
457 keystone/identity/core.py | 14 +++++++++++++-
458 keystone/token/backends/kvs.py | 15 +++++++++++++++
459 keystone/token/backends/sql.py | 14 ++++++++++++++
460 keystone/token/core.py | 10 ++++++++++
461 tests/test_keystoneclient.py | 23 +++++++++++++++++++++++
462 6 files changed, 76 insertions(+), 1 deletion(-)
463
464commit 18513c36e63ee2da417f1125cfa05ea9d525b6ee
465Author: Mark McLoughlin <markmc@redhat.com>
466Date: Thu Jun 14 10:59:33 2012 +0100
467
468 Open 2012.1.1 development
469
470 Bump version to 2012.1.1 to formally open development of the next
471 Essex stable update release.
472
473 See http://wiki.openstack.org/StableBranchRelease
474
475 Change-Id: I845e8abca87751bbe4ebfa9414add247f2afdc1f
476
477 setup.py | 2 +-
478 1 file changed, 1 insertion(+), 1 deletion(-)
479
480commit f70505ced12ae7319dedaf75bedb964c7469c6dd
481Author: Mark McLoughlin <markmc@redhat.com>
482Date: Tue Apr 10 13:35:30 2012 +0100
483
484 Fix expired token tests
485
486 Fixes bug #983800
487
488 The expiration timestamps are expressed in UTC time, so ensure:
489
490 1) The timestamp of the token created by the test is UTC time (i.e.
491 utcnow() vs now())
492
493 2) The expiration check in the dummy memcache client properly
494 accounts for UTC (i.e. utctimetuple() vs timetuple())
495
496 Change-Id: Ie7356456f79ab5a8070a79771bb7d210b1cedd47
497
498 tests/test_backend.py | 2 +-
499 tests/test_backend_memcache.py | 2 +-
500 2 files changed, 2 insertions(+), 2 deletions(-)
501
502commit aa7e7b96e7bd05819c899906091b9121385dc125
503Author: Dan Prince <dprince@redhat.com>
504Date: Wed Apr 11 10:57:56 2012 -0400
505
506 Add ChangeLog to tarball.
507
508 Fixes LP Bug #978981.
509
510 Change-Id: I5b98df88673422cfc39c471fd77eecd77fa0cf2c
511
512 MANIFEST.in | 1 +
513 1 file changed, 1 insertion(+)
514
515commit d0a73669369d86ff4c7b9de715fa4eec9bc58b59
516Author: Adam Gandelman <adamg@canonical.com>
517Date: Mon Jun 11 10:35:16 2012 -0700
518
519 Flush tenant membership deletion before user
520
521 Ensure user tenant membership is *actually* removed before deleting
522 user.
523
524 Applied to 'stable/essex', originally committed to trunk via
525 https://review.openstack.org/#/c/7353/
526
527 Fixes bug 998137.
528
529 Change-Id: Ib52970d68f288b8742c3e060c7040838a1c738c2
530
531 keystone/identity/backends/sql.py | 1 +
532 1 file changed, 1 insertion(+)
533
534commit 426549934e323a9bc435b9ec58163e88f5e74a32
535Author: Sam Morrison <sorrison@gmail.com>
536Date: Mon May 7 09:09:57 2012 +1000
537
538 Corrects url conversion in export_legacy_catalog
539
540 Fixes bug 994936
541
542 Change-Id: Ia63fdae7d0bcd7f8b0b587da588404765e22fb8f
543
544 AUTHORS | 1 +
545 keystone/common/sql/legacy.py | 2 +-
546 tests/test_import_legacy.py | 2 +-
547 3 files changed, 3 insertions(+), 2 deletions(-)
548
549commit 7715d6cd72477af83d95563b69a5f0273bdb719b
550Author: Alan Pevec <apevec@redhat.com>
551Date: Mon Jun 11 20:19:50 2012 +0200
552
553 Fix test env for the stable branch
554
555 Need both changes in one commit to pass the gate!
556
557 * Nail pep8 dependencies to 1.0.1.
558
559 Nails the pep8 deps for tox and test-requires to 1.0.1.
560 Fixes an issues causing pep8 failures due to a new pep8 release.
561
562 (cherry picked from Nova stable)
563
564 * Switch to 1000 rounds during unit tests
565
566 Fixes bug 992918
567
568 passlib 1.6 introduced a minimum number of rounds for sha512_crypt. As
569 a result, increase the rounds used during testing to the minimum
570
571 Change-Id: Ic0c635e92b4f13180a047904a6efa490ab599012
572
573 tests/test_overrides.conf | 2 +-
574 tools/test-requires | 2 +-
575 tox.ini | 2 +-
576 3 files changed, 3 insertions(+), 3 deletions(-)
577
578commit aff45d69a73033241531f5e3542a8d1782ddd859
579Author: Mark McLoughlin <markmc@redhat.com>
580Date: Fri Mar 30 12:17:48 2012 +0100
581
582 Make import_nova_auth only create roles which don't already exist
583
584 Fixes bug #969088
585
586 If a role already exists, there's no particular need for import_nova_auth
587 to barf. Instead, we should just use the existing role.
588
589 Change-Id: I18ae38af62b4c2b2423e20e436611fc30f844ae1
590
591 keystone/common/sql/nova.py | 5 ++++-
592 tests/test_migrate_nova_auth.py | 9 +++++++++
593 2 files changed, 13 insertions(+), 1 deletion(-)
594
595commit 7d08d12cea96910145f05499ba7d124603d7c4f6
596Author: Adam Gandelman <adamg@canonical.com>
597Date: Mon Apr 2 14:21:43 2012 -0700
598
599 Remove tenant membership during user deletion
600
601 Remove users' tenant membership on user deletion. Resolves a FK constraint
602 issue that previously went unnoticed due to testing against database
603 configurations that do not support FK constraints (MyISAM).
604
605 Fixes LP bug 959294.
606
607 Update: * Move tenant membership cleanup to the sql identity backend
608 * Add a test case to test_backend_sql
609
610 Change-Id: Ib4f5da03033f7886b36d1ab3b8b4ac37f08b2e0e
611
612 keystone/identity/backends/sql.py | 8 ++++++++
613 tests/test_backend_sql.py | 11 +++++++++++
614 2 files changed, 19 insertions(+)
615
616commit aa542c420aa283968a0154a29038ec0bb1be9326
617Author: Chmouel Boudjnah <chmouel@chmouel.com>
618Date: Mon Apr 2 17:15:47 2012 +0200
619
620 Add a _ at the end of reseller_prefix default.
621
622 - Fixes bug 971592.
623
624 Change-Id: Ic9edb2b8b0043413e4ec16de9c669646ae4230a6
625
626 keystone/middleware/swift_auth.py | 11 ++++++++++-
627 1 file changed, 10 insertions(+), 1 deletion(-)
628
629commit 0a0513d9fb1b84d5b998ff47088aee7f121dc794
630Merge: a05daf5 89e8dc0
631Author: Jenkins <jenkins@review.openstack.org>
632Date: Tue Apr 3 19:39:43 2012 +0000
633
634 Merge "Add support to swift_auth for tokenless authz" into milestone-proposed
635
636commit a05daf5f53fbf0084e0f19ed4a8b686ff60bcb90
637Merge: bc153d5 4314ae6
638Author: Jenkins <jenkins@review.openstack.org>
639Date: Tue Apr 3 19:29:19 2012 +0000
640
641 Merge "additional logging to support debugging auth issue" into milestone-proposed
642
643commit 89e8dc075151acc85d8c4f8972d3910c7f33bd25
644Author: Maru Newby <mnewby@internap.com>
645Date: Tue Mar 20 22:19:36 2012 -0700
646
647 Add support to swift_auth for tokenless authz
648
649 * Updates keystone.middleware.swift_auth to allow token-less
650 (unauthenticated) access for container sync (bug 954030) and
651 permitted referrers (bug 924578).
652
653 Change-Id: Ieccf458c44dfe55f546dc15c79704800dad59ac0
654
655 doc/source/configuringservices.rst | 3 +
656 keystone/middleware/swift_auth.py | 106 +++++++++++++++++++++++++----------
657 tests/test_swift_auth_middleware.py | 56 +++++++++---------
658 3 files changed, 104 insertions(+), 61 deletions(-)
659
660commit 4314ae6c038b96c080dfd13938678e358e5574e7
661Author: Joe Heck <heckj@mac.com>
662Date: Fri Mar 30 22:04:16 2012 -0700
663
664 additional logging to support debugging auth issue
665
666 fixes bug 969801
667
668 Change-Id: Iaf752e5f3692c91030cfd8575114f2c3293d1dba
669
670 keystone/middleware/auth_token.py | 8 +++++++-
671 1 file changed, 7 insertions(+), 1 deletion(-)
672
673commit bc153d5ad9b32737dd55c33fd12468e89189eded
674Author: Maru Newby <mnewby@internap.com>
675Date: Mon Mar 26 16:08:56 2012 -0700
676
677 Fixed misc errors in configuration.rst
678
679 * Addresses bug 965788
680
681 Change-Id: I5aa276589a9818c7f523e6da9531af363139adbb
682
683 doc/source/configuration.rst | 10 ++++++----
684 1 file changed, 6 insertions(+), 4 deletions(-)
685
686commit ada402155acf5bda83d1b0fbedfbb0d7e4144b58
687Author: termie <github@anarkystic.com>
688Date: Thu Mar 29 16:03:17 2012 -0700
689
690 don't duplicate the extra dict in extra
691
692 fixes bug 929815
693
694 Change-Id: Icfbe9a4b0eb2ef9b24bcf41113a6ec8e636210a9
695
696 keystone/catalog/backends/sql.py | 4 ++--
697 keystone/identity/backends/sql.py | 4 ++--
698 2 files changed, 4 insertions(+), 4 deletions(-)
699
700commit 1b7aa15ae425e68c15588ba738e9b701b62d995a
701Author: Dolph Mathews <dolph.mathews@gmail.com>
702Date: Tue Mar 27 10:57:04 2012 -0700
703
704 Raise keystone.exception for HTTP 401 (bug 962563)
705
706 Change-Id: I22e3b6769c69ef5917028980007d3295fed99fb7
707
708 keystone/contrib/s3/core.py | 3 ++-
709 1 file changed, 2 insertions(+), 1 deletion(-)
710
711commit b1336b0a3921621741ff8ba2adbc44113357e175
712Author: Dolph Mathews <dolph.mathews@gmail.com>
713Date: Fri Mar 23 10:46:16 2012 -0500
714
715 Validate object refs (return 404 instead of 500)
716
717 Combined fix for bug 963056:
718 user-crud 404
719 service-crud 404
720 ec2-credential-crud 404
721 user-role-crud 404
722 endpoint-crud 404
723
724 Change-Id: I7762aaaae9817ea7426039e4700e16b59e18cba1
725
726 keystone/catalog/core.py | 5 +-
727 keystone/contrib/ec2/core.py | 2 +
728 keystone/exception.py | 2 +-
729 keystone/identity/backends/kvs.py | 4 +
730 keystone/identity/backends/sql.py | 4 +
731 keystone/identity/core.py | 26 +++++-
732 tests/test_keystoneclient.py | 175 +++++++++++++++++++++++++++++++++++++
733 tests/test_keystoneclient_sql.py | 7 ++
734 8 files changed, 222 insertions(+), 3 deletions(-)
735
736commit 80afa04f6e031207e6a7003843852b37c81eacc6
737Merge: f745dae d9959d8
738Author: Jenkins <jenkins@review.openstack.org>
739Date: Tue Apr 3 14:45:36 2012 +0000
740
741 Merge "tenant-crud 404 (bug 963056)" into milestone-proposed
742
743commit f745dae9a6d9c68140476daa8403d0efc09826ab
744Merge: 8037722 b56e326
745Author: Jenkins <jenkins@review.openstack.org>
746Date: Tue Apr 3 13:30:07 2012 +0000
747
748 Merge "role-crud 404 (bug 963056)" into milestone-proposed
749
750commit d9959d85a759b4acdff52c25f20a9462d66b185d
751Author: Dolph Mathews <dolph.mathews@gmail.com>
752Date: Fri Mar 23 10:23:06 2012 -0500
753
754 tenant-crud 404 (bug 963056)
755
756 tenant-get
757 tenant-update
758 tenant-delete
759
760 Change-Id: I9e67cea985f546c9ddf6ce6d82a11486099bd524
761
762 keystone/identity/core.py | 10 +++++++++-
763 tests/test_keystoneclient.py | 21 +++++++++++++++++++++
764 2 files changed, 30 insertions(+), 1 deletion(-)
765
766commit b56e32645fa88cd21f4b5289cfb68d51fcbf740c
767Author: Dolph Mathews <dolph.mathews@gmail.com>
768Date: Fri Mar 23 09:10:59 2012 -0500
769
770 role-crud 404 (bug 963056)
771
772 role-get
773 role-delete
774 role-list
775
776 Change-Id: I099b1e1e5bd2cd77a2ea3b72fb0f14b88a3af26e
777
778 keystone/identity/backends/kvs.py | 3 +--
779 keystone/identity/backends/sql.py | 3 +--
780 keystone/identity/core.py | 13 ++++++++++--
781 tests/test_keystoneclient.py | 41 +++++++++++++++++++++++++++++++++++--
782 4 files changed, 52 insertions(+), 8 deletions(-)
783
784commit 8037722264668d9b66326cdfac25f6cf84d2b7d4
785Author: Maru Newby <mnewby@internap.com>
786Date: Tue Mar 20 18:47:19 2012 -0700
787
788 Improve swift_auth test coverage + Minor fixes
789
790 * Isolates authorize() tests from wsgi tests
791 * Adds coverage for authorize()
792 * Adds support for a blank reseller_prefix
793 * Adds swift_auth test dependencies to tools/test-requires
794 * Cleans up authorize()'s use of tenant_id/tenant_name
795 (addresses bug 963546)
796
797 Change-Id: I603b89ab4fe8559b0f5d72528afd659ee0f0bce1
798
799 AUTHORS | 1 +
800 keystone/middleware/swift_auth.py | 18 +--
801 tests/test_swift_auth_middleware.py | 281 ++++++++++++++++++-----------------
802 tools/test-requires | 4 +
803 4 files changed, 158 insertions(+), 146 deletions(-)
804
805commit f3ce326a8c9ab85f60145e6a198e061fd9ccf431
806Merge: 7abe0aa 1904228
807Author: Jenkins <jenkins@review.openstack.org>
808Date: Fri Mar 23 17:59:24 2012 +0000
809
810 Merge "Check values for EC2."
811
812commit 7abe0aa3845459b95a7d4e401e51d4ab8c4c0280
813Author: Chmouel Boudjnah <chmouel@chmouel.com>
814Date: Wed Mar 21 16:59:15 2012 +0000
815
816 S3 tokens cleanups.
817
818 - Cleanups.
819 - Remove reference about config admin_username/password/token.
820 - Return proper http error on errors.
821 - Add unittests (skip them for now when swift is not installed).
822 - Fixes bug 956983.
823
824 Change-Id: I392fc274f3b01a5a0b5779dd13f9cd3b819ee65a
825
826 doc/source/configuringservices.rst | 6 +-
827 keystone/middleware/s3_token.py | 124 ++++++++++++++++++++++------------
828 tests/test_s3_token_middleware.py | 130 ++++++++++++++++++++++++++++++++++++
829 3 files changed, 213 insertions(+), 47 deletions(-)
830
831commit 1904228a5a3fef549c5b9294eba5c39f9f6f72bd
832Author: Chmouel Boudjnah <chmouel@chmouel.com>
833Date: Thu Mar 22 21:34:39 2012 +0000
834
835 Check values for EC2.
836
837 - Add multiple check to methods to make sure we have a proper
838 tenant_id/user_id/credentials.
839 - Fixes bug 958135.
840
841 Change-Id: I4dd171e3db32d6ebdc70bb1a83492c8ecd09c21c
842
843 keystone/contrib/ec2/core.py | 61 +++++++++++++++++++++++++++++++++++++-----
844 1 file changed, 55 insertions(+), 6 deletions(-)
845
846commit 9feb00085f75ea2697fd2225e6003c2384904d08
847Author: Dolph Mathews <dolph.mathews@gmail.com>
848Date: Wed Mar 21 13:11:31 2012 -0500
849
850 Fix critical typo in endpoint_create (bug 961412)
851
852 It looks like catalog crud was previously untested.
853
854 Change-Id: I8e3060b6d6c737d3d97a5bd9076e9a5fdf9945e2
855
856 keystone/catalog/core.py | 2 +-
857 tests/test_keystoneclient_sql.py | 43 ++++++++++++++++++++++++++++++++++++++
858 2 files changed, 44 insertions(+), 1 deletion(-)
859