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

Proposed by Khaled Hussein
Status: Superseded
Proposed branch: lp:~khussein/swift/authn
Merge into: lp:~hudson-openstack/swift/trunk
Diff against target: 1008 lines (+442/-250)
7 files modified
.unittests (+1/-1)
doc/source/development_saio.rst (+9/-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
Chuck Thier (community) Needs Fixing
gholt Pending
Review via email: mp+45532@code.launchpad.net

This proposal supersedes a proposal from 2010-12-08.

This proposal has been superseded by a proposal from 2011-01-11.

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 :

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 :

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 :

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.

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

documentation change

161. By Khaled Hussein

merge trunk

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
=== modified file '.unittests'
--- .unittests 2010-07-13 03:34:34 +0000
+++ .unittests 2011-01-11 20:54:28 +0000
@@ -1,4 +1,4 @@
1#!/bin/bash1#!/bin/bash
22
3nosetests test/unit --exe --with-coverage --cover-package swift --cover-erase3nosetests test/unit/ --exe --with-coverage --cover-package swift --cover-erase
4rm -f .coverage4rm -f .coverage
55
=== modified file 'doc/source/development_saio.rst'
--- doc/source/development_saio.rst 2010-12-02 01:08:49 +0000
+++ doc/source/development_saio.rst 2011-01-11 20:54:28 +0000
@@ -240,7 +240,7 @@
240240
241 [pipeline:main]241 [pipeline:main]
242 # For DevAuth:242 # For DevAuth:
243 pipeline = healthcheck cache auth proxy-server243 pipeline = healthcheck cache devauthn devauthz papiauth proxy-server
244 # For Swauth:244 # For Swauth:
245 # pipeline = healthcheck cache swauth proxy-server245 # pipeline = healthcheck cache swauth proxy-server
246 246
@@ -249,8 +249,14 @@
249 allow_account_management = true249 allow_account_management = true
250250
251 # Only needed for DevAuth251 # Only needed for DevAuth
252 [filter:auth]252 [filter:devauthn]
253 use = egg:swift#auth253 use = egg:swift#devauthn
254
255 [filter:devauthz]
256 use = egg:swift#devauthz
257
258 [filter:papiauth]
259 use = egg:swift#papiauth
254260
255 # Only needed for Swauth261 # Only needed for Swauth
256 [filter:swauth]262 [filter:swauth]
257263
=== modified file 'setup.py'
--- setup.py 2011-01-05 15:17:36 +0000
+++ setup.py 2011-01-11 20:54:28 +0000
@@ -1,5 +1,5 @@
1#!/usr/bin/python1#!/usr/bin/python
2# Copyright (c) 2010-2011 OpenStack, LLC.2# Copyright (c) 2010 OpenStack, LLC.
3#3#
4# Licensed under the Apache License, Version 2.0 (the "License");4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.5# you may not use this file except in compliance with the License.
@@ -94,7 +94,9 @@
94 'auth=swift.auth.server:app_factory',94 'auth=swift.auth.server:app_factory',
95 ],95 ],
96 'paste.filter_factory': [96 'paste.filter_factory': [
97 'auth=swift.common.middleware.auth:filter_factory',97 'devauthn=swift.common.middleware.devauthn:filter_factory',
98 'devauthz=swift.common.middleware.devauthz:filter_factory',
99 'papiauth=swift.common.middleware.papiauth:filter_factory',
98 'swauth=swift.common.middleware.swauth:filter_factory',100 'swauth=swift.common.middleware.swauth:filter_factory',
99 'healthcheck=swift.common.middleware.healthcheck:filter_factory',101 'healthcheck=swift.common.middleware.healthcheck:filter_factory',
100 'memcache=swift.common.middleware.memcache:filter_factory',102 'memcache=swift.common.middleware.memcache:filter_factory',
101103
=== added file 'swift/common/middleware/devauthn.py'
--- swift/common/middleware/devauthn.py 1970-01-01 00:00:00 +0000
+++ swift/common/middleware/devauthn.py 2011-01-11 20:54:28 +0000
@@ -0,0 +1,145 @@
1# Copyright (c) 2010 OpenStack, LLC.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12# implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16from time import time
17
18from eventlet.timeout import Timeout
19from webob.exc import HTTPUnauthorized
20
21from swift.common.bufferedhttp import http_connect_raw as http_connect
22from swift.common.utils import cache_from_env, TRUE_VALUES
23
24
25class DevAuthN(object):
26 """Auth Middleware that uses the dev auth server."""
27
28 def __init__(self, app, conf):
29 self.app = app
30 self.conf = conf
31 self.reseller_prefix = conf.get('reseller_prefix', 'AUTH').strip()
32 if self.reseller_prefix and self.reseller_prefix[-1] != '_':
33 self.reseller_prefix += '_'
34 self.auth_host = conf.get('ip', '127.0.0.1')
35 self.auth_prefix = conf.get('prefix', '/')
36 self.auth_port = int(conf.get('port', 11000))
37 self.ssl = conf.get('ssl', 'false').lower() in TRUE_VALUES
38 self.timeout = int(conf.get('node_timeout', 10))
39 self.delegated = int(conf.get('delegated', 0))
40
41 def __call__(self, env, start_response):
42 """
43 Accepts a standard WSGI application call and authenticates the request.
44 For an authenticated request, SWIFT_GROUPS will be set to a comma
45 separated list of the user's groups. It'll also set X-Authorization
46 header to 'Proxy [Username]'. If it is running in a delegated mode, it
47 sets the X-Identity-Status header to 'Confirmed' if the token is valid,
48 or 'Indeterminate' if the token doesn't exist.
49
50 With a non-empty reseller prefix, acts as the definitive auth service
51 for just tokens and accounts that begin with that prefix, but will deny
52 requests outside this prefix if no other auth middleware overrides it.
53
54 With an empty reseller prefix, acts as the definitive auth service only
55 for tokens that validate to a non-empty set of groups. For all other
56 requests, acts as the fallback auth service when no other auth
57 middleware overrides it.
58 """
59
60 def custom_start_response(status, headers):
61 if self.delegated:
62 headers.append(('WWW-Authenticate', "Basic realm='API Realm'"))
63 return start_response(status, headers)
64
65 token = env.get('HTTP_X_AUTH_TOKEN', env.get('HTTP_X_STORAGE_TOKEN'))
66 if token and token.startswith(self.reseller_prefix):
67 # Note: Empty reseller_prefix will match all tokens.
68 # Attempt to auth my token with my auth server
69 groups = \
70 self.get_groups(token, memcache_client=cache_from_env(env))
71 if groups:
72 user = groups and groups.split(',', 1)[0] or ''
73 env['SWIFT_GROUPS'] = groups
74 env['HTTP_X_AUTHORIZATION'] = "Proxy " + user
75 if self.delegated:
76 env['HTTP_X_IDENTITY_STATUS'] = "Confirmed"
77 # We know the proxy logs the token, so we augment it just
78 # a bit to also log the authenticated user.
79 env['HTTP_X_AUTH_TOKEN'] = '%s,%s' % (user, token)
80 else:
81 if self.delegated and not self.reseller_prefix:
82 env['HTTP_X_IDENTITY_STATUS'] = "Invalid"
83 else:
84 # Unauthorized token
85 return HTTPUnauthorized()(env, custom_start_response)
86 else:
87 env['HTTP_X_AUTHORIZATION'] = "Proxy"
88 if self.delegated:
89 env['HTTP_X_IDENTITY_STATUS'] = "Indeterminate"
90 else:
91 return HTTPUnauthorized()(env, custom_start_response)
92
93 env['HTTP_AUTHORIZATION'] = "Basic dTpw"
94 return self.app(env, custom_start_response)
95
96 def get_groups(self, token, memcache_client=None):
97 """
98 Get groups for the given token.
99
100 If memcache_client is set, token credentials will be cached
101 appropriately.
102
103 With a cache miss, or no memcache_client, the configurated external
104 authentication server will be queried for the group information.
105
106 :param token: Token to validate and return a group string for.
107 :param memcache_client: Memcached client to use for caching token
108 credentials; None if no caching is desired.
109 :returns: None if the token is invalid or a string containing a comma
110 separated list of groups the authenticated user is a member
111 of. The first group in the list is also considered a unique
112 identifier for that user.
113 """
114 groups = None
115 key = '%s/token/%s' % (self.reseller_prefix, token)
116 cached_auth_data = memcache_client and memcache_client.get(key)
117 if cached_auth_data:
118 start, expiration, groups = cached_auth_data
119 if time() - start > expiration:
120 groups = None
121 if not groups:
122 with Timeout(self.timeout):
123 conn = http_connect(self.auth_host, self.auth_port, 'GET',
124 '%stoken/%s' % (self.auth_prefix, token), ssl=self.ssl)
125 resp = conn.getresponse()
126 resp.read()
127 conn.close()
128 if resp.status // 100 != 2:
129 return None
130 expiration = float(resp.getheader('x-auth-ttl'))
131 groups = resp.getheader('x-auth-groups')
132 if memcache_client:
133 memcache_client.set(key, (time(), expiration, groups),
134 timeout=expiration)
135 return groups
136
137
138def filter_factory(global_conf, **local_conf):
139 """Returns a WSGI filter app for use with paste.deploy."""
140 conf = global_conf.copy()
141 conf.update(local_conf)
142
143 def auth_filter(app):
144 return DevAuthN(app, conf)
145 return auth_filter
0146
=== renamed file 'swift/common/middleware/auth.py' => 'swift/common/middleware/devauthz.py'
--- swift/common/middleware/auth.py 2011-01-05 16:14:31 +0000
+++ swift/common/middleware/devauthz.py 2011-01-11 20:54:28 +0000
@@ -13,17 +13,13 @@
13# See the License for the specific language governing permissions and13# See the License for the specific language governing permissions and
14# limitations under the License.14# limitations under the License.
1515
16from time import time
17
18from eventlet.timeout import Timeout
19from webob.exc import HTTPForbidden, HTTPUnauthorized, HTTPNotFound16from webob.exc import HTTPForbidden, HTTPUnauthorized, HTTPNotFound
2017
21from swift.common.bufferedhttp import http_connect_raw as http_connect
22from swift.common.middleware.acl import clean_acl, parse_acl, referrer_allowed18from swift.common.middleware.acl import clean_acl, parse_acl, referrer_allowed
23from swift.common.utils import cache_from_env, split_path, TRUE_VALUES19from swift.common.utils import split_path, TRUE_VALUES
2420
2521
26class DevAuth(object):22class DevAuthZ(object):
27 """Auth Middleware that uses the dev auth server."""23 """Auth Middleware that uses the dev auth server."""
2824
29 def __init__(self, app, conf):25 def __init__(self, app, conf):
@@ -42,110 +38,50 @@
42 """38 """
43 Accepts a standard WSGI application call, authenticating the request39 Accepts a standard WSGI application call, authenticating the request
44 and installing callback hooks for authorization and ACL header40 and installing callback hooks for authorization and ACL header
45 validation. For an authenticated request, REMOTE_USER will be set to a41 validation.
46 comma separated list of the user's groups.
47
48 With a non-empty reseller prefix, acts as the definitive auth service
49 for just tokens and accounts that begin with that prefix, but will deny
50 requests outside this prefix if no other auth middleware overrides it.
51
52 With an empty reseller prefix, acts as the definitive auth service only
53 for tokens that validate to a non-empty set of groups. For all other
54 requests, acts as the fallback auth service when no other auth
55 middleware overrides it.
56 """42 """
57 token = env.get('HTTP_X_AUTH_TOKEN', env.get('HTTP_X_STORAGE_TOKEN'))43 groups = None
58 if token and token.startswith(self.reseller_prefix):44 if 'SWIFT_GROUPS' in env:
59 # Note: Empty reseller_prefix will match all tokens.45 groups = env['SWIFT_GROUPS']
60 # Attempt to auth my token with my auth server46 env['REMOTE_USER'] = groups
61 groups = \47 self.authorize = self.dev_authorize
62 self.get_groups(token, memcache_client=cache_from_env(env))48 env['swift.clean_acl'] = clean_acl
63 if groups:49 elif 'swift.authorize' not in env:
64 env['REMOTE_USER'] = groups50 self.authorize = self.empty_authorize
65 user = groups and groups.split(',', 1)[0] or ''51
66 # We know the proxy logs the token, so we augment it just a bit52 if self.reseller_prefix:
67 # to also log the authenticated user.53 # With a non-empty reseller_prefix, I would like to be called
68 env['HTTP_X_AUTH_TOKEN'] = '%s,%s' % (user, token)54 # back for anonymous access to accounts I know I'm the
55 # definitive auth for.
56 try:
57 version, rest = split_path(env.get('PATH_INFO', ''),
58 1, 2, True)
59 except ValueError:
60 return HTTPNotFound()(env, start_response)
61 if rest and rest.startswith(self.reseller_prefix):
62 # Handle anonymous access to accounts I'm the definitive
63 # auth for.
69 env['swift.authorize'] = self.authorize64 env['swift.authorize'] = self.authorize
70 env['swift.clean_acl'] = clean_acl65 env['swift.clean_acl'] = clean_acl
71 else:66 # Not my token, not my account, I can't authorize this request,
72 # Unauthorized token67 # deny all is a good idea if not already set...
73 if self.reseller_prefix:
74 # Because I know I'm the definitive auth for this token, I
75 # can deny it outright.
76 return HTTPUnauthorized()(env, start_response)
77 # Because I'm not certain if I'm the definitive auth for empty
78 # reseller_prefixed tokens, I won't overwrite swift.authorize.
79 elif 'swift.authorize' not in env:
80 env['swift.authorize'] = self.denied_response
81 else:
82 if self.reseller_prefix:
83 # With a non-empty reseller_prefix, I would like to be called
84 # back for anonymous access to accounts I know I'm the
85 # definitive auth for.
86 try:
87 version, rest = split_path(env.get('PATH_INFO', ''),
88 1, 2, True)
89 except ValueError:
90 return HTTPNotFound()(env, start_response)
91 if rest and rest.startswith(self.reseller_prefix):
92 # Handle anonymous access to accounts I'm the definitive
93 # auth for.
94 env['swift.authorize'] = self.authorize
95 env['swift.clean_acl'] = clean_acl
96 # Not my token, not my account, I can't authorize this request,
97 # deny all is a good idea if not already set...
98 elif 'swift.authorize' not in env:
99 env['swift.authorize'] = self.denied_response
100 # Because I'm not certain if I'm the definitive auth for empty
101 # reseller_prefixed accounts, I won't overwrite swift.authorize.
102 elif 'swift.authorize' not in env:68 elif 'swift.authorize' not in env:
103 env['swift.authorize'] = self.authorize69 env['swift.authorize'] = self.denied_response
104 env['swift.clean_acl'] = clean_acl70 # Because I'm not certain if I'm the definitive auth for empty
71 # reseller_prefixed accounts, I won't overwrite swift.authorize.
72 elif 'swift.authorize' not in env:
73 env['swift.authorize'] = self.empty_authorize
105 return self.app(env, start_response)74 return self.app(env, start_response)
10675
107 def get_groups(self, token, memcache_client=None):76 def empty_authorize(self, req):
108 """77 if 'x_identity_status' in req.headers:
109 Get groups for the given token.78 if req.headers['x_identity_status'] == 'Invalid':
11079 return self.denied_response(req)
111 If memcache_client is set, token credentials will be cached80 elif req.headers['x_identity_status'] == 'Indeterminate':
112 appropriately.81 return self.dev_authorize(req)
11382 return None
114 With a cache miss, or no memcache_client, the configurated external83
115 authentication server will be queried for the group information.84 def dev_authorize(self, req):
116
117 :param token: Token to validate and return a group string for.
118 :param memcache_client: Memcached client to use for caching token
119 credentials; None if no caching is desired.
120 :returns: None if the token is invalid or a string containing a comma
121 separated list of groups the authenticated user is a member
122 of. The first group in the list is also considered a unique
123 identifier for that user.
124 """
125 groups = None
126 key = '%s/token/%s' % (self.reseller_prefix, token)
127 cached_auth_data = memcache_client and memcache_client.get(key)
128 if cached_auth_data:
129 start, expiration, groups = cached_auth_data
130 if time() - start > expiration:
131 groups = None
132 if not groups:
133 with Timeout(self.timeout):
134 conn = http_connect(self.auth_host, self.auth_port, 'GET',
135 '%stoken/%s' % (self.auth_prefix, token), ssl=self.ssl)
136 resp = conn.getresponse()
137 resp.read()
138 conn.close()
139 if resp.status // 100 != 2:
140 return None
141 expiration = float(resp.getheader('x-auth-ttl'))
142 groups = resp.getheader('x-auth-groups')
143 if memcache_client:
144 memcache_client.set(key, (time(), expiration, groups),
145 timeout=expiration)
146 return groups
147
148 def authorize(self, req):
149 """85 """
150 Returns None if the request is authorized to continue or a standard86 Returns None if the request is authorized to continue or a standard
151 WSGI response callable if not.87 WSGI response callable if not.
@@ -179,10 +115,13 @@
179 Returns a standard WSGI response callable with the status of 403 or 401115 Returns a standard WSGI response callable with the status of 403 or 401
180 depending on whether the REMOTE_USER is set or not.116 depending on whether the REMOTE_USER is set or not.
181 """117 """
118 headers = [('www-authenticate', 'delegated')]
182 if req.remote_user:119 if req.remote_user:
183 return HTTPForbidden(request=req)120 resp = HTTPForbidden(headers=headers, request=req)
184 else:121 else:
185 return HTTPUnauthorized(request=req)122 resp = HTTPUnauthorized(headers=headers, request=req)
123
124 return resp
186125
187126
188def filter_factory(global_conf, **local_conf):127def filter_factory(global_conf, **local_conf):
@@ -191,5 +130,5 @@
191 conf.update(local_conf)130 conf.update(local_conf)
192131
193 def auth_filter(app):132 def auth_filter(app):
194 return DevAuth(app, conf)133 return DevAuthZ(app, conf)
195 return auth_filter134 return auth_filter
196135
=== added file 'swift/common/middleware/papiauth.py'
--- swift/common/middleware/papiauth.py 1970-01-01 00:00:00 +0000
+++ swift/common/middleware/papiauth.py 2011-01-11 20:54:28 +0000
@@ -0,0 +1,62 @@
1# Copyright (c) 2010 OpenStack, LLC.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12# implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16from webob.exc import HTTPUseProxy, HTTPUnauthorized
17
18from swift.common.utils import TRUE_VALUES
19
20
21class PAPIAuth(object):
22 """Auth Middleware that uses the dev auth server."""
23
24 def __init__(self, app, conf):
25 self.app = app
26 self.conf = conf
27 self.reseller_prefix = conf.get('reseller_prefix', 'AUTH').strip()
28 if self.reseller_prefix and self.reseller_prefix[-1] != '_':
29 self.reseller_prefix += '_'
30 self.auth_host = conf.get('ip', '127.0.0.1')
31 self.auth_port = int(conf.get('port', 11000))
32 self.auth_pass = conf.get('pass', 'dTpw')
33 self.ssl = conf.get('ssl', 'false').lower() in TRUE_VALUES
34 self.timeout = int(conf.get('node_timeout', 10))
35
36 def __call__(self, env, start_response):
37 # Make sure that the user has been authenticated by the Auth Service
38 if 'HTTP_X_AUTHORIZATION' not in env:
39 proxy_location = 'http://' + self.auth_host + ':' + \
40 str(self.auth_port) + '/'
41 return HTTPUseProxy(location=proxy_location)(env, start_response)
42
43 # Authenticate the Auth component itself.
44 headers = [('www-authenticate', 'Basic realm="swift"')]
45 if 'HTTP_AUTHORIZATION' not in env:
46 return HTTPUnauthorized(headers=headers)(env, start_response)
47 else:
48 auth_type, encoded_creds = env['HTTP_AUTHORIZATION'].split(None, 1)
49 if encoded_creds != self.auth_pass:
50 return HTTPUnauthorized(headers=headers)(env, start_response)
51
52 return self.app(env, start_response)
53
54
55def filter_factory(global_conf, **local_conf):
56 """Returns a WSGI filter app for use with paste.deploy."""
57 conf = global_conf.copy()
58 conf.update(local_conf)
59
60 def auth_filter(app):
61 return PAPIAuth(app, conf)
62 return auth_filter
063
=== modified file 'test/unit/common/middleware/test_auth.py'
--- test/unit/common/middleware/test_auth.py 2011-01-05 16:14:31 +0000
+++ test/unit/common/middleware/test_auth.py 2011-01-11 20:54:28 +0000
@@ -23,7 +23,7 @@
23import eventlet23import eventlet
24from webob import Request24from webob import Request
2525
26from swift.common.middleware import auth26from swift.common.middleware import devauthn, devauthz, papiauth
2727
28# mocks28# mocks
29logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))29logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))
@@ -122,243 +122,281 @@
122class TestAuth(unittest.TestCase):122class TestAuth(unittest.TestCase):
123123
124 def setUp(self):124 def setUp(self):
125 self.test_auth = auth.filter_factory({})(FakeApp())125 self.test_authn = devauthn.filter_factory({})(FakeApp())
126 self.test_authz = devauthz.filter_factory({})(FakeApp())
127 self.test_papiauth = papiauth.filter_factory({})(FakeApp())
126128
127 def test_auth_deny_non_reseller_prefix(self):129 def test_auth_deny_non_reseller_prefix(self):
128 old_http_connect = auth.http_connect130 reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/BLAH_account',
129 try:131 'HTTP_X_AUTH_TOKEN': 'BLAH_t', 'swift.cache': FakeMemcache()}
130 auth.http_connect = mock_http_connect(204,132 result = ''.join(self.test_authz(reqenv, lambda x, y: None))
131 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})133 self.assert_(result.startswith('401'), result)
132 reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/BLAH_account',134 self.assertEquals(reqenv['swift.authorize'],
133 'HTTP_X_AUTH_TOKEN': 'BLAH_t', 'swift.cache': FakeMemcache()}135 self.test_authz.denied_response)
134 result = ''.join(self.test_auth(reqenv, lambda x, y: None))
135 self.assert_(result.startswith('401'), result)
136 self.assertEquals(reqenv['swift.authorize'],
137 self.test_auth.denied_response)
138 finally:
139 auth.http_connect = old_http_connect
140136
141 def test_auth_deny_non_reseller_prefix_no_override(self):137 def test_auth_deny_non_reseller_prefix_no_override(self):
142 old_http_connect = auth.http_connect138 old_http_connect = devauthn.http_connect
143 try:139 try:
144 auth.http_connect = mock_http_connect(204,140 local_app = FakeApp()
141 local_authz = \
142 devauthz.filter_factory({'reseller_prefix': ''})(local_app)
143 local_authn = \
144 devauthn.filter_factory({'delegated': 1})(local_authz)
145 devauthn.http_connect = mock_http_connect(204,
145 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})146 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})
146 fake_authorize = lambda x: lambda x, y: ['500 Fake']147 fake_authorize = lambda x: lambda x, y: ['500 Fake']
147 reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/BLAH_account',148 reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/BLAH_account',
148 'HTTP_X_AUTH_TOKEN': 'BLAH_t', 'swift.cache': FakeMemcache(),149 'HTTP_X_AUTH_TOKEN': 'BLAH_t', 'swift.cache': FakeMemcache(),
149 'swift.authorize': fake_authorize}150 'swift.authorize': fake_authorize}
150 result = ''.join(self.test_auth(reqenv, lambda x, y: None))151 result = ''.join(local_authn(reqenv, lambda x, y: None))
151 self.assert_(result.startswith('500 Fake'), result)152 self.assert_(result.startswith('500 Fake'), result)
152 self.assertEquals(reqenv['swift.authorize'], fake_authorize)153 self.assertEquals(reqenv['swift.authorize'], fake_authorize)
153 finally:154 finally:
154 auth.http_connect = old_http_connect155 devauthn.http_connect = old_http_connect
155156
156 def test_auth_no_reseller_prefix_deny(self):157 def test_auth_no_reseller_prefix_deny_delegated(self):
157 # Ensures that when we have no reseller prefix, we don't deny a request158 # Ensures that when we have no reseller prefix, we don't deny a request
158 # outright but set up a denial swift.authorize and pass the request on159 # outright but set up a denial swift.authorize and pass the request on
159 # down the chain.160 # down the chain.
160 old_http_connect = auth.http_connect161 old_http_connect = devauthn.http_connect
161 try:162 try:
162 local_app = FakeApp()163 local_app = FakeApp()
163 local_auth = \164 local_authz = \
164 auth.filter_factory({'reseller_prefix': ''})(local_app)165 devauthz.filter_factory({'reseller_prefix': ''})(local_app)
165 auth.http_connect = mock_http_connect(404)166 local_authn = \
167 devauthn.filter_factory(\
168 {'reseller_prefix': '', 'delegated': 1})(local_authz)
169 devauthn.http_connect = mock_http_connect(404)
166 reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/account',170 reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/account',
167 'HTTP_X_AUTH_TOKEN': 't', 'swift.cache': FakeMemcache()}171 'HTTP_X_AUTH_TOKEN': 't', 'swift.cache': FakeMemcache()}
168 result = ''.join(local_auth(reqenv, lambda x, y: None))172 result = ''.join(local_authn(reqenv, lambda x, y: None))
169 self.assert_(result.startswith('401'), result)173 self.assert_(result.startswith('401'), result)
170 self.assert_(local_app.i_was_called)174 self.assert_(local_app.i_was_called)
171 self.assertEquals(reqenv['swift.authorize'],175 self.assertEquals(reqenv['swift.authorize'],
172 local_auth.denied_response)176 local_authz.empty_authorize)
173 finally:177 finally:
174 auth.http_connect = old_http_connect178 devauthn.http_connect = old_http_connect
179
180 def test_auth_no_reseller_prefix_deny_non_delegated(self):
181 # Ensures that when we have no reseller prefix, we don't deny a request
182 # outright but set up a denial swift.authorize and pass the request on
183 # down the chain.
184 old_http_connect = devauthn.http_connect
185 try:
186 local_app = FakeApp()
187 local_authn = \
188 devauthn.filter_factory(\
189 {'reseller_prefix': ''})(local_app)
190 devauthn.http_connect = mock_http_connect(404)
191 reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/account',
192 'HTTP_X_AUTH_TOKEN': 't', 'swift.cache': FakeMemcache()}
193 result = ''.join(local_authn(reqenv, lambda x, y: None))
194 self.assert_(result.startswith('401'), result)
195 self.assert_(not local_app.i_was_called)
196 finally:
197 devauthn.http_connect = old_http_connect
198
175199
176 def test_auth_no_reseller_prefix_allow(self):200 def test_auth_no_reseller_prefix_allow(self):
177 # Ensures that when we have no reseller prefix, we can still allow201 # Ensures that when we have no reseller prefix, we can still allow
178 # access if our auth server accepts requests202 # access if our auth server accepts requests
179 old_http_connect = auth.http_connect203 local_app = FakeApp()
180 try:204 local_auth = \
181 local_app = FakeApp()205 devauthz.filter_factory({'reseller_prefix': ''})(local_app)
182 local_auth = \206 reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/act',
183 auth.filter_factory({'reseller_prefix': ''})(local_app)207 'HTTP_X_AUTH_TOKEN': 't', 'swift.cache': None,
184 auth.http_connect = mock_http_connect(204,208 'SWIFT_GROUPS': 'act:usr,act,AUTH_cfa'}
185 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})209 result = ''.join(local_auth(reqenv, lambda x, y: None))
186 reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/act',210 self.assert_(result.startswith('204'), result)
187 'HTTP_X_AUTH_TOKEN': 't', 'swift.cache': None}211 self.assert_(local_app.i_was_called)
188 result = ''.join(local_auth(reqenv, lambda x, y: None))212 self.assertEquals(reqenv['swift.authorize'],
189 self.assert_(result.startswith('204'), result)213 local_auth.empty_authorize)
190 self.assert_(local_app.i_was_called)
191 self.assertEquals(reqenv['swift.authorize'],
192 local_auth.authorize)
193 finally:
194 auth.http_connect = old_http_connect
195214
196 def test_auth_no_reseller_prefix_no_token(self):215 def test_auth_no_reseller_prefix_no_token_delegated(self):
197 # Check that normally we set up a call back to our authorize.216 # Check that normally we set up a call back to our authorize.
198 local_auth = \217 local_authz = \
199 auth.filter_factory({'reseller_prefix': ''})(FakeApp())218 devauthz.filter_factory({'reseller_prefix': ''})(FakeApp())
219 local_authn = \
220 devauthn.filter_factory(\
221 {'reseller_prefix': '', 'delegated':1})(local_authz)
200 reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/account',222 reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/account',
201 'swift.cache': FakeMemcache()}223 'swift.cache': FakeMemcache()}
202 result = ''.join(local_auth(reqenv, lambda x, y: None))224 result = ''.join(local_authn(reqenv, lambda x, y: None))
203 self.assert_(result.startswith('401'), result)225 self.assert_(result.startswith('401'), result)
204 self.assertEquals(reqenv['swift.authorize'], local_auth.authorize)226 self.assertEquals(\
227 reqenv['swift.authorize'], local_authz.empty_authorize)
205 # Now make sure we don't override an existing swift.authorize when we228 # Now make sure we don't override an existing swift.authorize when we
206 # have no reseller prefix.229 # have no reseller prefix.
207 local_authorize = lambda req: None230 local_authorize = lambda req: None
208 reqenv['swift.authorize'] = local_authorize231 reqenv['swift.authorize'] = local_authorize
209 result = ''.join(local_auth(reqenv, lambda x, y: None))232 result = ''.join(local_authz(reqenv, lambda x, y: None))
210 self.assert_(result.startswith('204'), result)233 self.assert_(result.startswith('204'), result)
211 self.assertEquals(reqenv['swift.authorize'], local_authorize)234 self.assertEquals(reqenv['swift.authorize'], local_authorize)
212235
236 def test_auth_no_reseller_prefix_no_token_non_delegated(self):
237 # Ensure that in a non_delegated mode, no token gets denied
238 # right away.
239 local_app = FakeApp()
240 local_authn = \
241 devauthn.filter_factory(\
242 {'reseller_prefix': ''})(local_app)
243 reqenv = {'REQUEST_METHOD': 'GET', 'PATH_INFO': '/v1/account',
244 'swift.cache': FakeMemcache()}
245 result = ''.join(local_authn(reqenv, lambda x, y: None))
246 self.assert_(result.startswith('401'), result)
247 self.assert_(not local_app.i_was_called)
248
213 def test_auth_fail(self):249 def test_auth_fail(self):
214 old_http_connect = auth.http_connect250 old_http_connect = devauthn.http_connect
215 try:251 try:
216 auth.http_connect = mock_http_connect(404)252 devauthn.http_connect = mock_http_connect(404)
217 result = ''.join(self.test_auth({'REQUEST_METHOD': 'GET',253 result = ''.join(self.test_authn({'REQUEST_METHOD': 'GET',
218 'HTTP_X_AUTH_TOKEN': 'AUTH_t', 'swift.cache': FakeMemcache()},254 'HTTP_X_AUTH_TOKEN': 'AUTH_t', 'swift.cache': FakeMemcache()},
219 lambda x, y: None))255 lambda x, y: None))
220 self.assert_(result.startswith('401'), result)256 self.assert_(result.startswith('401'), result)
221 finally:257 finally:
222 auth.http_connect = old_http_connect258 devauthn.http_connect = old_http_connect
223259
224 def test_auth_success(self):260 def test_auth_success(self):
225 old_http_connect = auth.http_connect261 old_http_connect = devauthn.http_connect
226 try:262 try:
227 auth.http_connect = mock_http_connect(204,263 devauthn.http_connect = mock_http_connect(204,
228 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})264 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})
229 result = ''.join(self.test_auth({'REQUEST_METHOD': 'GET',265 result = ''.join(self.test_authn({'REQUEST_METHOD': 'GET',
230 'PATH_INFO': '/v/AUTH_cfa', 'HTTP_X_AUTH_TOKEN': 'AUTH_t',266 'PATH_INFO': '/v/AUTH_cfa', 'HTTP_X_AUTH_TOKEN': 'AUTH_t',
231 'swift.cache': FakeMemcache()}, lambda x, y: None))267 'swift.cache': FakeMemcache()}, lambda x, y: None))
232 self.assert_(result.startswith('204'), result)268 self.assert_(result.startswith('204'), result)
233 finally:269 finally:
234 auth.http_connect = old_http_connect270 devauthn.http_connect = old_http_connect
235271
236 def test_auth_memcache(self):272 def test_auth_memcache(self):
237 old_http_connect = auth.http_connect273 old_http_connect = devauthn.http_connect
238 try:274 try:
239 fake_memcache = FakeMemcache()275 fake_memcache = FakeMemcache()
240 auth.http_connect = mock_http_connect(204,276 devauthn.http_connect = mock_http_connect(204,
241 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})277 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})
242 result = ''.join(self.test_auth({'REQUEST_METHOD': 'GET',278 result = ''.join(self.test_authn({'REQUEST_METHOD': 'GET',
243 'PATH_INFO': '/v/AUTH_cfa', 'HTTP_X_AUTH_TOKEN': 'AUTH_t',279 'PATH_INFO': '/v/AUTH_cfa', 'HTTP_X_AUTH_TOKEN': 'AUTH_t',
244 'swift.cache': fake_memcache}, lambda x, y: None))280 'swift.cache': fake_memcache}, lambda x, y: None))
245 self.assert_(result.startswith('204'), result)281 self.assert_(result.startswith('204'), result)
246 auth.http_connect = mock_http_connect(404)282 devauthn.http_connect = mock_http_connect(404)
247 # Should still be in memcache283 # Should still be in memcache
248 result = ''.join(self.test_auth({'REQUEST_METHOD': 'GET',284 result = ''.join(self.test_authn({'REQUEST_METHOD': 'GET',
249 'PATH_INFO': '/v/AUTH_cfa', 'HTTP_X_AUTH_TOKEN': 'AUTH_t',285 'PATH_INFO': '/v/AUTH_cfa', 'HTTP_X_AUTH_TOKEN': 'AUTH_t',
250 'swift.cache': fake_memcache}, lambda x, y: None))286 'swift.cache': fake_memcache}, lambda x, y: None))
251 self.assert_(result.startswith('204'), result)287 self.assert_(result.startswith('204'), result)
252 finally:288 finally:
253 auth.http_connect = old_http_connect289 devauthn.http_connect = old_http_connect
254290
255 def test_auth_just_expired(self):291 def test_auth_just_expired(self):
256 old_http_connect = auth.http_connect292 old_http_connect = devauthn.http_connect
257 try:293 try:
258 fake_memcache = FakeMemcache()294 fake_memcache = FakeMemcache()
259 auth.http_connect = mock_http_connect(204,295 devauthn.http_connect = mock_http_connect(204,
260 {'x-auth-ttl': '0', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})296 {'x-auth-ttl': '0', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})
261 result = ''.join(self.test_auth({'REQUEST_METHOD': 'GET',297 result = ''.join(self.test_authn({'REQUEST_METHOD': 'GET',
262 'PATH_INFO': '/v/AUTH_cfa', 'HTTP_X_AUTH_TOKEN': 'AUTH_t',298 'PATH_INFO': '/v/AUTH_cfa', 'HTTP_X_AUTH_TOKEN': 'AUTH_t',
263 'swift.cache': fake_memcache}, lambda x, y: None))299 'swift.cache': fake_memcache}, lambda x, y: None))
264 self.assert_(result.startswith('204'), result)300 self.assert_(result.startswith('204'), result)
265 auth.http_connect = mock_http_connect(404)301 devauthn.http_connect = mock_http_connect(404)
266 # Should still be in memcache, but expired302 # Should still be in memcache, but expired
267 result = ''.join(self.test_auth({'REQUEST_METHOD': 'GET',303 result = ''.join(self.test_authn({'REQUEST_METHOD': 'GET',
268 'HTTP_X_AUTH_TOKEN': 'AUTH_t', 'swift.cache': fake_memcache},304 'HTTP_X_AUTH_TOKEN': 'AUTH_t', 'swift.cache': fake_memcache},
269 lambda x, y: None))305 lambda x, y: None))
270 self.assert_(result.startswith('401'), result)306 self.assert_(result.startswith('401'), result)
271 finally:307 finally:
272 auth.http_connect = old_http_connect308 devauthn.http_connect = old_http_connect
273309
274 def test_middleware_success(self):310 def test_middleware_success(self):
275 old_http_connect = auth.http_connect311 old_http_connect = devauthn.http_connect
276 try:312 try:
277 auth.http_connect = mock_http_connect(204,313 devauthn.http_connect = mock_http_connect(204,
278 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})314 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})
279 req = Request.blank('/v/AUTH_cfa/c/o',315 req = Request.blank('/v/AUTH_cfa/c/o',
280 headers={'x-auth-token': 'AUTH_t'})316 headers={'x-auth-token': 'AUTH_t'})
281 req.environ['swift.cache'] = FakeMemcache()317 req.environ['swift.cache'] = FakeMemcache()
282 result = ''.join(self.test_auth(req.environ, start_response))318 result = ''.join(self.test_authn(req.environ, start_response))
283 self.assert_(result.startswith('204'), result)319 self.assert_(result.startswith('204'), result)
284 self.assertEquals(req.remote_user, 'act:usr,act,AUTH_cfa')320 self.assertEquals(\
321 req.environ['SWIFT_GROUPS'], 'act:usr,act,AUTH_cfa')
285 finally:322 finally:
286 auth.http_connect = old_http_connect323 devauthn.http_connect = old_http_connect
287324
288 def test_middleware_no_header(self):325 def test_middleware_no_header(self):
289 old_http_connect = auth.http_connect326 old_http_connect = devauthn.http_connect
290 try:327 try:
291 auth.http_connect = mock_http_connect(204,328 devauthn.http_connect = mock_http_connect(204,
292 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})329 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})
293 req = Request.blank('/v/AUTH_cfa/c/o')330 req = Request.blank('/v/AUTH_cfa/c/o')
294 req.environ['swift.cache'] = FakeMemcache()331 req.environ['swift.cache'] = FakeMemcache()
295 result = ''.join(self.test_auth(req.environ, start_response))332 result = ''.join(self.test_authn(req.environ, start_response))
296 self.assert_(result.startswith('401'), result)333 self.assert_(result.startswith('401'), result)
297 self.assert_(not req.remote_user, req.remote_user)334 self.assert_(not req.remote_user, req.remote_user)
298 finally:335 finally:
299 auth.http_connect = old_http_connect336 devauthn.http_connect = old_http_connect
300337
301 def test_middleware_storage_token(self):338 def test_middleware_storage_token(self):
302 old_http_connect = auth.http_connect339 old_http_connect = devauthn.http_connect
303 try:340 try:
304 auth.http_connect = mock_http_connect(204,341 devauthn.http_connect = mock_http_connect(204,
305 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})342 {'x-auth-ttl': '1234', 'x-auth-groups': 'act:usr,act,AUTH_cfa'})
306 req = Request.blank('/v/AUTH_cfa/c/o',343 req = Request.blank('/v/AUTH_cfa/c/o',
307 headers={'x-storage-token': 'AUTH_t'})344 headers={'x-storage-token': 'AUTH_t'})
308 req.environ['swift.cache'] = FakeMemcache()345 req.environ['swift.cache'] = FakeMemcache()
309 result = ''.join(self.test_auth(req.environ, start_response))346 result = ''.join(self.test_authn(req.environ, start_response))
310 self.assert_(result.startswith('204'), result)347 self.assert_(result.startswith('204'), result)
311 self.assertEquals(req.remote_user, 'act:usr,act,AUTH_cfa')348 self.assertEquals(\
349 req.environ['SWIFT_GROUPS'], 'act:usr,act,AUTH_cfa')
312 finally:350 finally:
313 auth.http_connect = old_http_connect351 devauthn.http_connect = old_http_connect
314352
315 def test_authorize_bad_path(self):353 def test_authorize_bad_path(self):
316 req = Request.blank('/badpath')354 req = Request.blank('/badpath')
317 resp = self.test_auth.authorize(req)355 resp = self.test_authz.dev_authorize(req)
318 self.assertEquals(resp and resp.status_int, 401)356 self.assertEquals(resp and resp.status_int, 401)
319 req = Request.blank('/badpath')357 req = Request.blank('/badpath')
320 req.remote_user = 'act:usr,act,AUTH_cfa'358 req.remote_user = 'act:usr,act,AUTH_cfa'
321 resp = self.test_auth.authorize(req)359 resp = self.test_authz.dev_authorize(req)
322 self.assertEquals(resp and resp.status_int, 403)360 self.assertEquals(resp and resp.status_int, 403)
323 req = Request.blank('')361 req = Request.blank('')
324 resp = self.test_auth.authorize(req)362 resp = self.test_authz.dev_authorize(req)
325 self.assertEquals(resp and resp.status_int, 404)363 self.assertEquals(resp and resp.status_int, 404)
326 req = Request.blank('')364 req = Request.blank('')
327 req.environ['swift.cache'] = FakeMemcache()365 req.environ['swift.cache'] = FakeMemcache()
328 result = ''.join(self.test_auth(req.environ, lambda x, y: None))366 result = ''.join(self.test_authz(req.environ, lambda x, y: None))
329 self.assert_(result.startswith('404'), result)367 self.assert_(result.startswith('404'), result)
330368
331 def test_authorize_account_access(self):369 def test_authorize_account_access(self):
332 req = Request.blank('/v1/AUTH_cfa')370 req = Request.blank('/v1/AUTH_cfa')
333 req.remote_user = 'act:usr,act,AUTH_cfa'371 req.remote_user = 'act:usr,act,AUTH_cfa'
334 self.assertEquals(self.test_auth.authorize(req), None)372 self.assertEquals(self.test_authz.dev_authorize(req), None)
335 req = Request.blank('/v1/AUTH_cfa')373 req = Request.blank('/v1/AUTH_cfa')
336 req.remote_user = 'act:usr,act'374 req.remote_user = 'act:usr,act'
337 resp = self.test_auth.authorize(req)375 resp = self.test_authz.dev_authorize(req)
338 self.assertEquals(resp and resp.status_int, 403)376 self.assertEquals(resp and resp.status_int, 403)
339377
340 def test_authorize_acl_group_access(self):378 def test_authorize_acl_group_access(self):
341 req = Request.blank('/v1/AUTH_cfa')379 req = Request.blank('/v1/AUTH_cfa')
342 req.remote_user = 'act:usr,act'380 req.remote_user = 'act:usr,act'
343 resp = self.test_auth.authorize(req)381 resp = self.test_authz.dev_authorize(req)
344 self.assertEquals(resp and resp.status_int, 403)382 self.assertEquals(resp and resp.status_int, 403)
345 req = Request.blank('/v1/AUTH_cfa')383 req = Request.blank('/v1/AUTH_cfa')
346 req.remote_user = 'act:usr,act'384 req.remote_user = 'act:usr,act'
347 req.acl = 'act'385 req.acl = 'act'
348 self.assertEquals(self.test_auth.authorize(req), None)386 self.assertEquals(self.test_authz.dev_authorize(req), None)
349 req = Request.blank('/v1/AUTH_cfa')387 req = Request.blank('/v1/AUTH_cfa')
350 req.remote_user = 'act:usr,act'388 req.remote_user = 'act:usr,act'
351 req.acl = 'act:usr'389 req.acl = 'act:usr'
352 self.assertEquals(self.test_auth.authorize(req), None)390 self.assertEquals(self.test_authz.dev_authorize(req), None)
353 req = Request.blank('/v1/AUTH_cfa')391 req = Request.blank('/v1/AUTH_cfa')
354 req.remote_user = 'act:usr,act'392 req.remote_user = 'act:usr,act'
355 req.acl = 'act2'393 req.acl = 'act2'
356 resp = self.test_auth.authorize(req)394 resp = self.test_authz.dev_authorize(req)
357 self.assertEquals(resp and resp.status_int, 403)395 self.assertEquals(resp and resp.status_int, 403)
358 req = Request.blank('/v1/AUTH_cfa')396 req = Request.blank('/v1/AUTH_cfa')
359 req.remote_user = 'act:usr,act'397 req.remote_user = 'act:usr,act'
360 req.acl = 'act:usr2'398 req.acl = 'act:usr2'
361 resp = self.test_auth.authorize(req)399 resp = self.test_authz.dev_authorize(req)
362 self.assertEquals(resp and resp.status_int, 403)400 self.assertEquals(resp and resp.status_int, 403)
363401
364 def test_deny_cross_reseller(self):402 def test_deny_cross_reseller(self):
@@ -366,96 +404,96 @@
366 req = Request.blank('/v1/OTHER_cfa')404 req = Request.blank('/v1/OTHER_cfa')
367 req.remote_user = 'act:usr,act,AUTH_cfa'405 req.remote_user = 'act:usr,act,AUTH_cfa'
368 req.acl = 'act'406 req.acl = 'act'
369 resp = self.test_auth.authorize(req)407 resp = self.test_authz.dev_authorize(req)
370 self.assertEquals(resp and resp.status_int, 403)408 self.assertEquals(resp and resp.status_int, 403)
371409
372 def test_authorize_acl_referrer_access(self):410 def test_authorize_acl_referrer_access(self):
373 req = Request.blank('/v1/AUTH_cfa')411 req = Request.blank('/v1/AUTH_cfa')
374 req.remote_user = 'act:usr,act'412 req.remote_user = 'act:usr,act'
375 resp = self.test_auth.authorize(req)413 resp = self.test_authz.dev_authorize(req)
376 self.assertEquals(resp and resp.status_int, 403)414 self.assertEquals(resp and resp.status_int, 403)
377 req = Request.blank('/v1/AUTH_cfa')415 req = Request.blank('/v1/AUTH_cfa')
378 req.remote_user = 'act:usr,act'416 req.remote_user = 'act:usr,act'
379 req.acl = '.r:*'417 req.acl = '.r:*'
380 self.assertEquals(self.test_auth.authorize(req), None)418 self.assertEquals(self.test_authz.dev_authorize(req), None)
381 req = Request.blank('/v1/AUTH_cfa')419 req = Request.blank('/v1/AUTH_cfa')
382 req.remote_user = 'act:usr,act'420 req.remote_user = 'act:usr,act'
383 req.acl = '.r:.example.com'421 req.acl = '.r:.example.com'
384 resp = self.test_auth.authorize(req)422 resp = self.test_authz.dev_authorize(req)
385 self.assertEquals(resp and resp.status_int, 403)423 self.assertEquals(resp and resp.status_int, 403)
386 req = Request.blank('/v1/AUTH_cfa')424 req = Request.blank('/v1/AUTH_cfa')
387 req.remote_user = 'act:usr,act'425 req.remote_user = 'act:usr,act'
388 req.referer = 'http://www.example.com/index.html'426 req.referer = 'http://www.example.com/index.html'
389 req.acl = '.r:.example.com'427 req.acl = '.r:.example.com'
390 self.assertEquals(self.test_auth.authorize(req), None)428 self.assertEquals(self.test_authz.dev_authorize(req), None)
391 req = Request.blank('/v1/AUTH_cfa')429 req = Request.blank('/v1/AUTH_cfa')
392 resp = self.test_auth.authorize(req)430 resp = self.test_authz.dev_authorize(req)
393 self.assertEquals(resp and resp.status_int, 401)431 self.assertEquals(resp and resp.status_int, 401)
394 req = Request.blank('/v1/AUTH_cfa')432 req = Request.blank('/v1/AUTH_cfa')
395 req.acl = '.r:*'433 req.acl = '.r:*'
396 self.assertEquals(self.test_auth.authorize(req), None)434 self.assertEquals(self.test_authz.dev_authorize(req), None)
397 req = Request.blank('/v1/AUTH_cfa')435 req = Request.blank('/v1/AUTH_cfa')
398 req.acl = '.r:.example.com'436 req.acl = '.r:.example.com'
399 resp = self.test_auth.authorize(req)437 resp = self.test_authz.dev_authorize(req)
400 self.assertEquals(resp and resp.status_int, 401)438 self.assertEquals(resp and resp.status_int, 401)
401 req = Request.blank('/v1/AUTH_cfa')439 req = Request.blank('/v1/AUTH_cfa')
402 req.referer = 'http://www.example.com/index.html'440 req.referer = 'http://www.example.com/index.html'
403 req.acl = '.r:.example.com'441 req.acl = '.r:.example.com'
404 self.assertEquals(self.test_auth.authorize(req), None)442 self.assertEquals(self.test_authz.dev_authorize(req), None)
405443
406 def test_account_put_permissions(self):444 def test_account_put_permissions(self):
407 req = Request.blank('/v1/AUTH_new', environ={'REQUEST_METHOD': 'PUT'})445 req = Request.blank('/v1/AUTH_new', environ={'REQUEST_METHOD': 'PUT'})
408 req.remote_user = 'act:usr,act'446 req.remote_user = 'act:usr,act'
409 resp = self.test_auth.authorize(req)447 resp = self.test_authz.dev_authorize(req)
410 self.assertEquals(resp and resp.status_int, 403)448 self.assertEquals(resp and resp.status_int, 403)
411449
412 req = Request.blank('/v1/AUTH_new', environ={'REQUEST_METHOD': 'PUT'})450 req = Request.blank('/v1/AUTH_new', environ={'REQUEST_METHOD': 'PUT'})
413 req.remote_user = 'act:usr,act,AUTH_other'451 req.remote_user = 'act:usr,act,AUTH_other'
414 resp = self.test_auth.authorize(req)452 resp = self.test_authz.dev_authorize(req)
415 self.assertEquals(resp and resp.status_int, 403)453 self.assertEquals(resp and resp.status_int, 403)
416454
417 # Even PUTs to your own account as account admin should fail455 # Even PUTs to your own account as account admin should fail
418 req = Request.blank('/v1/AUTH_old', environ={'REQUEST_METHOD': 'PUT'})456 req = Request.blank('/v1/AUTH_old', environ={'REQUEST_METHOD': 'PUT'})
419 req.remote_user = 'act:usr,act,AUTH_old'457 req.remote_user = 'act:usr,act,AUTH_old'
420 resp = self.test_auth.authorize(req)458 resp = self.test_authz.dev_authorize(req)
421 self.assertEquals(resp and resp.status_int, 403)459 self.assertEquals(resp and resp.status_int, 403)
422460
423 req = Request.blank('/v1/AUTH_new', environ={'REQUEST_METHOD': 'PUT'})461 req = Request.blank('/v1/AUTH_new', environ={'REQUEST_METHOD': 'PUT'})
424 req.remote_user = 'act:usr,act,.reseller_admin'462 req.remote_user = 'act:usr,act,.reseller_admin'
425 resp = self.test_auth.authorize(req)463 resp = self.test_authz.dev_authorize(req)
426 self.assertEquals(resp, None)464 self.assertEquals(resp, None)
427465
428 # .super_admin is not something the middleware should ever see or care466 # .super_admin is not something the middleware should ever see or care
429 # about467 # about
430 req = Request.blank('/v1/AUTH_new', environ={'REQUEST_METHOD': 'PUT'})468 req = Request.blank('/v1/AUTH_new', environ={'REQUEST_METHOD': 'PUT'})
431 req.remote_user = 'act:usr,act,.super_admin'469 req.remote_user = 'act:usr,act,.super_admin'
432 resp = self.test_auth.authorize(req)470 resp = self.test_authz.dev_authorize(req)
433 self.assertEquals(resp and resp.status_int, 403)471 self.assertEquals(resp and resp.status_int, 403)
434472
435 def test_account_delete_permissions(self):473 def test_account_delete_permissions(self):
436 req = Request.blank('/v1/AUTH_new',474 req = Request.blank('/v1/AUTH_new',
437 environ={'REQUEST_METHOD': 'DELETE'})475 environ={'REQUEST_METHOD': 'DELETE'})
438 req.remote_user = 'act:usr,act'476 req.remote_user = 'act:usr,act'
439 resp = self.test_auth.authorize(req)477 resp = self.test_authz.dev_authorize(req)
440 self.assertEquals(resp and resp.status_int, 403)478 self.assertEquals(resp and resp.status_int, 403)
441479
442 req = Request.blank('/v1/AUTH_new',480 req = Request.blank('/v1/AUTH_new',
443 environ={'REQUEST_METHOD': 'DELETE'})481 environ={'REQUEST_METHOD': 'DELETE'})
444 req.remote_user = 'act:usr,act,AUTH_other'482 req.remote_user = 'act:usr,act,AUTH_other'
445 resp = self.test_auth.authorize(req)483 resp = self.test_authz.dev_authorize(req)
446 self.assertEquals(resp and resp.status_int, 403)484 self.assertEquals(resp and resp.status_int, 403)
447485
448 # Even DELETEs to your own account as account admin should fail486 # Even DELETEs to your own account as account admin should fail
449 req = Request.blank('/v1/AUTH_old',487 req = Request.blank('/v1/AUTH_old',
450 environ={'REQUEST_METHOD': 'DELETE'})488 environ={'REQUEST_METHOD': 'DELETE'})
451 req.remote_user = 'act:usr,act,AUTH_old'489 req.remote_user = 'act:usr,act,AUTH_old'
452 resp = self.test_auth.authorize(req)490 resp = self.test_authz.dev_authorize(req)
453 self.assertEquals(resp and resp.status_int, 403)491 self.assertEquals(resp and resp.status_int, 403)
454492
455 req = Request.blank('/v1/AUTH_new',493 req = Request.blank('/v1/AUTH_new',
456 environ={'REQUEST_METHOD': 'DELETE'})494 environ={'REQUEST_METHOD': 'DELETE'})
457 req.remote_user = 'act:usr,act,.reseller_admin'495 req.remote_user = 'act:usr,act,.reseller_admin'
458 resp = self.test_auth.authorize(req)496 resp = self.test_authz.dev_authorize(req)
459 self.assertEquals(resp, None)497 self.assertEquals(resp, None)
460498
461 # .super_admin is not something the middleware should ever see or care499 # .super_admin is not something the middleware should ever see or care
@@ -463,7 +501,7 @@
463 req = Request.blank('/v1/AUTH_new',501 req = Request.blank('/v1/AUTH_new',
464 environ={'REQUEST_METHOD': 'DELETE'})502 environ={'REQUEST_METHOD': 'DELETE'})
465 req.remote_user = 'act:usr,act,.super_admin'503 req.remote_user = 'act:usr,act,.super_admin'
466 resp = self.test_auth.authorize(req)504 resp = self.test_authz.dev_authorize(req)
467 self.assertEquals(resp and resp.status_int, 403)505 self.assertEquals(resp and resp.status_int, 403)
468506
469507