Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 880 lines (734 sloc) 34.118 kB
419c2cb @termie initial
termie authored
1 # vim: tabstop=4 shiftwidth=4 softtabstop=4
2
a606c39 @termie rename many service parts to public
termie authored
3 # this is the web public frontend that emulates keystone
75e781a @termie remove keystone from names, remove service
termie authored
4 import json
c6d6d43 @termie get tenant_add_and_remove_user test working
termie authored
5 import urllib
6 import urlparse
82f6445 @termie make create_tenant work for keystone api
termie authored
7 import uuid
63c7934 @termie get some tests working again
termie authored
8
7427b1a @termie refactor keystone compat and add catalog service
termie authored
9 import routes
75e781a @termie remove keystone from names, remove service
termie authored
10 import webob.dec
11 import webob.exc
7427b1a @termie refactor keystone compat and add catalog service
termie authored
12
763013c @heckj renaming keystonelight to keystone
heckj authored
13 from keystone import catalog
14 from keystone import identity
75e781a @termie remove keystone from names, remove service
termie authored
15 from keystone import logging
763013c @heckj renaming keystonelight to keystone
heckj authored
16 from keystone import policy
17 from keystone import token
75e781a @termie remove keystone from names, remove service
termie authored
18 from keystone import utils
763013c @heckj renaming keystonelight to keystone
heckj authored
19 from keystone import wsgi
419c2cb @termie initial
termie authored
20
9a0ec99 @termie rudimentary login working
termie authored
21
75e781a @termie remove keystone from names, remove service
termie authored
22 class Application(wsgi.Application):
23 @webob.dec.wsgify
24 def __call__(self, req):
25 arg_dict = req.environ['wsgiorg.routing_args'][1]
26 action = arg_dict['action']
27 del arg_dict['action']
28 del arg_dict['controller']
29 logging.debug('arg_dict: %s', arg_dict)
30
31 context = req.environ.get('openstack.context', {})
32 # allow middleware up the stack to override the params
33 params = {}
34 if 'openstack.params' in req.environ:
35 params = req.environ['openstack.params']
36 params.update(arg_dict)
37
38 # TODO(termie): do some basic normalization on methods
39 method = getattr(self, action)
40
41 # NOTE(vish): make sure we have no unicode keys for py2.6.
42 params = self._normalize_dict(params)
43 result = method(context, **params)
44
45 if result is None or type(result) is str or type(result) is unicode:
46 return result
47 elif isinstance(result, webob.exc.WSGIHTTPException):
48 return result
49
50 return self._serialize(result)
51
52 def _serialize(self, result):
53 return json.dumps(result, cls=utils.SmarterEncoder)
54
55 def _normalize_arg(self, arg):
56 return str(arg).replace(':', '_').replace('-', '_')
57
58 def _normalize_dict(self, d):
59 return dict([(self._normalize_arg(k), v)
60 for (k, v) in d.iteritems()])
61
62 def assert_admin(self, context):
63 if not context['is_admin']:
64 user_token_ref = self.token_api.get_token(
65 context=context, token_id=context['token_id'])
66 creds = user_token_ref['metadata'].copy()
67 creds['user_id'] = user_token_ref['user'].get('id')
68 creds['tenant_id'] = user_token_ref['tenant'].get('id')
69 print creds
70 # Accept either is_admin or the admin role
71 assert self.policy_api.can_haz(context,
72 ('is_admin:1', 'roles:admin'),
73 creds)
74
75
76 class AdminRouter(wsgi.Router):
feadf75 @termie config system overhaul
termie authored
77 def __init__(self):
7427b1a @termie refactor keystone compat and add catalog service
termie authored
78 mapper = routes.Mapper()
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
79
80 # Token Operations
75e781a @termie remove keystone from names, remove service
termie authored
81 auth_controller = TokenController()
9d99821 @termie adjust paths and use composite apps
termie authored
82 mapper.connect('/tokens',
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
83 controller=auth_controller,
7427b1a @termie refactor keystone compat and add catalog service
termie authored
84 action='authenticate',
85 conditions=dict(method=['POST']))
9d99821 @termie adjust paths and use composite apps
termie authored
86 mapper.connect('/tokens/{token_id}',
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
87 controller=auth_controller,
7427b1a @termie refactor keystone compat and add catalog service
termie authored
88 action='validate_token',
89 conditions=dict(method=['GET']))
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
90 mapper.connect('/tokens/{token_id}/endpoints',
91 controller=auth_controller,
92 action='endpoints',
93 conditions=dict(method=['GET']))
94
95 # Tenant Operations
75e781a @termie remove keystone from names, remove service
termie authored
96 tenant_controller = TenantController()
9d99821 @termie adjust paths and use composite apps
termie authored
97 mapper.connect('/tenants',
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
98 controller=tenant_controller,
99 action='get_tenants_for_token',
100 conditions=dict(method=['GET']))
101 mapper.connect('/tenants/{tenant_id}',
102 controller=tenant_controller,
103 action='get_tenant',
7427b1a @termie refactor keystone compat and add catalog service
termie authored
104 conditions=dict(method=['GET']))
105
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
106 # User Operations
75e781a @termie remove keystone from names, remove service
termie authored
107 user_controller = UserController()
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
108 mapper.connect('/users/{user_id}',
109 controller=user_controller,
110 action='get_user',
111 conditions=dict(method=['GET']))
112
113 # Role Operations
75e781a @termie remove keystone from names, remove service
termie authored
114 roles_controller = RoleController()
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
115 mapper.connect('/tenants/{tenant_id}/users/{user_id}/roles',
116 controller=roles_controller,
117 action='get_user_roles',
118 conditions=dict(method=['GET']))
119 mapper.connect('/users/{user_id}/roles',
120 controller=user_controller,
121 action='get_user_roles',
122 conditions=dict(method=['GET']))
7427b1a @termie refactor keystone compat and add catalog service
termie authored
123
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
124 # Miscellaneous Operations
75e781a @termie remove keystone from names, remove service
termie authored
125 version_controller = VersionController()
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
126 mapper.connect('/',
127 controller=version_controller,
128 action='get_version_info', module='admin/version',
129 conditions=dict(method=['GET']))
130
75e781a @termie remove keystone from names, remove service
termie authored
131 extensions_controller = ExtensionsController()
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
132 mapper.connect('/extensions',
133 controller=extensions_controller,
134 action='get_extensions_info',
135 conditions=dict(method=['GET']))
136
75e781a @termie remove keystone from names, remove service
termie authored
137 super(AdminRouter, self).__init__(mapper)
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
138
139
a606c39 @termie rename many service parts to public
termie authored
140 class PublicRouter(wsgi.Router):
feadf75 @termie config system overhaul
termie authored
141 def __init__(self):
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
142 mapper = routes.Mapper()
143
2723439 @termie add a noop controller
termie authored
144 noop_controller = NoopController()
145 mapper.connect('/',
146 controller=noop_controller,
147 action='noop')
148
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
149 # Token Operations
75e781a @termie remove keystone from names, remove service
termie authored
150 auth_controller = TokenController()
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
151 mapper.connect('/tokens',
152 controller=auth_controller,
153 action='authenticate',
154 conditions=dict(method=['POST']))
155 mapper.connect('/ec2tokens',
156 controller=auth_controller,
157 action='authenticate_ec2',
f2a9c51 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
158 conditions=dict(methods=['POST']))
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
159
2fb294f @devcamcar All tests but create_tenant pass
devcamcar authored
160 # Tenant Operations
75e781a @termie remove keystone from names, remove service
termie authored
161 tenant_controller = TenantController()
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
162 mapper.connect('/tenants',
163 controller=tenant_controller,
164 action='get_tenants_for_token',
f2a9c51 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
165 conditions=dict(methods=['GET']))
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
166
167 # Miscellaneous
75e781a @termie remove keystone from names, remove service
termie authored
168 version_controller = VersionController()
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
169 mapper.connect('/',
170 controller=version_controller,
171 action='get_version_info',
172 module='service/version',
173 conditions=dict(method=['GET']))
174
75e781a @termie remove keystone from names, remove service
termie authored
175 extensions_controller = ExtensionsController()
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
176 mapper.connect('/extensions',
177 controller=extensions_controller,
178 action='get_extensions_info',
179 conditions=dict(method=['GET']))
180
a606c39 @termie rename many service parts to public
termie authored
181 super(PublicRouter, self).__init__(mapper)
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
182
183
75e781a @termie remove keystone from names, remove service
termie authored
184 class AdminCrudExtension(wsgi.ExtensionRouter):
e396650 @termie copy over the os-ksadm extension
termie authored
185 """Previously known as the OS-KSADM extension.
186
187 Provides a bunch of CRUD operations for internal data types.
188
189 """
190
feadf75 @termie config system overhaul
termie authored
191 def __init__(self, application):
23c6f49 @termie example crud extension for create_tenant
termie authored
192 mapper = routes.Mapper()
75e781a @termie remove keystone from names, remove service
termie authored
193 tenant_controller = TenantController()
194 user_controller = UserController()
195 role_controller = RoleController()
196 service_controller = ServiceController()
e396650 @termie copy over the os-ksadm extension
termie authored
197
198 # Tenant Operations
199 mapper.connect("/tenants", controller=tenant_controller,
200 action="create_tenant",
201 conditions=dict(method=["POST"]))
202 mapper.connect("/tenants/{tenant_id}",
203 controller=tenant_controller,
94e9d6b @termie tenant test working again
termie authored
204 action="update_tenant",
205 conditions=dict(method=["PUT"]))
e396650 @termie copy over the os-ksadm extension
termie authored
206 mapper.connect("/tenants/{tenant_id}",
207 controller=tenant_controller,
94e9d6b @termie tenant test working again
termie authored
208 action="delete_tenant",
209 conditions=dict(method=["DELETE"]))
e396650 @termie copy over the os-ksadm extension
termie authored
210 mapper.connect("/tenants/{tenant_id}/users",
211 controller=user_controller,
212 action="get_tenant_users",
213 conditions=dict(method=["GET"]))
214
215 # User Operations
216 mapper.connect("/users",
217 controller=user_controller,
218 action="get_users",
219 conditions=dict(method=["GET"]))
220 mapper.connect("/users",
221 controller=user_controller,
222 action="create_user",
223 conditions=dict(method=["POST"]))
46943c5 @termie get user tests working
termie authored
224 # NOTE(termie): not in diablo
e396650 @termie copy over the os-ksadm extension
termie authored
225 mapper.connect("/users/{user_id}",
226 controller=user_controller,
227 action="update_user",
94e9d6b @termie tenant test working again
termie authored
228 conditions=dict(method=["PUT"]))
e396650 @termie copy over the os-ksadm extension
termie authored
229 mapper.connect("/users/{user_id}",
230 controller=user_controller,
231 action="delete_user",
232 conditions=dict(method=["DELETE"]))
233
46943c5 @termie get user tests working
termie authored
234 # COMPAT(diablo): the copy with no OS-KSADM is from diablo
235 mapper.connect("/users/{user_id}/password",
236 controller=user_controller,
237 action="set_user_password",
238 conditions=dict(method=["PUT"]))
239 mapper.connect("/users/{user_id}/OS-KSADM/password",
240 controller=user_controller,
241 action="set_user_password",
242 conditions=dict(method=["PUT"]))
243
244 # COMPAT(diablo): the copy with no OS-KSADM is from diablo
245 mapper.connect("/users/{user_id}/tenant",
246 controller=user_controller,
247 action="update_user_tenant",
248 conditions=dict(method=["PUT"]))
249 mapper.connect("/users/{user_id}/OS-KSADM/tenant",
250 controller=user_controller,
251 action="update_user_tenant",
252 conditions=dict(method=["PUT"]))
253
254 # COMPAT(diablo): the copy with no OS-KSADM is from diablo
255 mapper.connect("/users/{user_id}/enabled",
256 controller=user_controller,
257 action="set_user_enabled",
258 conditions=dict(method=["PUT"]))
259 mapper.connect("/users/{user_id}/OS-KSADM/enabled",
260 controller=user_controller,
261 action="set_user_enabled",
262 conditions=dict(method=["PUT"]))
e396650 @termie copy over the os-ksadm extension
termie authored
263
264 # User Roles
265 mapper.connect("/users/{user_id}/roles/OS-KSADM/{role_id}",
94e9d6b @termie tenant test working again
termie authored
266 controller=role_controller, action="add_role_to_user",
e396650 @termie copy over the os-ksadm extension
termie authored
267 conditions=dict(method=["PUT"]))
268 mapper.connect("/users/{user_id}/roles/OS-KSADM/{role_id}",
94e9d6b @termie tenant test working again
termie authored
269 controller=role_controller, action="delete_role_from_user",
e396650 @termie copy over the os-ksadm extension
termie authored
270 conditions=dict(method=["DELETE"]))
271
c6d6d43 @termie get tenant_add_and_remove_user test working
termie authored
272 # COMPAT(diablo): User Roles
273 mapper.connect("/users/{user_id}/roleRefs",
274 controller=role_controller, action="get_role_refs",
275 conditions=dict(method=["GET"]))
276 mapper.connect("/users/{user_id}/roleRefs",
277 controller=role_controller, action="create_role_ref",
278 conditions=dict(method=["POST"]))
279 mapper.connect("/users/{user_id}/roleRefs/{role_ref_id}",
280 controller=role_controller, action="delete_role_ref",
281 conditions=dict(method=["DELETE"]))
282
e396650 @termie copy over the os-ksadm extension
termie authored
283 # User-Tenant Roles
284 mapper.connect(
285 "/tenants/{tenant_id}/users/{user_id}/roles/OS-KSADM/{role_id}",
94e9d6b @termie tenant test working again
termie authored
286 controller=role_controller, action="add_role_to_user",
e396650 @termie copy over the os-ksadm extension
termie authored
287 conditions=dict(method=["PUT"]))
288 mapper.connect(
289 "/tenants/{tenant_id}/users/{user_id}/roles/OS-KSADM/{role_id}",
94e9d6b @termie tenant test working again
termie authored
290 controller=role_controller, action="delete_role_from_user",
e396650 @termie copy over the os-ksadm extension
termie authored
291 conditions=dict(method=["DELETE"]))
292
293 # Service Operations
294 mapper.connect("/OS-KSADM/services",
ebe158f @termie add the various role tests
termie authored
295 controller=service_controller,
296 action="get_services",
297 conditions=dict(method=["GET"]))
e396650 @termie copy over the os-ksadm extension
termie authored
298 mapper.connect("/OS-KSADM/services",
ebe158f @termie add the various role tests
termie authored
299 controller=service_controller,
300 action="create_service",
301 conditions=dict(method=["POST"]))
e396650 @termie copy over the os-ksadm extension
termie authored
302 mapper.connect("/OS-KSADM/services/{service_id}",
ebe158f @termie add the various role tests
termie authored
303 controller=service_controller,
304 action="delete_service",
305 conditions=dict(method=["DELETE"]))
e396650 @termie copy over the os-ksadm extension
termie authored
306 mapper.connect("/OS-KSADM/services/{service_id}",
ebe158f @termie add the various role tests
termie authored
307 controller=service_controller,
308 action="get_service",
309 conditions=dict(method=["GET"]))
e396650 @termie copy over the os-ksadm extension
termie authored
310
311 # Role Operations
ebe158f @termie add the various role tests
termie authored
312 mapper.connect("/OS-KSADM/roles",
313 controller=role_controller,
314 action="create_role",
315 conditions=dict(method=["POST"]))
316 mapper.connect("/OS-KSADM/roles",
317 controller=role_controller,
318 action="get_roles",
319 conditions=dict(method=["GET"]))
e396650 @termie copy over the os-ksadm extension
termie authored
320 mapper.connect("/OS-KSADM/roles/{role_id}",
ebe158f @termie add the various role tests
termie authored
321 controller=role_controller,
322 action="get_role",
323 conditions=dict(method=["GET"]))
e396650 @termie copy over the os-ksadm extension
termie authored
324 mapper.connect("/OS-KSADM/roles/{role_id}",
ebe158f @termie add the various role tests
termie authored
325 controller=role_controller,
326 action="delete_role",
327 conditions=dict(method=["DELETE"]))
e396650 @termie copy over the os-ksadm extension
termie authored
328
75e781a @termie remove keystone from names, remove service
termie authored
329 super(AdminCrudExtension, self).__init__(
feadf75 @termie config system overhaul
termie authored
330 application, mapper)
23c6f49 @termie example crud extension for create_tenant
termie authored
331
332
2723439 @termie add a noop controller
termie authored
333 class NoopController(Application):
334 def __init__(self):
335 super(NoopController, self).__init__()
336
337 def noop(self, context):
338 return {}
339
340
75e781a @termie remove keystone from names, remove service
termie authored
341 class TokenController(Application):
feadf75 @termie config system overhaul
termie authored
342 def __init__(self):
343 self.catalog_api = catalog.Manager()
344 self.identity_api = identity.Manager()
345 self.token_api = token.Manager()
346 self.policy_api = policy.Manager()
75e781a @termie remove keystone from names, remove service
termie authored
347 super(TokenController, self).__init__()
cd712b2 @termie add a default handler for /
termie authored
348
7427b1a @termie refactor keystone compat and add catalog service
termie authored
349 def authenticate(self, context, auth=None):
350 """Authenticate credentials and return a token.
351
75e781a @termie remove keystone from names, remove service
termie authored
352 Accept auth as a dict that looks like:
7427b1a @termie refactor keystone compat and add catalog service
termie authored
353
354 {
355 "auth":{
356 "passwordCredentials":{
357 "username":"test_user",
358 "password":"mypass"
359 },
360 "tenantName":"customer-x"
361 }
362 }
363
364 In this case, tenant is optional, if not provided the token will be
365 considered "unscoped" and can later be used to get a scoped token.
366
367 Alternatively, this call accepts auth with only a token and tenant
368 that will return a token that is scoped to that tenant.
369 """
370
371 if 'passwordCredentials' in auth:
372 username = auth['passwordCredentials'].get('username', '')
373 password = auth['passwordCredentials'].get('password', '')
2ac753e @termie everything but the catalog
termie authored
374 tenant_name = auth.get('tenantName', None)
375
776a159 @termie users require a name
termie authored
376 if username:
377 user_ref = self.identity_api.get_user_by_name(
378 context=context, user_name=username)
379 user_id = user_ref['id']
380 else:
381 user_id = auth['passwordCredentials'].get('userId', None)
382
2ac753e @termie everything but the catalog
termie authored
383 # more compat
384 if tenant_name:
4ba33be @termie add templated catalog backend
termie authored
385 tenant_ref = self.identity_api.get_tenant_by_name(
386 context=context, tenant_name=tenant_name)
387 tenant_id = tenant_ref['id']
2ac753e @termie everything but the catalog
termie authored
388 else:
389 tenant_id = auth.get('tenantId', None)
7427b1a @termie refactor keystone compat and add catalog service
termie authored
390
2340dee @termie rename extras to metadata
termie authored
391 (user_ref, tenant_ref, metadata_ref) = \
06944e8 @termie add context to calls
termie authored
392 self.identity_api.authenticate(context=context,
776a159 @termie users require a name
termie authored
393 user_id=user_id,
7427b1a @termie refactor keystone compat and add catalog service
termie authored
394 password=password,
2ac753e @termie everything but the catalog
termie authored
395 tenant_id=tenant_id)
2340dee @termie rename extras to metadata
termie authored
396 token_ref = self.token_api.create_token(
397 context, dict(expires='',
398 user=user_ref,
399 tenant=tenant_ref,
400 metadata=metadata_ref))
aaf7695 @termie handle unscoped requests
termie authored
401 if tenant_ref:
402 catalog_ref = self.catalog_api.get_catalog(
403 context=context,
404 user_id=user_ref['id'],
405 tenant_id=tenant_ref['id'],
2340dee @termie rename extras to metadata
termie authored
406 metadata=metadata_ref)
aaf7695 @termie handle unscoped requests
termie authored
407 else:
408 catalog_ref = {}
7427b1a @termie refactor keystone compat and add catalog service
termie authored
409
2f2465e @termie working authenticate in keystoneclient
termie authored
410 elif 'token' in auth:
411 token = auth['token'].get('id', None)
412
413 tenant_name = auth.get('tenantName')
414
415 # more compat
416 if tenant_name:
417 tenant_ref = self.identity_api.get_tenant_by_name(
418 context=context, tenant_name=tenant_name)
419 tenant_id = tenant_ref['id']
420 else:
421 tenant_id = auth.get('tenantId', None)
7427b1a @termie refactor keystone compat and add catalog service
termie authored
422
06944e8 @termie add context to calls
termie authored
423 old_token_ref = self.token_api.get_token(context=context,
424 token_id=token)
7427b1a @termie refactor keystone compat and add catalog service
termie authored
425 user_ref = old_token_ref['user']
426
aea09bd @termie fix token auth
termie authored
427 tenants = self.identity_api.get_tenants_for_user(context,
428 user_ref['id'])
1bd1349 @termie add a couple more tests
termie authored
429 if tenant_id:
430 assert tenant_id in tenants
7427b1a @termie refactor keystone compat and add catalog service
termie authored
431
06944e8 @termie add context to calls
termie authored
432 tenant_ref = self.identity_api.get_tenant(context=context,
2ac753e @termie everything but the catalog
termie authored
433 tenant_id=tenant_id)
1bd1349 @termie add a couple more tests
termie authored
434 if tenant_ref:
435 metadata_ref = self.identity_api.get_metadata(
436 context=context,
437 user_id=user_ref['id'],
438 tenant_id=tenant_ref['id'])
439 catalog_ref = self.catalog_api.get_catalog(
440 context=context,
441 user_id=user_ref['id'],
442 tenant_id=tenant_ref['id'],
443 metadata=metadata_ref)
444 else:
445 metadata_ref = {}
446 catalog_ref = {}
447
2340dee @termie rename extras to metadata
termie authored
448 token_ref = self.token_api.create_token(
449 context, dict(expires='',
450 user=user_ref,
451 tenant=tenant_ref,
452 metadata=metadata_ref))
7427b1a @termie refactor keystone compat and add catalog service
termie authored
453
2e1558e @termie clean up keystoneclient setup
termie authored
454 # TODO(termie): optimize this call at some point and put it into the
2340dee @termie rename extras to metadata
termie authored
455 # the return for metadata
456 # fill out the roles in the metadata
2e1558e @termie clean up keystoneclient setup
termie authored
457 roles_ref = []
2340dee @termie rename extras to metadata
termie authored
458 for role_id in metadata_ref.get('roles', []):
2e1558e @termie clean up keystoneclient setup
termie authored
459 roles_ref.append(self.identity_api.get_role(context, role_id))
63c7934 @termie get some tests working again
termie authored
460 logging.debug('TOKEN_REF %s', token_ref)
2e1558e @termie clean up keystoneclient setup
termie authored
461 return self._format_authenticate(token_ref, roles_ref, catalog_ref)
7427b1a @termie refactor keystone compat and add catalog service
termie authored
462
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
463 def authenticate_ec2(self, context):
464 raise NotImplemented()
465
466 # admin only
6c84c1b @termie reorg
termie authored
467 def validate_token(self, context, token_id, belongs_to=None):
468 """Check that a token is valid.
469
470 Optionally, also ensure that it is owned by a specific tenant.
471
472 """
860aa86 @termie add the policy code
termie authored
473 # TODO(termie): this stuff should probably be moved to middleware
2d6b348 @termie add role refs to validate token
termie authored
474 self.assert_admin(context)
6c84c1b @termie reorg
termie authored
475
476 token_ref = self.token_api.get_token(context=context,
477 token_id=token_id)
478 if belongs_to:
479 assert token_ref['tenant']['id'] == belongs_to
2d6b348 @termie add role refs to validate token
termie authored
480
481 # TODO(termie): optimize this call at some point and put it into the
482 # the return for metadata
483 # fill out the roles in the metadata
484 metadata_ref = token_ref['metadata']
485 roles_ref = []
486 for role_id in metadata_ref.get('roles', []):
487 roles_ref.append(self.identity_api.get_role(context, role_id))
488 return self._format_token(token_ref, roles_ref)
6c84c1b @termie reorg
termie authored
489
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
490 def endpoints(self, context, token_id):
491 """Return service catalog endpoints."""
6c84c1b @termie reorg
termie authored
492 token_ref = self.token_api.get_token(context=context,
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
493 token_id=token_id)
494 catalog_ref = self.catalog_api.get_catalog(context,
ff15e5f @termie get endpoints test working
termie authored
495 token_ref['user']['id'],
496 token_ref['tenant']['id'])
497 return {'token': {'serviceCatalog': self._format_catalog(catalog_ref)}}
82f6445 @termie make create_tenant work for keystone api
termie authored
498
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
499 def _format_authenticate(self, token_ref, roles_ref, catalog_ref):
500 o = self._format_token(token_ref, roles_ref)
501 o['access']['serviceCatalog'] = self._format_catalog(catalog_ref)
63c7934 @termie get some tests working again
termie authored
502 return o
82f6445 @termie make create_tenant work for keystone api
termie authored
503
2e1558e @termie clean up keystoneclient setup
termie authored
504 def _format_token(self, token_ref, roles_ref):
6c84c1b @termie reorg
termie authored
505 user_ref = token_ref['user']
2340dee @termie rename extras to metadata
termie authored
506 metadata_ref = token_ref['metadata']
6c84c1b @termie reorg
termie authored
507 o = {'access': {'token': {'id': token_ref['id'],
508 'expires': token_ref['expires']
509 },
510 'user': {'id': user_ref['id'],
511 'name': user_ref['name'],
3479575 @termie updates to make compatible with middleware
termie authored
512 'username': user_ref['name'],
513 'roles': roles_ref,
2340dee @termie rename extras to metadata
termie authored
514 'roles_links': metadata_ref.get('roles_links',
aaf7695 @termie handle unscoped requests
termie authored
515 [])
6c84c1b @termie reorg
termie authored
516 }
517 }
518 }
aaf7695 @termie handle unscoped requests
termie authored
519 if 'tenant' in token_ref and token_ref['tenant']:
3479575 @termie updates to make compatible with middleware
termie authored
520 token_ref['tenant']['enabled'] = True
6c84c1b @termie reorg
termie authored
521 o['access']['token']['tenant'] = token_ref['tenant']
522 return o
523
3caf2a8 @termie remove test_keystone_compat's catalog tests
termie authored
524 def _format_catalog(self, catalog_ref):
75e781a @termie remove keystone from names, remove service
termie authored
525 """Munge catalogs from internal to output format
526 Internal catalogs look like:
3caf2a8 @termie remove test_keystone_compat's catalog tests
termie authored
527
528 {$REGION: {
529 {$SERVICE: {
530 $key1: $value1,
531 ...
532 }
533 }
534 }
535
75e781a @termie remove keystone from names, remove service
termie authored
536 The legacy api wants them to look like
3caf2a8 @termie remove test_keystone_compat's catalog tests
termie authored
537
538 [{'name': $SERVICE[name],
539 'type': $SERVICE,
540 'endpoints': [{
541 'tenantId': $tenant_id,
542 ...
543 'region': $REGION,
544 }],
545 'endpoints_links': [],
546 }]
547
548 """
549 if not catalog_ref:
550 return {}
551
552 services = {}
553 for region, region_ref in catalog_ref.iteritems():
554 for service, service_ref in region_ref.iteritems():
555 new_service_ref = services.get(service, {})
2f2465e @termie working authenticate in keystoneclient
termie authored
556 new_service_ref['name'] = service_ref.pop('name')
557 new_service_ref['type'] = service
558 new_service_ref['endpoints_links'] = []
559 service_ref['region'] = region
560
561 endpoints_ref = new_service_ref.get('endpoints', [])
562 endpoints_ref.append(service_ref)
3caf2a8 @termie remove test_keystone_compat's catalog tests
termie authored
563
2f2465e @termie working authenticate in keystoneclient
termie authored
564 new_service_ref['endpoints'] = endpoints_ref
565 services[service] = new_service_ref
3caf2a8 @termie remove test_keystone_compat's catalog tests
termie authored
566
2f2465e @termie working authenticate in keystoneclient
termie authored
567 return services.values()
3caf2a8 @termie remove test_keystone_compat's catalog tests
termie authored
568
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
569
75e781a @termie remove keystone from names, remove service
termie authored
570 class TenantController(Application):
feadf75 @termie config system overhaul
termie authored
571 def __init__(self):
572 self.identity_api = identity.Manager()
573 self.policy_api = policy.Manager()
574 self.token_api = token.Manager()
75e781a @termie remove keystone from names, remove service
termie authored
575 super(TenantController, self).__init__()
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
576
2fb294f @devcamcar All tests but create_tenant pass
devcamcar authored
577 def get_tenants_for_token(self, context, **kw):
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
578 """Get valid tenants for token based on token used to authenticate.
579
580 Pulls the token from the context, validates it and gets the valid
581 tenants for the user in the token.
582
583 Doesn't care about token scopedness.
584
585 """
586 token_ref = self.token_api.get_token(context=context,
587 token_id=context['token_id'])
588 assert token_ref is not None
589
590 user_ref = token_ref['user']
13ec79b @termie keystoneclient tests working against sql backend
termie authored
591 tenant_ids = self.identity_api.get_tenants_for_user(
592 context, user_ref['id'])
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
593 tenant_refs = []
13ec79b @termie keystoneclient tests working against sql backend
termie authored
594 for tenant_id in tenant_ids:
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
595 tenant_refs.append(self.identity_api.get_tenant(
596 context=context,
597 tenant_id=tenant_id))
598 return self._format_tenants_for_token(tenant_refs)
599
600 def get_tenant(self, context, tenant_id):
601 # TODO(termie): this stuff should probably be moved to middleware
602 if not context['is_admin']:
603 user_token_ref = self.token_api.get_token(
604 context=context, token_id=context['token_id'])
2340dee @termie rename extras to metadata
termie authored
605 creds = user_token_ref['metadata'].copy()
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
606 creds['user_id'] = user_token_ref['user'].get('id')
607 creds['tenant_id'] = user_token_ref['tenant'].get('id')
608 # Accept either is_admin or the admin role
609 assert self.policy_api.can_haz(context,
610 ('is_admin:1', 'roles:admin'),
611 creds)
612
613 tenant = self.identity_api.get_tenant(context, tenant_id)
94e9d6b @termie tenant test working again
termie authored
614 if not tenant:
75e781a @termie remove keystone from names, remove service
termie authored
615 return webob.exc.HTTPNotFound()
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
616 return {'tenant': tenant}
617
94e9d6b @termie tenant test working again
termie authored
618 # CRUD Extension
13ec79b @termie keystoneclient tests working against sql backend
termie authored
619 def create_tenant(self, context, tenant):
620 tenant_ref = self._normalize_dict(tenant)
94e9d6b @termie tenant test working again
termie authored
621 self.assert_admin(context)
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
622 tenant_id = (tenant_ref.get('id')
623 and tenant_ref.get('id')
624 or uuid.uuid4().hex)
625 tenant_ref['id'] = tenant_id
626
627 tenant = self.identity_api.create_tenant(
628 context, tenant_id=tenant_id, data=tenant_ref)
629 return {'tenant': tenant}
630
94e9d6b @termie tenant test working again
termie authored
631 def update_tenant(self, context, tenant_id, tenant):
632 self.assert_admin(context)
633 tenant_ref = self.identity_api.update_tenant(
634 context, tenant_id=tenant_id, data=tenant)
635 return {'tenant': tenant_ref}
636
637 def delete_tenant(self, context, tenant_id, **kw):
638 self.assert_admin(context)
639 self.identity_api.delete_tenant(context, tenant_id=tenant_id)
640
641 def get_tenant_users(self, context, **kw):
642 self.assert_admin(context)
c6d6d43 @termie get tenant_add_and_remove_user test working
termie authored
643 raise NotImplementedError()
94e9d6b @termie tenant test working again
termie authored
644
7427b1a @termie refactor keystone compat and add catalog service
termie authored
645 def _format_tenants_for_token(self, tenant_refs):
3479575 @termie updates to make compatible with middleware
termie authored
646 for x in tenant_refs:
647 x['enabled'] = True
ba4913f @termie base tests on keystone-diablo/stable
termie authored
648 o = {'tenants': tenant_refs,
649 'tenants_links': []}
a98b2ed @termie get tenants passing, yay
termie authored
650 return o
419c2cb @termie initial
termie authored
651
35ec297 @termie tests running through, still failing
termie authored
652
75e781a @termie remove keystone from names, remove service
termie authored
653 class UserController(Application):
feadf75 @termie config system overhaul
termie authored
654 def __init__(self):
655 self.catalog_api = catalog.Manager()
656 self.identity_api = identity.Manager()
657 self.policy_api = policy.Manager()
658 self.token_api = token.Manager()
75e781a @termie remove keystone from names, remove service
termie authored
659 super(UserController, self).__init__()
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
660
661 def get_user(self, context, user_id):
46943c5 @termie get user tests working
termie authored
662 self.assert_admin(context)
663 user_ref = self.identity_api.get_user(context, user_id)
664 if not user_ref:
75e781a @termie remove keystone from names, remove service
termie authored
665 raise webob.exc.HTTPNotFound()
46943c5 @termie get user tests working
termie authored
666 return {'user': user_ref}
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
667
5c89972 @termie add list users
termie authored
668 def get_users(self, context):
669 # NOTE(termie): i can't imagine that this really wants all the data
670 # about every single user in the system...
671 self.assert_admin(context)
13ec79b @termie keystoneclient tests working against sql backend
termie authored
672 user_refs = self.identity_api.list_users(context)
673 return {'users': user_refs}
5c89972 @termie add list users
termie authored
674
46943c5 @termie get user tests working
termie authored
675 # CRUD extension
676 def create_user(self, context, user):
13ec79b @termie keystoneclient tests working against sql backend
termie authored
677 user = self._normalize_dict(user)
46943c5 @termie get user tests working
termie authored
678 self.assert_admin(context)
13ec79b @termie keystoneclient tests working against sql backend
termie authored
679 tenant_id = user.get('tenantId', None)
46943c5 @termie get user tests working
termie authored
680 user_id = uuid.uuid4().hex
681 user_ref = user.copy()
682 user_ref['id'] = user_id
683 new_user_ref = self.identity_api.create_user(
684 context, user_id, user_ref)
13ec79b @termie keystoneclient tests working against sql backend
termie authored
685 if tenant_id:
686 self.identity_api.add_user_to_tenant(tenant_id, user_id)
46943c5 @termie get user tests working
termie authored
687 return {'user': new_user_ref}
688
689 # NOTE(termie): this is really more of a patch than a put
690 def update_user(self, context, user_id, user):
691 self.assert_admin(context)
692 user_ref = self.identity_api.get_user(context, user_id)
693 del user['id']
694 user_ref.update(user)
695 self.identity_api.update_user(context, user_id, user_ref)
696 return {'user': user_ref}
697
698 def delete_user(self, context, user_id):
699 self.assert_admin(context)
700 self.identity_api.delete_user(context, user_id)
701
702 def set_user_enabled(self, context, user_id, user):
703 return self.update_user(context, user_id, user)
704
705 def set_user_password(self, context, user_id, user):
706 return self.update_user(context, user_id, user)
707
708 def update_user_tenant(self, context, user_id, user):
709 """Update the default tenant."""
710 # ensure that we're a member of that tenant
711 tenant_id = user.get('tenantId')
712 self.identity_api.add_user_to_tenant(context, tenant_id, user_id)
713 return self.update_user(context, user_id, user)
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
714
715
75e781a @termie remove keystone from names, remove service
termie authored
716 class RoleController(Application):
feadf75 @termie config system overhaul
termie authored
717 def __init__(self):
718 self.catalog_api = catalog.Manager()
719 self.identity_api = identity.Manager()
720 self.token_api = token.Manager()
721 self.policy_api = policy.Manager()
75e781a @termie remove keystone from names, remove service
termie authored
722 super(RoleController, self).__init__()
e396650 @termie copy over the os-ksadm extension
termie authored
723
724 def get_user_roles(self, context, user_id, tenant_id=None):
725 raise NotImplemented()
726
ebe158f @termie add the various role tests
termie authored
727 # CRUD extension
728 def get_role(self, context, role_id):
729 self.assert_admin(context)
730 role_ref = self.identity_api.get_role(context, role_id)
731 if not role_ref:
75e781a @termie remove keystone from names, remove service
termie authored
732 raise webob.exc.HTTPNotFound()
ebe158f @termie add the various role tests
termie authored
733 return {'role': role_ref}
734
735 def create_role(self, context, role):
13ec79b @termie keystoneclient tests working against sql backend
termie authored
736 role = self._normalize_dict(role)
737 self.assert_admin(context)
ebe158f @termie add the various role tests
termie authored
738 role_id = uuid.uuid4().hex
739 role['id'] = role_id
740 role_ref = self.identity_api.create_role(context, role_id, role)
741 return {'role': role_ref}
742
743 def delete_role(self, context, role_id):
744 self.assert_admin(context)
745 role_ref = self.identity_api.delete_role(context, role_id)
746
747 def get_roles(self, context):
748 self.assert_admin(context)
749 roles = self.identity_api.list_roles(context)
750 # TODO(termie): probably inefficient at some point
13ec79b @termie keystoneclient tests working against sql backend
termie authored
751 return {'roles': roles}
ebe158f @termie add the various role tests
termie authored
752
c6d6d43 @termie get tenant_add_and_remove_user test working
termie authored
753 # COMPAT(diablo): CRUD extension
754 def get_role_refs(self, context, user_id):
755 """Ultimate hack to get around having to make role_refs first-class.
756
757 This will basically iterate over the various roles the user has in
758 all tenants the user is a member of and create fake role_refs where
759 the id encodes the user-tenant-role information so we can look
760 up the appropriate data when we need to delete them.
761
762 """
763 self.assert_admin(context)
764 user_ref = self.identity_api.get_user(context, user_id)
765 tenant_ids = self.identity_api.get_tenants_for_user(context, user_id)
766 o = []
767 for tenant_id in tenant_ids:
768 role_ids = self.identity_api.get_roles_for_user_and_tenant(
769 context, user_id, tenant_id)
770 for role_id in role_ids:
771 ref = {'roleId': role_id,
772 'tenantId': tenant_id,
773 'userId': user_id}
774 ref['id'] = urllib.urlencode(ref)
775 o.append(ref)
776 return {'roles': o}
777
778 def create_role_ref(self, context, user_id, role):
779 """This is actually used for adding a user to a tenant.
780
781 In the legacy data model adding a user to a tenant required setting
782 a role.
783
784 """
785 self.assert_admin(context)
786 # TODO(termie): for now we're ignoring the actual role
787 tenant_id = role.get('tenantId')
788 role_id = role.get('roleId')
789 self.identity_api.add_user_to_tenant(context, tenant_id, user_id)
790 self.identity_api.add_role_to_user_and_tenant(
791 context, user_id, tenant_id, role_id)
792 role_ref = self.identity_api.get_role(context, role_id)
793 return {'role': role_ref}
794
795 def delete_role_ref(self, context, user_id, role_ref_id):
796 """This is actually used for deleting a user from a tenant.
797
798 In the legacy data model removing a user from a tenant required
799 deleting a role.
800
801 To emulate this, we encode the tenant and role in the role_ref_id,
802 and if this happens to be the last role for the user-tenant pair,
803 we remove the user from the tenant.
804
805 """
806 self.assert_admin(context)
807 # TODO(termie): for now we're ignoring the actual role
808 role_ref_ref = urlparse.parse_qs(role_ref_id)
809 tenant_id = role_ref_ref.get('tenantId')[0]
810 role_id = role_ref_ref.get('roleId')[0]
811 self.identity_api.remove_role_from_user_and_tenant(
812 context, user_id, tenant_id, role_id)
813 roles = self.identity_api.get_roles_for_user_and_tenant(
814 context, user_id, tenant_id)
815 if not roles:
816 self.identity_api.remove_user_from_tenant(
817 context, tenant_id, user_id)
818
819
75e781a @termie remove keystone from names, remove service
termie authored
820 class ServiceController(Application):
feadf75 @termie config system overhaul
termie authored
821 def __init__(self):
822 self.catalog_api = catalog.Manager()
823 self.identity_api = identity.Manager()
824 self.token_api = token.Manager()
825 self.policy_api = policy.Manager()
75e781a @termie remove keystone from names, remove service
termie authored
826 super(ServiceController, self).__init__()
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
827
205a7b9 @termie finished up services stuff
termie authored
828 # CRUD extensions
a606c39 @termie rename many service parts to public
termie authored
829 # NOTE(termie): this OS-KSADM stuff is not very consistent
205a7b9 @termie finished up services stuff
termie authored
830 def get_services(self, context):
831 service_list = self.catalog_api.list_services(context)
832 service_refs = [self.catalog_api.get_service(context, x)
833 for x in service_list]
834 return {'OS-KSADM:services': service_refs}
835
836 def get_service(self, context, service_id):
837 service_ref = self.catalog_api.get_service(context, service_id)
838 if not service_ref:
75e781a @termie remove keystone from names, remove service
termie authored
839 raise webob.exc.HTTPNotFound()
205a7b9 @termie finished up services stuff
termie authored
840 return {'OS-KSADM:service': service_ref}
841
842 def delete_service(self, context, service_id):
843 service_ref = self.catalog_api.delete_service(context, service_id)
844
845 def create_service(self, context, OS_KSADM_service):
846 service_id = uuid.uuid4().hex
847 service_ref = OS_KSADM_service.copy()
848 service_ref['id'] = service_id
849 new_service_ref = self.catalog_api.create_service(
850 context, service_id, service_ref)
851 return {'OS-KSADM:service': new_service_ref}
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
852
853
75e781a @termie remove keystone from names, remove service
termie authored
854 class VersionController(Application):
feadf75 @termie config system overhaul
termie authored
855 def __init__(self):
75e781a @termie remove keystone from names, remove service
termie authored
856 super(VersionController, self).__init__()
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
857
858 def get_version_info(self, context, module='version'):
859 raise NotImplemented()
860
861
75e781a @termie remove keystone from names, remove service
termie authored
862 class ExtensionsController(Application):
feadf75 @termie config system overhaul
termie authored
863 def __init__(self):
75e781a @termie remove keystone from names, remove service
termie authored
864 super(ExtensionsController, self).__init__()
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
865
866 def get_extensions_info(self, context):
867 raise NotImplemented()
868
869
a606c39 @termie rename many service parts to public
termie authored
870 def public_app_factory(global_conf, **local_conf):
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
871 conf = global_conf.copy()
872 conf.update(local_conf)
a606c39 @termie rename many service parts to public
termie authored
873 return PublicRouter()
4b55fa5 @devcamcar Split keystone compat by admin and service endpoints
devcamcar authored
874
875
876 def admin_app_factory(global_conf, **local_conf):
7427b1a @termie refactor keystone compat and add catalog service
termie authored
877 conf = global_conf.copy()
878 conf.update(local_conf)
75e781a @termie remove keystone from names, remove service
termie authored
879 return AdminRouter()
Something went wrong with that request. Please try again.