Merge lp:~khussein/swift/authn into lp:~hudson-openstack/swift/trunk

Proposed by Khaled Hussein
Status: Work in progress
Proposed branch: lp:~khussein/swift/authn
Merge into: lp:~hudson-openstack/swift/trunk
Diff against target: 1009 lines (+443/-250)
7 files modified
.unittests (+1/-1)
doc/source/development_saio.rst (+10/-3)
setup.py (+4/-2)
swift/common/middleware/devauthn.py (+145/-0)
swift/common/middleware/devauthz.py (+48/-109)
swift/common/middleware/papiauth.py (+62/-0)
test/unit/common/middleware/test_auth.py (+173/-135)
To merge this branch: bzr merge lp:~khussein/swift/authn
Reviewer Review Type Date Requested Status
gholt (community) Disapprove
Chuck Thier Pending
Mike Barton Pending
Review via email: mp+45909@code.launchpad.net

This proposal supersedes a proposal from 2011-01-07.

Description of the change

Implemented the proposed protocol to handle authentication in OpenStack services.

To post a comment you must log in.
Revision history for this message
Mike Barton (redbo) wrote : Posted in a previous version of this proposal

> self.response_status = status

self.response_status is storing per-request info in a shared object. That could be wrong under concurrency.

> ''.join(response_itr)
> return [resp.read()]
> response.content_length = sum(map(len, response.app_iter))

Storing many GB of data in RAM is a bad idea.

> usersConfig.readfp(open('/etc/openstack/users.ini'))

You shouldn't re-read and parse the basic auth credentials file on every request. The local imports there are kind of ugly too.

> def validateCreds(self, username, password):

only major pep8 violation I see is those camel caps.

> - 'auth=swift.auth.server:app_factory',
> + #'auth=swift.auth.server:app_factory',
> + 'auth=swift.auth.basicauth:app_factory',

Was leaving it this way a mistake? The basic auth isn't super useful right now, and removing the devauth filter completely breaks our dev and testing environments.

review: Needs Fixing
Revision history for this message
gholt (gholt) wrote : Posted in a previous version of this proposal

We meant for this to be a work-in-progress; sorry.

Revision history for this message
gholt (gholt) wrote : Posted in a previous version of this proposal

Oh, and these weren't the droids you were looking for anyhow. Move along; move along.

Revision history for this message
Khaled Hussein (khussein) wrote : Posted in a previous version of this proposal

The proxy-server config now would be [auth1 devauth papiauth]

Revision history for this message
Chuck Thier (cthier) wrote : Posted in a previous version of this proposal

Initial comments:

1. There is one unit test failure
2. There are 9 functional test failures
3. There are no unit tests for the new pieces of middleware
4. There are no docs that explain how/when to use the different pieces of middleware
5. Do the saio or multiserver install docs need to change?
6. auth1 is a poor choice for the module name and class name
7. Is anything going to need to change when we move to swauth?
8. PEP8:

cthier@storage1:~/swift/authn$ pep8 -r swift/common/middleware/auth1.py
swift/common/middleware/auth1.py:24:1: E302 expected 2 blank lines, found 1
swift/common/middleware/auth1.py:97:1: W293 blank line contains whitespace
swift/common/middleware/auth1.py:112:75: W291 trailing whitespace
swift/common/middleware/auth1.py:113:76: W291 trailing whitespace
swift/common/middleware/auth1.py:140:1: E302 expected 2 blank lines, found 1

cthier@storage1:~/swift/authn$ pep8 -r swift/common/middleware/papiauth.py
swift/common/middleware/papiauth.py:43:50: W291 trailing whitespace
swift/common/middleware/papiauth.py:63:1: W391 blank line at end of file
cthier@storage1:~/swift/authn$ pep8 -r swift/common/middleware/auth.py

cthier@storage1:~/swift/authn$ pep8 -r swift/common/middleware/devauth.py
swift/common/middleware/devauth.py:40:20: W291 trailing whitespace

review: Needs Fixing
Revision history for this message
gholt (gholt) wrote : Posted in a previous version of this proposal

As I understood things, the DevAuth that we have always used was not going to change except that it was going to set an additional header instead of just setting REMOTE_USER. All the new auth stuff was going to be new files. What happened with that plan?

Revision history for this message
Khaled Hussein (khussein) wrote : Posted in a previous version of this proposal

Following the 'public or anonymous access' use case that you've mentioned, we've discussed adding the delegated mode, which is documented in our blueprint. So, this added a couple of new changes to the source code. It also lead us to refactor the code base a little bit so that we separate the two concerns: authentication and authorization into two separate modules.

Revision history for this message
gholt (gholt) wrote :

You need to put a note in the description indicating how one should convert their SAIO over to use this branch.

I did the best I could based on the diff (changed my proxy-server.conf to have the three!? new auth middlewares) and not a single functional test passed.

Also, st did not work with this scheme.

You would need to update the SAIO docs and the How-To Install Multinode docs and probably other docs I'm not thinking of.

You changed a copyright notice that you probably didn't intend to.

I'll reiterate: It is best if you don't change the existing auth code and instead add a new one. Once the new one appears to work flawlessly and is a drop-in replacement for the old, then we can talk about defaults, etc.

review: Disapprove
lp:~khussein/swift/authn updated
160. By Khaled Hussein

documentation change

161. By Khaled Hussein

merge trunk

Revision history for this message
Khaled Hussein (khussein) wrote :

Hey Greg, thank you for your time today and I am glad that the tests pass.

Unmerged revisions

161. By Khaled Hussein

merge trunk

160. By Khaled Hussein

documentation change

159. By Khaled Hussein

saio documentation changes

158. By Khaled Hussein

PEP8 Stuff :)

157. By Khaled Hussein

Refactored and Added unit tests

156. By Khaled Hussein

fixing conflicts

155. By Khaled Hussein

fixed functional tests

154. By Khaled Hussein

setup.py config changes

153. By Khaled Hussein

Merged trunk

152. By Khaled Hussein

