Merge lp:~gandelman-a/keystone/pkg_changes_03062011 into lp:~ubuntu-server-dev/keystone/essex

Proposed by Adam Gandelman
Status: Merged
Merge reported by: Chuck Short
Merged at revision: not available
Proposed branch: lp:~gandelman-a/keystone/pkg_changes_03062011
Merge into: lp:~ubuntu-server-dev/keystone/essex
Diff against target: 786 lines (+9/-748)
4 files modified
debian/changelog (+8/-0)
debian/patches/keystone-auth.patch (+0/-746)
debian/patches/series (+0/-1)
debian/patches/sql_connection.patch (+1/-1)
To merge this branch: bzr merge lp:~gandelman-a/keystone/pkg_changes_03062011
Reviewer Review Type Date Requested Status
Ubuntu Server Developers Pending
Review via email: mp+96283@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2012-03-03 01:38:46 +0000
3+++ debian/changelog 2012-03-07 02:13:21 +0000
4@@ -1,3 +1,11 @@
5+keystone (2012.1~e4-0ubuntu3) UNRELEASED; urgency=low
6+
7+ * debian/patches/keystone-auth.patch: Drop, applied upstream at commit
8+ 29337e66.
9+ * debian/patches/sql_connection.patch: Refresh
10+
11+ -- Adam Gandelman <adamg@canonical.com> Tue, 06 Mar 2012 16:13:37 -0800
12+
13 keystone (2012.1~e4-0ubuntu2) precise; urgency=low
14
15 * debian/keystone.preinst: Create group before creating user (LP: #945299)
16
17=== removed file 'debian/patches/keystone-auth.patch'
18--- debian/patches/keystone-auth.patch 2012-03-02 14:54:39 +0000
19+++ debian/patches/keystone-auth.patch 1970-01-01 00:00:00 +0000
20@@ -1,746 +0,0 @@
21-Description: Backport improvements to auth_token middleware.
22-Author: Chuck Short <zulcss@ubuntu.com>
23-
24-diff -Naurp keystone-2012.1.orig/keystone/middleware/auth_token.py keystone-2012.1/keystone/middleware/auth_token.py
25---- keystone-2012.1.orig/keystone/middleware/auth_token.py 2012-02-29 05:16:06.000000000 -0500
26-+++ keystone-2012.1/keystone/middleware/auth_token.py 2012-03-02 09:44:16.498651385 -0500
27-@@ -18,18 +18,17 @@
28- """
29- TOKEN-BASED AUTH MIDDLEWARE
30-
31--This WSGI component performs multiple jobs:
32-+This WSGI component:
33-
34--* it verifies that incoming client requests have valid tokens by verifying
35-+* Verifies that incoming client requests have valid tokens by validating
36- tokens with the auth service.
37--* it will reject unauthenticated requests UNLESS it is in 'delay_auth_decision'
38-+* Rejects unauthenticated requests UNLESS it is in 'delay_auth_decision'
39- mode, which means the final decision is delegated to the downstream WSGI
40- component (usually the OpenStack service)
41--* it will collect and forward identity information from a valid token
42-- such as user name etc...
43--
44--Refer to: http://wiki.openstack.org/openstack-authn
45-+* Collects and forwards identity information based on a valid token
46-+ such as user name, tenant, etc
47-
48-+Refer to: http://keystone.openstack.org/middleware_architecture.html
49-
50- HEADERS
51- -------
52-@@ -41,17 +40,18 @@ Coming in from initial call from client
53- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
54-
55- HTTP_X_AUTH_TOKEN
56-- the client token being passed in
57-+ The client token being passed in.
58-
59- HTTP_X_STORAGE_TOKEN
60-- the client token being passed in (legacy Rackspace use) to support
61-- cloud files
62-+ The client token being passed in (legacy Rackspace use) to support
63-+ swift/cloud files
64-
65- Used for communication between components
66- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
67-
68--www-authenticate
69-- only used if this component is being used remotely
70-+WWW-Authenticate
71-+ HTTP header returned to a user indicating which endpoint to use
72-+ to retrieve a new token
73-
74- HTTP_AUTHORIZATION
75- basic auth password used to validate the connection
76-@@ -60,368 +60,370 @@ What we add to the request for use by th
77- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
78-
79- HTTP_X_AUTHORIZATION
80-- the client identity being passed in
81-+ The client identity being passed in
82-+
83-+HTTP_X_IDENTITY_STATUS
84-+ 'Confirmed' or 'Invalid'
85-+ The underlying service will only see a value of 'Invalid' if the Middleware
86-+ is configured to run in 'delay_auth_decision' mode
87-+
88-+HTTP_X_TENANT_ID
89-+ Identity service managed unique identifier, string
90-+
91-+HTTP_X_TENANT_NAME
92-+ Unique tenant identifier, string
93-+
94-+HTTP_X_USER_ID
95-+ Identity-service managed unique identifier, string
96-+
97-+HTTP_X_USER_NAME
98-+ Unique user identifier, string
99-+
100-+HTTP_X_ROLES
101-+ Comma delimited list of case-sensitive Roles
102-+
103-+HTTP_X_TENANT
104-+ *Deprecated* in favor of HTTP_X_TENANT_ID and HTTP_X_TENANT_NAME
105-+ Keystone-assigned unique identifier, deprecated
106-+
107-+HTTP_X_USER
108-+ *Deprecated* in favor of HTTP_X_USER_ID and HTTP_X_USER_NAME
109-+ Unique user name, string
110-+
111-+HTTP_X_ROLE
112-+ *Deprecated* in favor of HTTP_X_ROLES
113-+ This is being renamed, and the new header contains the same data.
114-
115- """
116-+
117- import httplib
118- import json
119--import os
120-+import logging
121-
122--import eventlet
123--from eventlet import wsgi
124--from paste import deploy
125--from urlparse import urlparse
126- import webob
127- import webob.exc
128--from webob.exc import HTTPUnauthorized
129-
130--from keystone.common.bufferedhttp import http_connect_raw as http_connect
131-
132--ADMIN_TENANTNAME = 'admin'
133--PROTOCOL_NAME = 'Token Authentication'
134-+logger = logging.getLogger('keystone.middleware.auth_token')
135-
136-
137--class AuthProtocol(object):
138-- """Auth Middleware that handles authenticating client calls"""
139-+class InvalidUserToken(Exception):
140-+ pass
141-+
142-+
143-+class ServiceError(Exception):
144-+ pass
145-
146-- def _init_protocol_common(self, app, conf):
147-- """ Common initialization code"""
148-- print 'Starting the %s component' % PROTOCOL_NAME
149-
150-+class AuthProtocol(object):
151-+ """Auth Middleware that handles authenticating client calls."""
152-+
153-+ def __init__(self, app, conf):
154-+ logger.info('Starting keystone auth_token middleware')
155- self.conf = conf
156- self.app = app
157-- #if app is set, then we are in a WSGI pipeline and requests get passed
158-- # on to app. If it is not set, this component should forward requests
159--
160-- # where to find the OpenStack service (if not in local WSGI chain)
161-- # these settings are only used if this component is acting as a proxy
162-- # and the OpenSTack service is running remotely
163-- self.service_protocol = conf.get('service_protocol', 'https')
164-- self.service_host = conf.get('service_host')
165-- self.service_port = int(conf.get('service_port'))
166-- self.service_url = '%s://%s:%s' % (self.service_protocol,
167-- self.service_host,
168-- self.service_port)
169-- # used to verify this component with the OpenStack service or PAPIAuth
170-- self.service_pass = conf.get('service_pass')
171-
172- # delay_auth_decision means we still allow unauthenticated requests
173- # through and we let the downstream service make the final decision
174- self.delay_auth_decision = int(conf.get('delay_auth_decision', 0))
175-
176-- def _init_protocol(self, conf):
177-- """ Protocol specific initialization """
178--
179- # where to find the auth service (we use this to validate tokens)
180- self.auth_host = conf.get('auth_host')
181- self.auth_port = int(conf.get('auth_port'))
182-- self.auth_protocol = conf.get('auth_protocol', 'https')
183-
184-- # where to tell clients to find the auth service (default to url
185-- # constructed based on endpoint we have for the service to use)
186-- self.auth_location = conf.get('auth_uri',
187-- '%s://%s:%s' % (self.auth_protocol,
188-- self.auth_host,
189-- self.auth_port))
190-+ auth_protocol = conf.get('auth_protocol', 'https')
191-+ if auth_protocol == 'http':
192-+ self.http_client_class = httplib.HTTPConnection
193-+ else:
194-+ self.http_client_class = httplib.HTTPSConnection
195-+
196-+ default_auth_uri = '%s://%s:%s' % (auth_protocol,
197-+ self.auth_host,
198-+ self.auth_port)
199-+ self.auth_uri = conf.get('auth_uri', default_auth_uri)
200-
201- # Credentials used to verify this component with the Auth service since
202- # validating tokens is a privileged call
203- self.admin_token = conf.get('admin_token')
204- self.admin_user = conf.get('admin_user')
205- self.admin_password = conf.get('admin_password')
206-+ self.admin_tenant_name = conf.get('admin_tenant_name', 'admin')
207-
208-- def __init__(self, app, conf):
209-- """ Common initialization code """
210-+ def __call__(self, env, start_response):
211-+ """Handle incoming request.
212-
213-- #TODO(ziad): maybe we refactor this into a superclass
214-- self._init_protocol_common(app, conf) # Applies to all protocols
215-- self._init_protocol(conf) # Specific to this protocol
216-+ Authenticate send downstream on success. Reject request if
217-+ we can't authenticate.
218-
219-- def __call__(self, env, start_response):
220-- """ Handle incoming request. Authenticate. And send downstream. """
221-+ """
222-+ logger.debug('Authenticating user token')
223-+ try:
224-+ self._remove_auth_headers(env)
225-+ user_token = self._get_user_token_from_header(env)
226-+ token_info = self._validate_user_token(user_token)
227-+ user_headers = self._build_user_headers(token_info)
228-+ self._add_headers(env, user_headers)
229-+ return self.app(env, start_response)
230-
231-- #Prep headers to forward request to local or remote downstream service
232-- proxy_headers = env.copy()
233-- for header in proxy_headers.iterkeys():
234-- if header.startswith('HTTP_'):
235-- proxy_headers[header[5:]] = proxy_headers[header]
236-- del proxy_headers[header]
237--
238-- #Look for authentication claims
239-- claims = self._get_claims(env)
240-- if not claims:
241-- #No claim(s) provided
242-+ except InvalidUserToken:
243- if self.delay_auth_decision:
244-- #Configured to allow downstream service to make final decision.
245-- #So mark status as Invalid and forward the request downstream
246-- self._decorate_request('X_IDENTITY_STATUS',
247-- 'Invalid',
248-- env,
249-- proxy_headers)
250-+ logger.info('Invalid user token - deferring reject downstream')
251-+ self._add_headers(env, {'X-Identity-Status': 'Invalid'})
252-+ return self.app(env, start_response)
253- else:
254-- #Respond to client as appropriate for this auth protocol
255-+ logger.info('Invalid user token - rejecting request')
256- return self._reject_request(env, start_response)
257-+
258-+ except ServiceError, e:
259-+ logger.critical('Unable to obtain admin token: %s' % e)
260-+ resp = webob.exc.HTTPServiceUnavailable()
261-+ return resp(env, start_response)
262-+
263-+ def _remove_auth_headers(self, env):
264-+ """Remove headers so a user can't fake authentication.
265-+
266-+ :param env: wsgi request environment
267-+
268-+ """
269-+ auth_headers = (
270-+ 'X-Identity-Status',
271-+ 'X-Tenant-Id',
272-+ 'X-Tenant-Name',
273-+ 'X-User-Id',
274-+ 'X-User-Name',
275-+ 'X-Roles',
276-+ # Deprecated
277-+ 'X-User',
278-+ 'X-Tenant',
279-+ 'X-Role',
280-+ )
281-+ logger.debug('Removing headers from request environment: %s' %
282-+ ','.join(auth_headers))
283-+ self._remove_headers(env, auth_headers)
284-+
285-+ def _get_user_token_from_header(self, env):
286-+ """Get token id from request.
287-+
288-+ :param env: wsgi request environment
289-+ :return token id
290-+ :raises InvalidUserToken if no token is provided in request
291-+
292-+ """
293-+ token = self._get_header(env, 'X-Auth-Token',
294-+ self._get_header(env, 'X-Storage-Token'))
295-+ if token:
296-+ return token
297- else:
298-- # this request is presenting claims. Let's validate them
299-- valid = self._validate_claims(claims)
300-- if not valid:
301-- # Keystone rejected claim
302-- if self.delay_auth_decision:
303-- # Downstream service will receive call still and decide
304-- self._decorate_request('X_IDENTITY_STATUS',
305-- 'Invalid',
306-- env,
307-- proxy_headers)
308-- else:
309-- #Respond to client as appropriate for this auth protocol
310-- return self._reject_claims(env, start_response)
311-- else:
312-- self._decorate_request('X_IDENTITY_STATUS',
313-- 'Confirmed',
314-- env,
315-- proxy_headers)
316--
317-- #Collect information about valid claims
318-- if valid:
319-- claims = self._expound_claims(claims)
320--
321-- # Store authentication data
322-- if claims:
323-- self._decorate_request('X_AUTHORIZATION',
324-- 'Proxy %s' % claims['user'],
325-- env,
326-- proxy_headers)
327--
328-- # For legacy compatibility before we had ID and Name
329-- self._decorate_request('X_TENANT',
330-- claims['tenant'],
331-- env,
332-- proxy_headers)
333--
334-- # Services should use these
335-- self._decorate_request('X_TENANT_NAME',
336-- claims.get('tenantName',
337-- claims['tenant']),
338-- env,
339-- proxy_headers)
340-- self._decorate_request('X_TENANT_ID',
341-- claims['tenant'],
342-- env,
343-- proxy_headers)
344--
345-- self._decorate_request('X_USER',
346-- claims['userName'],
347-- env,
348-- proxy_headers)
349-- self._decorate_request('X_USER_ID',
350-- claims['user'],
351-- env,
352-- proxy_headers)
353--
354-- # NOTE(lzyeval): claims has a key 'roles' which is
355-- # guaranteed to be a list (see note below)
356-- roles = ','.join(filter(lambda x: x, claims['roles']))
357-- self._decorate_request('X_ROLE',
358-- roles,
359-- env,
360-- proxy_headers)
361--
362-- # NOTE(todd): unused
363-- self.expanded = True
364--
365-- #Send request downstream
366-- return self._forward_request(env, start_response, proxy_headers)
367--
368-- def _get_claims(self, env):
369-- """Get claims from request"""
370-- claims = env.get('HTTP_X_AUTH_TOKEN', env.get('HTTP_X_STORAGE_TOKEN'))
371-- return claims
372-+ raise InvalidUserToken('Unable to find token in headers')
373-
374- def _reject_request(self, env, start_response):
375-- """Redirect client to auth server"""
376-- headers = [('WWW-Authenticate',
377-- "Keystone uri='%s'" % self.auth_location)]
378-+ """Redirect client to auth server.
379-+
380-+ :param env: wsgi request environment
381-+ :param start_response: wsgi response callback
382-+ :returns HTTPUnauthorized http response
383-+
384-+ """
385-+ headers = [('WWW-Authenticate', 'Keystone uri=\'%s\'' % self.auth_uri)]
386- resp = webob.exc.HTTPUnauthorized('Authentication required', headers)
387- return resp(env, start_response)
388-
389-- def _reject_claims(self, env, start_response):
390-- """Client sent bad claims"""
391-- resp = webob.exc.HTTPUnauthorized()
392-- return resp(env, start_response)
393-+ def get_admin_token(self):
394-+ """Return admin token, possibly fetching a new one.
395-+
396-+ :return admin token id
397-+ :raise ServiceError when unable to retrieve token from keystone
398-
399-- def _get_admin_auth_token(self, username, password):
400- """
401-- This function gets an admin auth token to be used by this service to
402-- validate a user's token. Validate_token is a priviledged call so
403-- it needs to be authenticated by a service that is calling it
404-+ if not self.admin_token:
405-+ self.admin_token = self._request_admin_token()
406-+
407-+ return self.admin_token
408-+
409-+ def _get_http_connection(self):
410-+ return self.http_client_class(self.auth_host, self.auth_port)
411-+
412-+ def _json_request(self, method, path, body=None, additional_headers=None):
413-+ """HTTP request helper used to make json requests.
414-+
415-+ :param method: http method
416-+ :param path: relative request url
417-+ :param body: dict to encode to json as request body. Optional.
418-+ :param additional_headers: dict of additional headers to send with
419-+ http request. Optional.
420-+ :return (http response object, response body parsed as json)
421-+ :raise ServerError when unable to communicate with keystone
422-+
423- """
424-- headers = {
425-- "Content-type": "application/json",
426-- "Accept": "application/json",
427-- }
428-- params = {
429-- "auth": {
430-- "passwordCredentials": {
431-- "username": username,
432-- "password": password,
433-- },
434-- "tenantName": ADMIN_TENANTNAME,
435-- }
436-- }
437-- if self.auth_protocol == "http":
438-- conn = httplib.HTTPConnection(self.auth_host, self.auth_port)
439-- else:
440-- conn = httplib.HTTPSConnection(self.auth_host,
441-- self.auth_port,
442-- cert_file=self.cert_file)
443-- conn.request("POST",
444-- '/v2.0/tokens',
445-- json.dumps(params),
446-- headers=headers)
447-- response = conn.getresponse()
448-- data = response.read()
449-- conn.close()
450-+ conn = self._get_http_connection()
451-+
452-+ kwargs = {
453-+ 'headers': {
454-+ 'Content-type': 'application/json',
455-+ 'Accept': 'application/json',
456-+ },
457-+ }
458-+
459-+ if additional_headers:
460-+ kwargs['headers'].update(additional_headers)
461-+
462-+ if body:
463-+ kwargs['body'] = json.dumps(body)
464-+
465- try:
466-- return json.loads(data)["access"]["token"]["id"]
467-- except KeyError:
468-- return None
469-+ conn.request(method, path, **kwargs)
470-+ response = conn.getresponse()
471-+ body = response.read()
472-+ data = json.loads(body)
473-+ except Exception, e:
474-+ logger.error('HTTP connection exception: %s' % e)
475-+ raise ServiceError('Unable to communicate with keystone')
476-+ finally:
477-+ conn.close()
478-
479-- def _validate_claims(self, claims, retry=True):
480-- """Validate claims, and provide identity information isf applicable """
481-+ return response, data
482-
483-- # Step 1: We need to auth with the keystone service, so get an
484-- # admin token
485-- if not self.admin_token:
486-- self.admin_token = self._get_admin_auth_token(self.admin_user,
487-- self.admin_password)
488-+ def _request_admin_token(self):
489-+ """Retrieve new token as admin user from keystone.
490-
491-- # Step 2: validate the user's token with the auth service
492-- # since this is a priviledged op,m we need to auth ourselves
493-- # by using an admin token
494-- headers = {
495-- 'Content-type': 'application/json',
496-- 'Accept': 'application/json',
497-- 'X-Auth-Token': self.admin_token,
498-+ :return token id upon success
499-+ :raises ServerError when unable to communicate with keystone
500-+
501-+ """
502-+ params = {
503-+ 'auth': {
504-+ 'passwordCredentials': {
505-+ 'username': self.admin_user,
506-+ 'password': self.admin_password,
507-+ },
508-+ 'tenantName': self.admin_tenant_name,
509- }
510-- ##TODO(ziad):we need to figure out how to auth to keystone
511-- #since validate_token is a priviledged call
512-- #Khaled's version uses creds to get a token
513-- # 'X-Auth-Token': admin_token}
514-- # we're using a test token from the ini file for now
515-- conn = http_connect(self.auth_host,
516-- self.auth_port,
517-- 'GET',
518-- '/v2.0/tokens/%s' % claims,
519-- headers=headers)
520-- resp = conn.getresponse()
521-- # data = resp.read()
522-- conn.close()
523--
524-- if not str(resp.status).startswith('20'):
525-- if retry:
526-- self.admin_token = None
527-- return self._validate_claims(claims, False)
528-- else:
529-- return False
530-+ }
531-+
532-+ response, data = self._json_request('POST',
533-+ '/v2.0/tokens',
534-+ body=params)
535-+
536-+ try:
537-+ token = data['access']['token']['id']
538-+ assert token
539-+ return token
540-+ except (AssertionError, KeyError):
541-+ raise ServiceError('invalid json response')
542-+
543-+ def _validate_user_token(self, user_token, retry=True):
544-+ """Authenticate user token with keystone.
545-+
546-+ :param user_token: user's token id
547-+ :param retry: flag that forces the middleware to retry
548-+ user authentication when an indeterminate
549-+ response is received. Optional.
550-+ :return token object received from keystone on success
551-+ :raise InvalidUserToken if token is rejected
552-+ :raise ServiceError if unable to authenticate token
553-+
554-+ """
555-+ headers = {'X-Auth-Token': self.get_admin_token()}
556-+ response, data = self._json_request('GET',
557-+ '/v2.0/tokens/%s' % user_token,
558-+ additional_headers=headers)
559-+
560-+ if response.status == 200:
561-+ return data
562-+ if response.status == 404:
563-+ # FIXME(ja): I'm assuming the 404 status means that user_token is
564-+ # invalid - not that the admin_token is invalid
565-+ raise InvalidUserToken('Token authorization failed')
566-+ if response.status == 401:
567-+ logger.info('Keystone rejected admin token, resetting')
568-+ self.admin_token = None
569- else:
570-- #TODO(Ziad): there is an optimization we can do here. We have just
571-- #received data from Keystone that we can use instead of making
572-- #another call in _expound_claims
573-- return True
574--
575-- def _expound_claims(self, claims):
576-- # Valid token. Get user data and put it in to the call
577-- # so the downstream service can use it
578-- headers = {
579-- 'Content-type': 'application/json',
580-- 'Accept': 'application/json',
581-- 'X-Auth-Token': self.admin_token,
582-- }
583-- ##TODO(ziad):we need to figure out how to auth to keystone
584-- #since validate_token is a priviledged call
585-- #Khaled's version uses creds to get a token
586-- # 'X-Auth-Token': admin_token}
587-- # we're using a test token from the ini file for now
588-- conn = http_connect(self.auth_host,
589-- self.auth_port,
590-- 'GET',
591-- '/v2.0/tokens/%s' % claims,
592-- headers=headers)
593-- resp = conn.getresponse()
594-- data = resp.read()
595-- conn.close()
596--
597-- if not str(resp.status).startswith('20'):
598-- raise LookupError('Unable to locate claims: %s' % resp.status)
599--
600-- token_info = json.loads(data)
601-- access_user = token_info['access']['user']
602-- access_token = token_info['access']['token']
603-- # Nova looks for the non case-sensitive role 'admin'
604-- # to determine admin-ness
605-- # NOTE(lzyeval): roles is always a list
606-- roles = map(lambda y: y['name'], access_user.get('roles', []))
607-+ logger.error('Bad response code while validating token: %s' %
608-+ response.status)
609-+ if retry:
610-+ logger.info('Retrying validation')
611-+ return self._validate_user_token(user_token, False)
612-+ else:
613-+ raise InvalidUserToken()
614-+
615-+ def _build_user_headers(self, token_info):
616-+ """Convert token object into headers.
617-
618-+ Build headers that represent authenticated user:
619-+ * X_IDENTITY_STATUS: Confirmed or Invalid
620-+ * X_TENANT_ID: id of tenant if tenant is present
621-+ * X_TENANT_NAME: name of tenant if tenant is present
622-+ * X_USER_ID: id of user
623-+ * X_USER_NAME: name of user
624-+ * X_ROLES: list of roles
625-+
626-+ Additional (deprecated) headers include:
627-+ * X_USER: name of user
628-+ * X_TENANT: For legacy compatibility before we had ID and Name
629-+ * X_ROLE: list of roles
630-+
631-+ :param token_info: token object returned by keystone on authentication
632-+ :raise InvalidUserToken when unable to parse token object
633-+
634-+ """
635-+ user = token_info['access']['user']
636-+ token = token_info['access']['token']
637-+ roles = ','.join([role['name'] for role in user.get('roles', [])])
638-+
639-+ # FIXME(ja): I think we are checking in both places because:
640-+ # tenant might not be returned, and there was a pre-release
641-+ # that put tenant objects inside the user object?
642- try:
643-- tenant = access_token['tenant']['id']
644-- tenant_name = access_token['tenant']['name']
645-+ tenant_id = token['tenant']['id']
646-+ tenant_name = token['tenant']['name']
647- except:
648-- tenant = None
649-- tenant_name = None
650-- if not tenant:
651-- tenant = access_user.get('tenantId')
652-- tenant_name = access_user.get('tenantName')
653-- verified_claims = {
654-- 'user': access_user['id'],
655-- 'userName': access_user['username'],
656-- 'tenant': tenant,
657-- 'roles': roles,
658-- }
659-- if tenant_name:
660-- verified_claims['tenantName'] = tenant_name
661-- return verified_claims
662--
663-- def _decorate_request(self, index, value, env, proxy_headers):
664-- """Add headers to request"""
665-- proxy_headers[index] = value
666-- env['HTTP_%s' % index] = value
667--
668-- def _forward_request(self, env, start_response, proxy_headers):
669-- """Token/Auth processed & claims added to headers"""
670-- self._decorate_request('AUTHORIZATION',
671-- 'Basic %s' % self.service_pass, env, proxy_headers)
672-- #now decide how to pass on the call
673-- if self.app:
674-- # Pass to downstream WSGI component
675-- return self.app(env, start_response)
676-- #.custom_start_response)
677-- else:
678-- # We are forwarding to a remote service (no downstream WSGI app)
679-- req = webob.Request(proxy_headers)
680-- parsed = urlparse(req.url)
681--
682-- conn = http_connect(self.service_host,
683-- self.service_port,
684-- req.method,
685-- parsed.path,
686-- proxy_headers,
687-- ssl=(self.service_protocol == 'https'))
688-- resp = conn.getresponse()
689-- data = resp.read()
690--
691-- #TODO(ziad): use a more sophisticated proxy
692-- # we are rewriting the headers now
693--
694-- if resp.status == 401 or resp.status == 305:
695-- # Add our own headers to the list
696-- headers = [('WWW_AUTHENTICATE',
697-- "Keystone uri='%s'" % self.auth_location)]
698-- return webob.Response(status=resp.status,
699-- body=data,
700-- headerlist=headers)(env, start_response)
701-- else:
702-- return webob.Response(status=resp.status,
703-- body=data)(env, start_response)
704-+ tenant_id = user.get('tenantId')
705-+ tenant_name = user.get('tenantName')
706-+
707-+ user_id = user['id']
708-+ user_name = user['username']
709-+
710-+ return {
711-+ 'X-Identity-Status': 'Confirmed',
712-+ 'X-Tenant-Id': tenant_id,
713-+ 'X-Tenant-Name': tenant_name,
714-+ 'X-User-Id': user_id,
715-+ 'X-User-Name': user_name,
716-+ 'X-Roles': roles,
717-+ # Deprecated
718-+ 'X-User': user_name,
719-+ 'X-Tenant': tenant_name,
720-+ 'X-Role': roles,
721-+ }
722-+
723-+ def _header_to_env_var(self, key):
724-+ """Convert header to wsgi env variable.
725-+
726-+ :param key: http header name (ex. 'X-Auth-Token')
727-+ :return wsgi env variable name (ex. 'HTTP_X_AUTH_TOKEN')
728-+
729-+ """
730-+ return 'HTTP_%s' % key.replace('-', '_').upper()
731-+
732-+ def _add_headers(self, env, headers):
733-+ """Add http headers to environment."""
734-+ for (k, v) in headers.iteritems():
735-+ env_key = self._header_to_env_var(k)
736-+ env[env_key] = v
737-+
738-+ def _remove_headers(self, env, keys):
739-+ """Remove http headers from environment."""
740-+ for k in keys:
741-+ env_key = self._header_to_env_var(k)
742-+ try:
743-+ del env[env_key]
744-+ except KeyError:
745-+ pass
746-+
747-+ def _get_header(self, env, key, default=None):
748-+ """Get http header from environment."""
749-+ env_key = self._header_to_env_var(key)
750-+ return env.get(env_key, default)
751-
752-
753- def filter_factory(global_conf, **local_conf):
754-@@ -438,12 +440,3 @@ def app_factory(global_conf, **local_con
755- conf = global_conf.copy()
756- conf.update(local_conf)
757- return AuthProtocol(None, conf)
758--
759--if __name__ == '__main__':
760-- app_path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
761-- os.pardir,
762-- os.pardir,
763-- 'examples/paste/auth_token.ini')
764-- app = deploy.loadapp('config:%s' % app_path,
765-- global_conf={'log_name': 'auth_token.log'})
766-- wsgi.server(eventlet.listen(('', 8090)), app)
767
768=== modified file 'debian/patches/series'
769--- debian/patches/series 2012-03-02 14:54:39 +0000
770+++ debian/patches/series 2012-03-07 02:13:21 +0000
771@@ -1,2 +1,1 @@
772 sql_connection.patch
773-keystone-auth.patch
774
775=== modified file 'debian/patches/sql_connection.patch'
776--- debian/patches/sql_connection.patch 2012-03-01 01:57:57 +0000
777+++ debian/patches/sql_connection.patch 2012-03-07 02:13:21 +0000
778@@ -18,7 +18,7 @@
779 # syslog_log_facility = LOG_LOCAL0
780
781 [sql]
782--connection = sqlite:///bla.db
783+-connection = sqlite:///keystone.db
784 +connection = sqlite:////var/lib/keystone/keystone.db
785 idle_timeout = 200
786 min_pool_size = 5

Subscribers

People subscribed via source and target branches