Fixed unit tests

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.unittests'
2--- .unittests 2010-07-13 03:34:34 +0000
3+++ .unittests 2011-01-12 19:08:11 +0000
4@@ -1,4 +1,4 @@
5 #!/bin/bash
6
7-nosetests test/unit --exe --with-coverage --cover-package swift --cover-erase
8+nosetests test/unit/ --exe --with-coverage --cover-package swift --cover-erase
9 rm -f .coverage
10
11=== modified file 'doc/source/development_saio.rst'
12--- doc/source/development_saio.rst 2010-12-02 01:08:49 +0000
13+++ doc/source/development_saio.rst 2011-01-12 19:08:11 +0000
14@@ -240,7 +240,7 @@
15
16 [pipeline:main]
17 # For DevAuth:
18- pipeline = healthcheck cache auth proxy-server
19+ pipeline = healthcheck cache devauthn devauthz papiauth proxy-server
20 # For Swauth:
21 # pipeline = healthcheck cache swauth proxy-server
22
23@@ -249,8 +249,15 @@
24 allow_account_management = true
25
26 # Only needed for DevAuth
27- [filter:auth]
28- use = egg:swift#auth
29+ [filter:devauthn]
30+ use = egg:swift#devauthn
31+ delegated = 1
32+
33+ [filter:devauthz]
34+ use = egg:swift#devauthz
35+
36+ [filter:papiauth]
37+ use = egg:swift#papiauth
38
39 # Only needed for Swauth
40 [filter:swauth]
41
42=== modified file 'setup.py'
43--- setup.py 2011-01-05 15:17:36 +0000
44+++ setup.py 2011-01-12 19:08:11 +0000
45@@ -1,5 +1,5 @@
46 #!/usr/bin/python
47-# Copyright (c) 2010-2011 OpenStack, LLC.
48+# Copyright (c) 2010 OpenStack, LLC.
49 #
50 # Licensed under the Apache License, Version 2.0 (the "License");
51 # you may not use this file except in compliance with the License.
52@@ -94,7 +94,9 @@
53 'auth=swift.auth.server:app_factory',
54 ],
55 'paste.filter_factory': [
56- 'auth=swift.common.middleware.auth:filter_factory',
57+ 'devauthn=swift.common.middleware.devauthn:filter_factory',
58+ 'devauthz=swift.common.middleware.devauthz:filter_factory',
59+ 'papiauth=swift.common.middleware.papiauth:filter_factory',
60 'swauth=swift.common.middleware.swauth:filter_factory',
61 'healthcheck=swift.common.middleware.healthcheck:filter_factory',
62 'memcache=swift.common.middleware.memcache:filter_factory',
63
64=== added file 'swift/common/middleware/devauthn.py'
65--- swift/common/middleware/devauthn.py 1970-01-01 00:00:00 +0000
66+++ swift/common/middleware/devauthn.py 2011-01-12 19:08:11 +0000
67@@ -0,0 +1,145 @@
68+# Copyright (c) 2010 OpenStack, LLC.
69+#
70+# Licensed under the Apache License, Version 2.0 (the "License");
71+# you may not use this file except in compliance with the License.
72+# You may obtain a copy of the License at
73+#
74+# http://www.apache.org/licenses/LICENSE-2.0
75+#
76+# Unless required by applicable law or agreed to in writing, software
77+# distributed under the License is distributed on an "AS IS" BASIS,
78+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
79+# implied.
80+# See the License for the specific language governing permissions and
81+# limitations under the License.
82+
83+from time import time
84+
85+from eventlet.timeout import Timeout
86+from webob.exc import HTTPUnauthorized
87+
88+from swift.common.bufferedhttp import http_connect_raw as http_connect
89+from swift.common.utils import cache_from_env, TRUE_VALUES
90+
91+
92+class DevAuthN(object):
93+ """Auth Middleware that uses the dev auth server."""
94+
95+ def __init__(self, app, conf):
96+ self.app = app
97+ self.conf = conf
98+ self.reseller_prefix = conf.get('reseller_prefix', 'AUTH').strip()
99+ if self.reseller_prefix and self.reseller_prefix[-1] != '_':
100+ self.reseller_prefix += '_'
101+ self.auth_host = conf.get('ip', '127.0.0.1')
102+ self.auth_prefix = conf.get('prefix', '/')
103+ self.auth_port = int(conf.get('port', 11000))
104+ self.ssl = conf.get('ssl', 'false').lower() in TRUE_VALUES
105+ self.timeout = int(conf.get('node_timeout', 10))
106+ self.delegated = int(conf.get('delegated', 0))
107+
108+ def __call__(self, env, start_response):
109+ """
110+ Accepts a standard WSGI application call and authenticates the request.
111+ For an authenticated request, SWIFT_GROUPS will be set to a comma
112+ separated list of the user's groups. It'll also set X-Authorization
113+ header to 'Proxy [Username]'. If it is running in a delegated mode, it
114+ sets the X-Identity-Status header to 'Confirmed' if the token is valid,
115+ or 'Indeterminate' if the token doesn't exist.
116+
117+ With a non-empty reseller prefix, acts as the definitive auth service
118+ for just tokens and accounts that begin with that prefix, but will deny
119+ requests outside this prefix if no other auth middleware overrides it.
120+
121+ With an empty reseller prefix, acts as the definitive auth service only
122+ for tokens that validate to a non-empty set of groups. For all other
123+ requests, acts as the fallback auth service when no other auth
124+ middleware overrides it.
125+ """
126+
127+ def custom_start_response(status, headers):
128+ if self.delegated:
129+ headers.append(('WWW-Authenticate', "Basic realm='API Realm'"))
130+ return start_response(status, headers)
131+
132+ token = env.get('HTTP_X_AUTH_TOKEN', env.get('HTTP_X_STORAGE_TOKEN'))
133+ if token and token.startswith(self.reseller_prefix):
134+ # Note: Empty reseller_prefix will match all tokens.
135+ # Attempt to auth my token with my auth server
136+ groups = \
137+ self.get_groups(token, memcache_client=cache_from_env(env))
138+ if groups:
139+ user = groups and groups.split(',', 1)[0] or ''
140+ env['SWIFT_GROUPS'] = groups
141+ env['HTTP_X_AUTHORIZATION'] = "Proxy " + user
142+ if self.delegated:
143+ env['HTTP_X_IDENTITY_STATUS'] = "Confirmed"
144+ # We know the proxy logs the token, so we augment it just
145+ # a bit to also log the authenticated user.
146+ env['HTTP_X_AUTH_TOKEN'] = '%s,%s' % (user, token)
147+ else:
148+ if self.delegated and not self.reseller_prefix:
149+ env['HTTP_X_IDENTITY_STATUS'] = "Invalid"
150+ else:
151+ # Unauthorized token
152+ return HTTPUnauthorized()(env, custom_start_response)
153+ else:
154+ env['HTTP_X_AUTHORIZATION'] = "Proxy"
155+ if self.delegated:
156+ env['HTTP_X_IDENTITY_STATUS'] = "Indeterminate"
157+ else:
158+ return HTTPUnauthorized()(env, custom_start_response)
159+
160+ env['HTTP_AUTHORIZATION'] = "Basic dTpw"
161+ return self.app(env, custom_start_response)
162+
163+ def get_groups(self, token, memcache_client=None):
164+ """
165+ Get groups for the given token.
166+
167+ If memcache_client is set, token credentials will be cached
168+ appropriately.
169+
170+ With a cache miss, or no memcache_client, the configurated external
171+ authentication server will be queried for the group information.
172+
173+ :param token: Token to validate and return a group string for.
174+ :param memcache_client: Memcached client to use for caching token
175+ credentials; None if no caching is desired.
176+ :returns: None if the token is invalid or a string containing a comma
177+ separated list of groups the authenticated user is a member
178+ of. The first group in the list is also considered a unique
179+ identifier for that user.
180+ """
181+ groups = None
182+ key = '%s/token/%s' % (self.reseller_prefix, token)
183+ cached_auth_data = memcache_client and memcache_client.get(key)
184+ if cached_auth_data:
185+ start, expiration, groups = cached_auth_data
186+ if time() - start > expiration:
187+ groups = None
188+ if not groups:
189+ with Timeout(self.timeout):
190+ conn = http_connect(self.auth_host, self.auth_port, 'GET',
191+ '%stoken/%s' % (self.auth_prefix, token), ssl=self.ssl)
192+ resp = conn.getresponse()
193+ resp.read()
194+ conn.close()
195+ if resp.status // 100 != 2:
196+ return None
197+ expiration = float(resp.getheader('x-auth-ttl'))
198+ groups = resp.getheader('x-auth-groups')
199+ if memcache_client:
200+ memcache_client.set(key, (time(), expiration, groups),
201+ timeout=expiration)
202+ return groups
203+
204+
205+def filter_factory(global_conf, **local_conf):
206+ """Returns a WSGI filter app for use with paste.deploy."""
207+ conf = global_conf.copy()
208+ conf.update(local_conf)
209+
210+ def auth_filter(app):
211+ return DevAuthN(app, conf)
212+ return auth_filter
213
214=== renamed file 'swift/common/middleware/auth.py' => 'swift/common/middleware/devauthz.py'
215--- swift/common/middleware/auth.py 2011-01-05 16:14:31 +0000
216+++ swift/common/middleware/devauthz.py 2011-01-12 19:08:11 +0000
217@@ -13,17 +13,13 @@
218 # See the License for the specific language governing permissions and
219 # limitations under the License.
220
221-from time import time
222-
223-from eventlet.timeout import Timeout
224 from webob.exc import HTTPForbidden, HTTPUnauthorized, HTTPNotFound
225
226-from swift.common.bufferedhttp import http_connect_raw as http_connect
227 from swift.common.middleware.acl import clean_acl, parse_acl, referrer_allowed
228-from swift.common.utils import cache_from_env, split_path, TRUE_VALUES
229-
230-
231-class DevAuth(object):
232+from swift.common.utils import split_path, TRUE_VALUES
233+
234+
235+class DevAuthZ(object):
236 """Auth Middleware that uses the dev auth server."""
237
238 def __init__(self, app, conf):
239@@ -42,110 +38,50 @@
240 """
241 Accepts a standard WSGI application call, authenticating the request
242 and installing callback hooks for authorization and ACL header
243- validation. For an authenticated request, REMOTE_USER will be set to a
244- comma separated list of the user's groups.
245-
246- With a non-empty reseller prefix, acts as the definitive auth service
247- for just tokens and accounts that begin with that prefix, but will deny
248- requests outside this prefix if no other auth middleware overrides it.
249-
250- With an empty reseller prefix, acts as the definitive auth service only
251- for tokens that validate to a non-empty set of groups. For all other
252- requests, acts as the fallback auth service when no other auth
253- middleware overrides it.
254+ validation.
255 """
256- token = env.get('HTTP_X_AUTH_TOKEN', env.get('HTTP_X_STORAGE_TOKEN'))
257- if token and token.startswith(self.reseller_prefix):
258- # Note: Empty reseller_prefix will match all tokens.
259- # Attempt to auth my token with my auth server
260- groups = \
261- self.get_groups(token, memcache_client=cache_from_env(env))
262- if groups:
263- env['REMOTE_USER'] = groups
264- user = groups and groups.split(',', 1)[0] or ''
265- # We know the proxy logs the token, so we augment it just a bit
266- # to also log the authenticated user.
267- env['HTTP_X_AUTH_TOKEN'] = '%s,%s' % (user, token)
268+ groups = None
269+ if 'SWIFT_GROUPS' in env:
270+ groups = env['SWIFT_GROUPS']
271+ env['REMOTE_USER'] = groups
272+ self.authorize = self.dev_authorize
273+ env['swift.clean_acl'] = clean_acl
274+ elif 'swift.authorize' not in env:
275+ self.authorize = self.empty_authorize
276+
277+ if self.reseller_prefix:
278+ # With a non-empty reseller_prefix, I would like to be called
279+ # back for anonymous access to accounts I know I'm the
280+ # definitive auth for.
281+ try:
282+ version, rest = split_path(env.get('PATH_INFO', ''),
283+ 1, 2, True)
284+ except ValueError:
285+ return HTTPNotFound()(env, start_response)
286+ if rest and rest.startswith(self.reseller_prefix):
287+ # Handle anonymous access to accounts I'm the definitive
288+ # auth for.
289 env['swift.authorize'] = self.authorize
290 env['swift.clean_acl'] = clean_acl
291- else:
292- # Unauthorized token
293- if self.reseller_prefix:
294- # Because I know I'm the definitive auth for this token, I
295- # can deny it outright.
296- return HTTPUnauthorized()(env, start_response)
297- # Because I'm not certain if I'm the definitive auth for empty
298- # reseller_prefixed tokens, I won't overwrite swift.authorize.
299- elif 'swift.authorize' not in env:
300- env['swift.authorize'] = self.denied_response
301- else:
302- if self.reseller_prefix:
303- # With a non-empty reseller_prefix, I would like to be called
304- # back for anonymous access to accounts I know I'm the
305- # definitive auth for.
306- try:
307- version, rest = split_path(env.get('PATH_INFO', ''),
308- 1, 2, True)
309- except ValueError:
310- return HTTPNotFound()(env, start_response)
311- if rest and rest.startswith(self.reseller_prefix):
312- # Handle anonymous access to accounts I'm the definitive
313- # auth for.
314- env['swift.authorize'] = self.authorize
315- env['swift.clean_acl'] = clean_acl
316- # Not my token, not my account, I can't authorize this request,
317- # deny all is a good idea if not already set...
318- elif 'swift.authorize' not in env:
319- env['swift.authorize'] = self.denied_response
320- # Because I'm not certain if I'm the definitive auth for empty
321- # reseller_prefixed accounts, I won't overwrite swift.authorize.
322+ # Not my token, not my account, I can't authorize this request,
323+ # deny all is a good idea if not already set...
324 elif 'swift.authorize' not in env:
325- env['swift.authorize'] = self.authorize
326- env['swift.clean_acl'] = clean_acl
327+ env['swift.authorize'] = self.denied_response
328+ # Because I'm not certain if I'm the definitive auth for empty
329+ # reseller_prefixed accounts, I won't overwrite swift.authorize.
330+ elif 'swift.authorize' not in env:
331+ env['swift.authorize'] = self.empty_authorize
332 return self.app(env, start_response)
333
334- def get_groups(self, token, memcache_client=None):
335- """
336- Get groups for the given token.
337-
338- If memcache_client is set, token credentials will be cached
339- appropriately.
340-
341- With a cache miss, or no memcache_client, the configurated external
342- authentication server will be queried for the group information.
343-
344- :param token: Token to validate and return a group string for.
345- :param memcache_client: Memcached client to use for caching token
346- credentials; None if no caching is desired.
347- :returns: None if the token is invalid or a string containing a comma
348- separated list of groups the authenticated user is a member
349- of. The first group in the list is also considered a unique
350- identifier for that user.
351- """
352- groups = None
353- key = '%s/token/%s' % (self.reseller_prefix, token)
354- cached_auth_data = memcache_client and memcache_client.get(key)
355- if cached_auth_data:
356- start, expiration, groups = cached_auth_data
357- if time() - start > expiration:
358- groups = None
359- if not groups:
360- with Timeout(self.timeout):
361- conn = http_connect(self.auth_host, self.auth_port, 'GET',
362- '%stoken/%s' % (self.auth_prefix, token), ssl=self.ssl)
363- resp = conn.getresponse()
364- resp.read()
365- conn.close()
366- if resp.status // 100 != 2:
367- return None
368- expiration = float(resp.getheader('x-auth-ttl'))
369- groups = resp.getheader('x-auth-groups')
370- if memcache_client:
371- memcache_client.set(key, (time(), expiration, groups),
372- timeout=expiration)
373- return groups
374-
375- def authorize(self, req):
376+ def empty_authorize(self, req):
377+ if 'x_identity_status' in req.headers:
378+ if req.headers['x_identity_status'] == 'Invalid':
379+ return self.denied_response(req)
380+ elif req.headers['x_identity_status'] == 'Indeterminate':
381+ return self.dev_authorize(req)
382+ return None
383+
384+ def dev_authorize(self, req):
385 """
386 Returns None if the request is authorized to continue or a standard
387 WSGI response callable if not.
388@@ -179,10 +115,13 @@
389 Returns a standard WSGI response callable with the status of 403 or 401
390 depending on whether the REMOTE_USER is set or not.
391 """
392+ headers = [('www-authenticate', 'delegated')]
393 if req.remote_user:
394- return HTTPForbidden(request=req)
395+ resp = HTTPForbidden(headers=headers, request=req)
396 else:
397- return HTTPUnauthorized(request=req)
398+ resp = HTTPUnauthorized(headers=headers, request=req)
399+
400+ return resp
401
402
403 def filter_factory(global_conf, **local_conf):
404@@ -191,5 +130,5 @@
405 conf.update(local_conf)
406
407 def auth_filter(app):
408- return DevAuth(app, conf)
409+ return DevAuthZ(app, conf)
410 return auth_filter
411
412=== added file 'swift/common/middleware/papiauth.py'
413--- swift/common/middleware/papiauth.py 1970-01-01 00:00:00 +0000
414+++ swift/common/middleware/papiauth.py 2011-01-12 19:08:11 +0000
415@@ -0,0 +1,62 @@
416+# Copyright (c) 2010 OpenStack, LLC.
417+#
418+# Licensed under the Apache License, Version 2.0 (the "License");
419+# you may not use this file except in compliance with the License.
420+# You may obtain a copy of the License at
421+#
422+# http://www.apache.org/licenses/LICENSE-2.0
423+#
424+# Unless required by applicable law or agreed to in writing, software
425+# distributed under the License is distributed on an "AS IS" BASIS,
426+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
427+# implied.
428+# See the License for the specific language governing permissions and
429+# limitations under the License.
430+
431+from webob.exc import HTTPUseProxy, HTTPUnauthorized
432+
433+from swift.common.utils import TRUE_VALUES
434+
435+
436+class PAPIAuth(object):
437+ """Auth Middleware that uses the dev auth server."""
438+
439+ def __init__(self, app, conf):
440+ self.app = app
441+ self.conf = conf
442+ self.reseller_prefix = conf.get('reseller_prefix', 'AUTH').strip()
443+ if self.reseller_prefix and self.reseller_prefix[-1] != '_':
444+ self.reseller_prefix += '_'
445+ self.auth_host = conf.get('ip', '127.0.0.1')
446+ self.auth_port = int(conf.get('port', 11000))
447+ self.auth_pass = conf.get('pass', 'dTpw')
448+ self.ssl = conf.get('ssl', 'false').lower() in TRUE_VALUES
449+ self.timeout = int(conf.get('node_timeout', 10))
450+
451+ def __call__(self, env, start_response):
452+ # Make sure that the user has been authenticated by the Auth Service
453+ if 'HTTP_X_AUTHORIZATION' not in env:
454+ proxy_location = 'http://' + self.auth_host + ':' + \
455+ str(self.auth_port) + '/'
456+ return HTTPUseProxy(location=proxy_location)(env, start_response)
457+
458+ # Authenticate the Auth component itself.
459+ headers = [('www-authenticate', 'Basic realm="swift"')]
460+ if 'HTTP_AUTHORIZATION' not in env:
461+ return HTTPUnauthorized(headers=headers)(env, start_response)
462+ else:
463+ auth_type, encoded_creds = env['HTTP_AUTHORIZATION'].split(None, 1)
464+ if encoded_creds != self.auth_pass:
465+ return HTTPUnauthorized(headers=headers)(env, start_response)
466+
467+ return self.app(env, start_response)
468+
469+
470+def filter_factory(global_conf, **local_conf):
471+ """Returns a WSGI filter app for use with paste.deploy."""
472+ conf = global_conf.copy()
473+ conf.update(local_conf)
474+
475+ def auth_filter(app):
476+ return PAPIAuth(app, conf)
477+ return auth_filter
478
479=== modified file 'test/unit/common/middleware/test_auth.py'
480--- test/unit/common/middleware/test_auth.py 2011-01-05 16:14:31 +0000
481+++ test/unit/common/middleware/test_auth.py 2011-01-12 19:08:11 +0000
482@@ -23,7 +23,7 @@
483 import eventlet
484 from webob import Request
485
486-from swift.common.middleware import auth
487+from swift.common.middleware import devauthn, devauthz, papiauth
488
489 # mocks
490 logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))
491@@ -122,243 +122,281 @@
492 class TestAuth(unittest.TestCase):
493
494 def setUp(self):
495- self.test_auth = auth.filter_factory({})(FakeApp())
496+ self.test_authn = devauthn.filter_factory({})(FakeApp())
497+ self.test_authz = devauthz.filter_factory({})(FakeApp())
498+ self.test_papiauth = papiauth.filter_factory({})(FakeApp())
499
500 def test_auth_deny_non_reseller_prefix(self):
501- old_http_connect = auth.http_connect
502- try:
503- auth.http_connect = mock_http_connect(204,
504- {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})
505- reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/BLAH_account',
506- 'HTTP_X_AUTH_TOKEN': 'BLAH_t', 'swift.cache': FakeMemcache()}
507- result = ''.join(self.test_auth(reqenv, lambda x, y: None))
508- self.assert_(result.startswith('401'), result)
509- self.assertEquals(reqenv['swift.authorize'],
510- self.test_auth.denied_response)
511- finally:
512- auth.http_connect = old_http_connect
513+ reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/BLAH_account',
514+ 'HTTP_X_AUTH_TOKEN': 'BLAH_t', 'swift.cache': FakeMemcache()}
515+ result = ''.join(self.test_authz(reqenv, lambda x, y: None))
516+ self.assert_(result.startswith('401'), result)
517+ self.assertEquals(reqenv['swift.authorize'],
518+ self.test_authz.denied_response)
519
520 def test_auth_deny_non_reseller_prefix_no_override(self):
521- old_http_connect = auth.http_connect
522+ old_http_connect = devauthn.http_connect
523 try:
524- auth.http_connect = mock_http_connect(204,
525+ local_app = FakeApp()
526+ local_authz = \
527+ devauthz.filter_factory({'reseller_prefix': ''})(local_app)
528+ local_authn = \
529+ devauthn.filter_factory({'delegated': 1})(local_authz)
530+ devauthn.http_connect = mock_http_connect(204,
531 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})
532 fake_authorize = lambda x: lambda x, y: ['500 Fake']
533 reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/BLAH_account',
534 'HTTP_X_AUTH_TOKEN': 'BLAH_t', 'swift.cache': FakeMemcache(),
535 'swift.authorize': fake_authorize}
536- result = ''.join(self.test_auth(reqenv, lambda x, y: None))
537+ result = ''.join(local_authn(reqenv, lambda x, y: None))
538 self.assert_(result.startswith('500 Fake'), result)
539 self.assertEquals(reqenv['swift.authorize'], fake_authorize)
540 finally:
541- auth.http_connect = old_http_connect
542+ devauthn.http_connect = old_http_connect
543
544- def test_auth_no_reseller_prefix_deny(self):
545+ def test_auth_no_reseller_prefix_deny_delegated(self):
546 # Ensures that when we have no reseller prefix, we don't deny a request
547 # outright but set up a denial swift.authorize and pass the request on
548 # down the chain.
549- old_http_connect = auth.http_connect
550+ old_http_connect = devauthn.http_connect
551 try:
552 local_app = FakeApp()
553- local_auth = \
554- auth.filter_factory({'reseller_prefix': ''})(local_app)
555- auth.http_connect = mock_http_connect(404)
556+ local_authz = \
557+ devauthz.filter_factory({'reseller_prefix': ''})(local_app)
558+ local_authn = \
559+ devauthn.filter_factory(\
560+ {'reseller_prefix': '', 'delegated': 1})(local_authz)
561+ devauthn.http_connect = mock_http_connect(404)
562 reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/account',
563 'HTTP_X_AUTH_TOKEN': 't', 'swift.cache': FakeMemcache()}
564- result = ''.join(local_auth(reqenv, lambda x, y: None))
565+ result = ''.join(local_authn(reqenv, lambda x, y: None))
566 self.assert_(result.startswith('401'), result)
567 self.assert_(local_app.i_was_called)
568 self.assertEquals(reqenv['swift.authorize'],
569- local_auth.denied_response)
570- finally:
571- auth.http_connect = old_http_connect
572+ local_authz.empty_authorize)
573+ finally:
574+ devauthn.http_connect = old_http_connect
575+
576+ def test_auth_no_reseller_prefix_deny_non_delegated(self):
577+ # Ensures that when we have no reseller prefix, we don't deny a request
578+ # outright but set up a denial swift.authorize and pass the request on
579+ # down the chain.
580+ old_http_connect = devauthn.http_connect
581+ try:
582+ local_app = FakeApp()
583+ local_authn = \
584+ devauthn.filter_factory(\
585+ {'reseller_prefix': ''})(local_app)
586+ devauthn.http_connect = mock_http_connect(404)
587+ reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/account',
588+ 'HTTP_X_AUTH_TOKEN': 't', 'swift.cache': FakeMemcache()}
589+ result = ''.join(local_authn(reqenv, lambda x, y: None))
590+ self.assert_(result.startswith('401'), result)
591+ self.assert_(not local_app.i_was_called)
592+ finally:
593+ devauthn.http_connect = old_http_connect
594+
595
596 def test_auth_no_reseller_prefix_allow(self):
597 # Ensures that when we have no reseller prefix, we can still allow
598 # access if our auth server accepts requests
599- old_http_connect = auth.http_connect
600- try:
601- local_app = FakeApp()
602- local_auth = \
603- auth.filter_factory({'reseller_prefix': ''})(local_app)
604- auth.http_connect = mock_http_connect(204,
605- {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})
606- reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/act',
607- 'HTTP_X_AUTH_TOKEN': 't', 'swift.cache': None}
608- result = ''.join(local_auth(reqenv, lambda x, y: None))
609- self.assert_(result.startswith('204'), result)
610- self.assert_(local_app.i_was_called)
611- self.assertEquals(reqenv['swift.authorize'],
612- local_auth.authorize)
613- finally:
614- auth.http_connect = old_http_connect
615+ local_app = FakeApp()
616+ local_auth = \
617+ devauthz.filter_factory({'reseller_prefix': ''})(local_app)
618+ reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/act',
619+ 'HTTP_X_AUTH_TOKEN': 't', 'swift.cache': None,
620+ 'SWIFT_GROUPS': 'act:usr,act,AUTH_cfa'}
621+ result = ''.join(local_auth(reqenv, lambda x, y: None))
622+ self.assert_(result.startswith('204'), result)
623+ self.assert_(local_app.i_was_called)
624+ self.assertEquals(reqenv['swift.authorize'],
625+ local_auth.empty_authorize)
626
627- def test_auth_no_reseller_prefix_no_token(self):
628+ def test_auth_no_reseller_prefix_no_token_delegated(self):
629 # Check that normally we set up a call back to our authorize.
630- local_auth = \
631- auth.filter_factory({'reseller_prefix': ''})(FakeApp())
632+ local_authz = \
633+ devauthz.filter_factory({'reseller_prefix': ''})(FakeApp())
634+ local_authn = \
635+ devauthn.filter_factory(\
636+ {'reseller_prefix': '', 'delegated':1})(local_authz)
637 reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/account',
638 'swift.cache': FakeMemcache()}
639- result = ''.join(local_auth(reqenv, lambda x, y: None))
640+ result = ''.join(local_authn(reqenv, lambda x, y: None))
641 self.assert_(result.startswith('401'), result)
642- self.assertEquals(reqenv['swift.authorize'], local_auth.authorize)
643+ self.assertEquals(\
644+ reqenv['swift.authorize'], local_authz.empty_authorize)
645 # Now make sure we don't override an existing swift.authorize when we
646 # have no reseller prefix.
647 local_authorize = lambda req: None
648 reqenv['swift.authorize'] = local_authorize
649- result = ''.join(local_auth(reqenv, lambda x, y: None))
650+ result = ''.join(local_authz(reqenv, lambda x, y: None))
651 self.assert_(result.startswith('204'), result)
652 self.assertEquals(reqenv['swift.authorize'], local_authorize)
653
654+ def test_auth_no_reseller_prefix_no_token_non_delegated(self):
655+ # Ensure that in a non_delegated mode, no token gets denied
656+ # right away.
657+ local_app = FakeApp()
658+ local_authn = \
659+ devauthn.filter_factory(\
660+ {'reseller_prefix': ''})(local_app)
661+ reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/account',
662+ 'swift.cache': FakeMemcache()}
663+ result = ''.join(local_authn(reqenv, lambda x, y: None))
664+ self.assert_(result.startswith('401'), result)
665+ self.assert_(not local_app.i_was_called)
666+
667 def test_auth_fail(self):
668- old_http_connect = auth.http_connect
669+ old_http_connect = devauthn.http_connect
670 try:
671- auth.http_connect = mock_http_connect(404)
672- result = ''.join(self.test_auth({'REQUEST_METHOD': 'GET',
673+ devauthn.http_connect = mock_http_connect(404)
674+ result = ''.join(self.test_authn({'REQUEST_METHOD': 'GET',
675 'HTTP_X_AUTH_TOKEN': 'AUTH_t', 'swift.cache': FakeMemcache()},
676 lambda x, y: None))
677 self.assert_(result.startswith('401'), result)
678 finally:
679- auth.http_connect = old_http_connect
680+ devauthn.http_connect = old_http_connect
681
682 def test_auth_success(self):
683- old_http_connect = auth.http_connect
684+ old_http_connect = devauthn.http_connect
685 try:
686- auth.http_connect = mock_http_connect(204,
687+ devauthn.http_connect = mock_http_connect(204,
688 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})
689- result = ''.join(self.test_auth({'REQUEST_METHOD': 'GET',
690+ result = ''.join(self.test_authn({'REQUEST_METHOD': 'GET',
691 'PATH_INFO': '/v/AUTH_cfa', 'HTTP_X_AUTH_TOKEN': 'AUTH_t',
692 'swift.cache': FakeMemcache()}, lambda x, y: None))
693 self.assert_(result.startswith('204'), result)
694 finally:
695- auth.http_connect = old_http_connect
696+ devauthn.http_connect = old_http_connect
697
698 def test_auth_memcache(self):
699- old_http_connect = auth.http_connect
700+ old_http_connect = devauthn.http_connect
701 try:
702 fake_memcache = FakeMemcache()
703- auth.http_connect = mock_http_connect(204,
704+ devauthn.http_connect = mock_http_connect(204,
705 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})
706- result = ''.join(self.test_auth({'REQUEST_METHOD': 'GET',
707+ result = ''.join(self.test_authn({'REQUEST_METHOD': 'GET',
708 'PATH_INFO': '/v/AUTH_cfa', 'HTTP_X_AUTH_TOKEN': 'AUTH_t',
709 'swift.cache': fake_memcache}, lambda x, y: None))
710 self.assert_(result.startswith('204'), result)
711- auth.http_connect = mock_http_connect(404)
712+ devauthn.http_connect = mock_http_connect(404)
713 # Should still be in memcache
714- result = ''.join(self.test_auth({'REQUEST_METHOD': 'GET',
715+ result = ''.join(self.test_authn({'REQUEST_METHOD': 'GET',
716 'PATH_INFO': '/v/AUTH_cfa', 'HTTP_X_AUTH_TOKEN': 'AUTH_t',
717 'swift.cache': fake_memcache}, lambda x, y: None))
718 self.assert_(result.startswith('204'), result)
719 finally:
720- auth.http_connect = old_http_connect
721+ devauthn.http_connect = old_http_connect
722
723 def test_auth_just_expired(self):
724- old_http_connect = auth.http_connect
725+ old_http_connect = devauthn.http_connect
726 try:
727 fake_memcache = FakeMemcache()
728- auth.http_connect = mock_http_connect(204,
729+ devauthn.http_connect = mock_http_connect(204,
730 {'x-auth-ttl': '0', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})
731- result = ''.join(self.test_auth({'REQUEST_METHOD': 'GET',
732+ result = ''.join(self.test_authn({'REQUEST_METHOD': 'GET',
733 'PATH_INFO': '/v/AUTH_cfa', 'HTTP_X_AUTH_TOKEN': 'AUTH_t',
734 'swift.cache': fake_memcache}, lambda x, y: None))
735 self.assert_(result.startswith('204'), result)
736- auth.http_connect = mock_http_connect(404)
737+ devauthn.http_connect = mock_http_connect(404)
738 # Should still be in memcache, but expired
739- result = ''.join(self.test_auth({'REQUEST_METHOD': 'GET',
740+ result = ''.join(self.test_authn({'REQUEST_METHOD': 'GET',
741 'HTTP_X_AUTH_TOKEN': 'AUTH_t', 'swift.cache': fake_memcache},
742 lambda x, y: None))
743 self.assert_(result.startswith('401'), result)
744 finally:
745- auth.http_connect = old_http_connect
746+ devauthn.http_connect = old_http_connect
747
748 def test_middleware_success(self):
749- old_http_connect = auth.http_connect
750+ old_http_connect = devauthn.http_connect
751 try:
752- auth.http_connect = mock_http_connect(204,
753+ devauthn.http_connect = mock_http_connect(204,
754 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})
755 req = Request.blank('/v/AUTH_cfa/c/o',
756 headers={'x-auth-token': 'AUTH_t'})
757 req.environ['swift.cache'] = FakeMemcache()
758- result = ''.join(self.test_auth(req.environ, start_response))
759+ result = ''.join(self.test_authn(req.environ, start_response))
760 self.assert_(result.startswith('204'), result)
761- self.assertEquals(req.remote_user, 'act:usr,act,AUTH_cfa')
762+ self.assertEquals(\
763+ req.environ['SWIFT_GROUPS'], 'act:usr,act,AUTH_cfa')
764 finally:
765- auth.http_connect = old_http_connect
766+ devauthn.http_connect = old_http_connect
767
768 def test_middleware_no_header(self):
769- old_http_connect = auth.http_connect
770+ old_http_connect = devauthn.http_connect
771 try:
772- auth.http_connect = mock_http_connect(204,
773+ devauthn.http_connect = mock_http_connect(204,
774 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})
775 req = Request.blank('/v/AUTH_cfa/c/o')
776 req.environ['swift.cache'] = FakeMemcache()
777- result = ''.join(self.test_auth(req.environ, start_response))
778+ result = ''.join(self.test_authn(req.environ, start_response))
779 self.assert_(result.startswith('401'), result)
780 self.assert_(not req.remote_user, req.remote_user)
781 finally:
782- auth.http_connect = old_http_connect
783+ devauthn.http_connect = old_http_connect
784
785 def test_middleware_storage_token(self):
786- old_http_connect = auth.http_connect
787+ old_http_connect = devauthn.http_connect
788 try:
789- auth.http_connect = mock_http_connect(204,
790+ devauthn.http_connect = mock_http_connect(204,
791 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})
792 req = Request.blank('/v/AUTH_cfa/c/o',
793 headers={'x-storage-token': 'AUTH_t'})
794 req.environ['swift.cache'] = FakeMemcache()
795- result = ''.join(self.test_auth(req.environ, start_response))
796+ result = ''.join(self.test_authn(req.environ, start_response))
797 self.assert_(result.startswith('204'), result)
798- self.assertEquals(req.remote_user, 'act:usr,act,AUTH_cfa')
799+ self.assertEquals(\
800+ req.environ['SWIFT_GROUPS'], 'act:usr,act,AUTH_cfa')
801 finally:
802- auth.http_connect = old_http_connect
803+ devauthn.http_connect = old_http_connect
804
805 def test_authorize_bad_path(self):
806 req = Request.blank('/badpath')
807- resp = self.test_auth.authorize(req)
808+ resp = self.test_authz.dev_authorize(req)
809 self.assertEquals(resp and resp.status_int, 401)
810 req = Request.blank('/badpath')
811 req.remote_user = 'act:usr,act,AUTH_cfa'
812- resp = self.test_auth.authorize(req)
813+ resp = self.test_authz.dev_authorize(req)
814 self.assertEquals(resp and resp.status_int, 403)
815 req = Request.blank('')
816- resp = self.test_auth.authorize(req)
817+ resp = self.test_authz.dev_authorize(req)
818 self.assertEquals(resp and resp.status_int, 404)
819 req = Request.blank('')
820 req.environ['swift.cache'] = FakeMemcache()
821- result = ''.join(self.test_auth(req.environ, lambda x, y: None))
822+ result = ''.join(self.test_authz(req.environ, lambda x, y: None))
823 self.assert_(result.startswith('404'), result)
824
825 def test_authorize_account_access(self):
826 req = Request.blank('/v1/AUTH_cfa')
827 req.remote_user = 'act:usr,act,AUTH_cfa'
828- self.assertEquals(self.test_auth.authorize(req), None)
829+ self.assertEquals(self.test_authz.dev_authorize(req), None)
830 req = Request.blank('/v1/AUTH_cfa')
831 req.remote_user = 'act:usr,act'
832- resp = self.test_auth.authorize(req)
833+ resp = self.test_authz.dev_authorize(req)
834 self.assertEquals(resp and resp.status_int, 403)
835
836 def test_authorize_acl_group_access(self):
837 req = Request.blank('/v1/AUTH_cfa')
838 req.remote_user = 'act:usr,act'
839- resp = self.test_auth.authorize(req)
840+ resp = self.test_authz.dev_authorize(req)
841 self.assertEquals(resp and resp.status_int, 403)
842 req = Request.blank('/v1/AUTH_cfa')
843 req.remote_user = 'act:usr,act'
844 req.acl = 'act'
845- self.assertEquals(self.test_auth.authorize(req), None)
846+ self.assertEquals(self.test_authz.dev_authorize(req), None)
847 req = Request.blank('/v1/AUTH_cfa')
848 req.remote_user = 'act:usr,act'
849 req.acl = 'act:usr'
850- self.assertEquals(self.test_auth.authorize(req), None)
851+ self.assertEquals(self.test_authz.dev_authorize(req), None)
852 req = Request.blank('/v1/AUTH_cfa')
853 req.remote_user = 'act:usr,act'
854 req.acl = 'act2'
855- resp = self.test_auth.authorize(req)
856+ resp = self.test_authz.dev_authorize(req)
857 self.assertEquals(resp and resp.status_int, 403)
858 req = Request.blank('/v1/AUTH_cfa')
859 req.remote_user = 'act:usr,act'
860 req.acl = 'act:usr2'
861- resp = self.test_auth.authorize(req)
862+ resp = self.test_authz.dev_authorize(req)
863 self.assertEquals(resp and resp.status_int, 403)
864
865 def test_deny_cross_reseller(self):
866@@ -366,96 +404,96 @@
867 req = Request.blank('/v1/OTHER_cfa')
868 req.remote_user = 'act:usr,act,AUTH_cfa'
869 req.acl = 'act'
870- resp = self.test_auth.authorize(req)
871+ resp = self.test_authz.dev_authorize(req)
872 self.assertEquals(resp and resp.status_int, 403)
873
874 def test_authorize_acl_referrer_access(self):
875 req = Request.blank('/v1/AUTH_cfa')
876 req.remote_user = 'act:usr,act'
877- resp = self.test_auth.authorize(req)
878- self.assertEquals(resp and resp.status_int, 403)
879- req = Request.blank('/v1/AUTH_cfa')
880- req.remote_user = 'act:usr,act'
881- req.acl = '.r:*'
882- self.assertEquals(self.test_auth.authorize(req), None)
883- req = Request.blank('/v1/AUTH_cfa')
884- req.remote_user = 'act:usr,act'
885- req.acl = '.r:.example.com'
886- resp = self.test_auth.authorize(req)
887- self.assertEquals(resp and resp.status_int, 403)
888- req = Request.blank('/v1/AUTH_cfa')
889- req.remote_user = 'act:usr,act'
890- req.referer = 'http://www.example.com/index.html'
891- req.acl = '.r:.example.com'
892- self.assertEquals(self.test_auth.authorize(req), None)
893- req = Request.blank('/v1/AUTH_cfa')
894- resp = self.test_auth.authorize(req)
895- self.assertEquals(resp and resp.status_int, 401)
896- req = Request.blank('/v1/AUTH_cfa')
897- req.acl = '.r:*'
898- self.assertEquals(self.test_auth.authorize(req), None)
899- req = Request.blank('/v1/AUTH_cfa')
900- req.acl = '.r:.example.com'
901- resp = self.test_auth.authorize(req)
902- self.assertEquals(resp and resp.status_int, 401)
903- req = Request.blank('/v1/AUTH_cfa')
904- req.referer = 'http://www.example.com/index.html'
905- req.acl = '.r:.example.com'
906- self.assertEquals(self.test_auth.authorize(req), None)
907+ resp = self.test_authz.dev_authorize(req)
908+ self.assertEquals(resp and resp.status_int, 403)
909+ req = Request.blank('/v1/AUTH_cfa')
910+ req.remote_user = 'act:usr,act'
911+ req.acl = '.r:*'
912+ self.assertEquals(self.test_authz.dev_authorize(req), None)
913+ req = Request.blank('/v1/AUTH_cfa')
914+ req.remote_user = 'act:usr,act'
915+ req.acl = '.r:.example.com'
916+ resp = self.test_authz.dev_authorize(req)
917+ self.assertEquals(resp and resp.status_int, 403)
918+ req = Request.blank('/v1/AUTH_cfa')
919+ req.remote_user = 'act:usr,act'
920+ req.referer = 'http://www.example.com/index.html'
921+ req.acl = '.r:.example.com'
922+ self.assertEquals(self.test_authz.dev_authorize(req), None)
923+ req = Request.blank('/v1/AUTH_cfa')
924+ resp = self.test_authz.dev_authorize(req)
925+ self.assertEquals(resp and resp.status_int, 401)
926+ req = Request.blank('/v1/AUTH_cfa')
927+ req.acl = '.r:*'
928+ self.assertEquals(self.test_authz.dev_authorize(req), None)
929+ req = Request.blank('/v1/AUTH_cfa')
930+ req.acl = '.r:.example.com'
931+ resp = self.test_authz.dev_authorize(req)
932+ self.assertEquals(resp and resp.status_int, 401)
933+ req = Request.blank('/v1/AUTH_cfa')
934+ req.referer = 'http://www.example.com/index.html'
935+ req.acl = '.r:.example.com'
936+ self.assertEquals(self.test_authz.dev_authorize(req), None)
937
938 def test_account_put_permissions(self):
939 req = Request.blank('/v1/AUTH_new', environ={'REQUEST_METHOD': 'PUT'})
940 req.remote_user = 'act:usr,act'
941- resp = self.test_auth.authorize(req)
942+ resp = self.test_authz.dev_authorize(req)
943 self.assertEquals(resp and resp.status_int, 403)
944
945 req = Request.blank('/v1/AUTH_new', environ={'REQUEST_METHOD': 'PUT'})
946 req.remote_user = 'act:usr,act,AUTH_other'
947- resp = self.test_auth.authorize(req)
948+ resp = self.test_authz.dev_authorize(req)
949 self.assertEquals(resp and resp.status_int, 403)
950
951 # Even PUTs to your own account as account admin should fail
952 req = Request.blank('/v1/AUTH_old', environ={'REQUEST_METHOD': 'PUT'})
953 req.remote_user = 'act:usr,act,AUTH_old'
954- resp = self.test_auth.authorize(req)
955+ resp = self.test_authz.dev_authorize(req)
956 self.assertEquals(resp and resp.status_int, 403)
957
958 req = Request.blank('/v1/AUTH_new', environ={'REQUEST_METHOD': 'PUT'})
959 req.remote_user = 'act:usr,act,.reseller_admin'
960- resp = self.test_auth.authorize(req)
961+ resp = self.test_authz.dev_authorize(req)
962 self.assertEquals(resp, None)
963
964 # .super_admin is not something the middleware should ever see or care
965 # about
966 req = Request.blank('/v1/AUTH_new', environ={'REQUEST_METHOD': 'PUT'})
967 req.remote_user = 'act:usr,act,.super_admin'
968- resp = self.test_auth.authorize(req)
969+ resp = self.test_authz.dev_authorize(req)
970 self.assertEquals(resp and resp.status_int, 403)
971
972 def test_account_delete_permissions(self):
973 req = Request.blank('/v1/AUTH_new',
974 environ={'REQUEST_METHOD': 'DELETE'})
975 req.remote_user = 'act:usr,act'
976- resp = self.test_auth.authorize(req)
977+ resp = self.test_authz.dev_authorize(req)
978 self.assertEquals(resp and resp.status_int, 403)
979
980 req = Request.blank('/v1/AUTH_new',
981 environ={'REQUEST_METHOD': 'DELETE'})
982 req.remote_user = 'act:usr,act,AUTH_other'
983- resp = self.test_auth.authorize(req)
984+ resp = self.test_authz.dev_authorize(req)
985 self.assertEquals(resp and resp.status_int, 403)
986
987 # Even DELETEs to your own account as account admin should fail
988 req = Request.blank('/v1/AUTH_old',
989 environ={'REQUEST_METHOD': 'DELETE'})
990 req.remote_user = 'act:usr,act,AUTH_old'
991- resp = self.test_auth.authorize(req)
992+ resp = self.test_authz.dev_authorize(req)
993 self.assertEquals(resp and resp.status_int, 403)
994
995 req = Request.blank('/v1/AUTH_new',
996 environ={'REQUEST_METHOD': 'DELETE'})
997 req.remote_user = 'act:usr,act,.reseller_admin'
998- resp = self.test_auth.authorize(req)
999+ resp = self.test_authz.dev_authorize(req)
1000 self.assertEquals(resp, None)
1001
1002 # .super_admin is not something the middleware should ever see or care
1003@@ -463,7 +501,7 @@
1004 req = Request.blank('/v1/AUTH_new',
1005 environ={'REQUEST_METHOD': 'DELETE'})
1006 req.remote_user = 'act:usr,act,.super_admin'
1007- resp = self.test_auth.authorize(req)
1008+ resp = self.test_authz.dev_authorize(req)
1009 self.assertEquals(resp and resp.status_int, 403)
1010
1011