diff options
| author | Ziad Sawalha <github@highbridgellc.com> | 2011-08-11 02:03:26 -0500 |
|---|---|---|
| committer | Ziad Sawalha <github@highbridgellc.com> | 2011-08-11 02:41:57 -0500 |
| commit | d52cde680b2e968c60f59638ada9f651b4b4cab2 (patch) | |
| tree | 60af19d0d81761ada25f4535ca2f7535ae32f7e4 | |
| parent | b1fd6aac34a2e96d7e71f307f31f40fa3bf3fac1 (diff) | |
| download | keystone-d52cde680b2e968c60f59638ada9f651b4b4cab2.tar.gz keystone-d52cde680b2e968c60f59638ada9f651b4b4cab2.tar.xz keystone-d52cde680b2e968c60f59638ada9f651b4b4cab2.zip | |
Correct 401, 305, and www-authenticate responses
Change-Id: I6205567e7b68917d5ecabcf336a4891802ab7381
Fixing memcache issues.Fixing pep8 changes.
Change-Id: I4e941efec2fad4b945481072b43334bf6477580f
| -rw-r--r-- | examples/echo/echo/echo.ini | 1 | ||||
| -rw-r--r-- | examples/echo/echo/echo_remote.ini | 2 | ||||
| -rw-r--r-- | examples/paste/auth_token.ini | 3 | ||||
| -rw-r--r-- | examples/paste/glance-api.conf | 1 | ||||
| -rw-r--r-- | examples/paste/glance-registry.conf | 1 | ||||
| -rw-r--r-- | examples/paste/nova-api-paste.ini | 1 | ||||
| -rwxr-xr-x | keystone/backends/memcache/api/token.py | 34 | ||||
| -rwxr-xr-x | keystone/middleware/auth_token.py | 40 | ||||
| -rw-r--r-- | keystone/middleware/remoteauth.py | 12 | ||||
| -rwxr-xr-x | run_tests.py | 2 |
10 files changed, 66 insertions, 31 deletions
diff --git a/examples/echo/echo/echo.ini b/examples/echo/echo/echo.ini index aecb3f4b..b5647601 100644 --- a/examples/echo/echo/echo.ini +++ b/examples/echo/echo/echo.ini @@ -25,6 +25,7 @@ paste.filter_factory = keystone.middleware.auth_token:filter_factory auth_host = 127.0.0.1 auth_port = 5001 auth_protocol = http +auth_uri = http://localhost:5000/ ;how to authenticate to the auth service for priviledged operations ;like validate token admin_token = 999888777666 diff --git a/examples/echo/echo/echo_remote.ini b/examples/echo/echo/echo_remote.ini index a429485d..ba5e4610 100644 --- a/examples/echo/echo/echo_remote.ini +++ b/examples/echo/echo/echo_remote.ini @@ -14,6 +14,6 @@ paste.filter_factory = keystone.middleware.remoteauth:filter_factory ; (otherwise we redirect call) remote_auth_pass = dTpw ;where to redirect untrusted calls to -auth_location = http://127.0.0.1:5001/ +proxy_location = http://127.0.0.1:8090/ diff --git a/examples/paste/auth_token.ini b/examples/paste/auth_token.ini index b2899e36..bb37241b 100644 --- a/examples/paste/auth_token.ini +++ b/examples/paste/auth_token.ini @@ -6,9 +6,10 @@ paste.app_factory = auth_token:app_factory auth_protocol = http auth_host = 127.0.0.1 auth_port = 5001 +auth_uri = http://127.0.0.1:5000/ admin_token = 999888777666 -delay_auth_decision = 0 +delay_auth_decision = 1 service_protocol = http service_host = 127.0.0.1 diff --git a/examples/paste/glance-api.conf b/examples/paste/glance-api.conf index 6b1d8801..26dea5ee 100644 --- a/examples/paste/glance-api.conf +++ b/examples/paste/glance-api.conf @@ -82,6 +82,7 @@ service_port = 808 auth_host = 127.0.0.1 auth_port = 5001 auth_protocol = http +auth_uri = http://127.0.0.1:5000/ admin_token = 999888777666 # Allows anonymous access diff --git a/examples/paste/glance-registry.conf b/examples/paste/glance-registry.conf index a66323cd..378705e5 100644 --- a/examples/paste/glance-registry.conf +++ b/examples/paste/glance-registry.conf @@ -46,6 +46,7 @@ service_port = 808 auth_host = 127.0.0.1 auth_port = 5001 auth_protocol = http +auth_uri = http://127.0.0.1:5000/ admin_token = 999888777666 # Allows anonymous access diff --git a/examples/paste/nova-api-paste.ini b/examples/paste/nova-api-paste.ini index 7cc75ffe..bf7ae41f 100644 --- a/examples/paste/nova-api-paste.ini +++ b/examples/paste/nova-api-paste.ini @@ -90,6 +90,7 @@ service_port = 808 auth_host = 127.0.0.1 auth_port = 5001 auth_protocol = http +auth_uri = http://127.0.0.1:5000/ admin_token = 999888777666 [filter:auth_shim] diff --git a/keystone/backends/memcache/api/token.py b/keystone/backends/memcache/api/token.py index a614eb33..c758a19b 100755 --- a/keystone/backends/memcache/api/token.py +++ b/keystone/backends/memcache/api/token.py @@ -14,39 +14,49 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. - +from keystone.backends.memcache import MEMCACHE_SERVER, models from keystone.backends.api import BaseTokenAPI class TokenAPI(BaseTokenAPI): def create(self, token): + if not hasattr(token, 'tenant_id'): + token.tenant_id = None if token.tenant_id != None: tenant_user_key = token.tenant_id + "::" + token.user_id else: tenant_user_key = token.user_id - #Setting them for a day. + MEMCACHE_SERVER.set(token.id, token) MEMCACHE_SERVER.set(tenant_user_key, token) - def get(self, id, session=None): - return MEMCACHE_SERVER.get(id) - - def delete(self, id, session=None): + def get(self, id): token = MEMCACHE_SERVER.get(id) + if token != None and not hasattr(token, 'tenant_id'): + token.tenant_id = None + return token + + def delete(self, id): + token = self.get(id) if token != None: MEMCACHE_SERVER.delete(id) - if token.tenant_id != None: MEMCACHE_SERVER.delete(token.tenant_id + "::" + token.user_id) else: MEMCACHE_SERVER.delete(token.id) MEMCACHE_SERVER.delete(token.user_id) - def get_for_user(self, user_id, session=None): - return MEMCACHE_SERVER.get(user_id) - - def get_for_user_by_tenant(self, user_id, tenant_id, session=None): - return MEMCACHE_SERVER.get(tenant_id + "::" + user_id) + def get_for_user(self, user_id): + token = MEMCACHE_SERVER.get(user_id) + if token != None and not hasattr(token, 'tenant_id'): + token.tenant_id = None + return token + + def get_for_user_by_tenant(self, user_id, tenant_id): + token = MEMCACHE_SERVER.get(tenant_id + "::" + user_id) + if token != None and not hasattr(token, 'tenant_id'): + token.tenant_id = None + return token def get(): diff --git a/keystone/middleware/auth_token.py b/keystone/middleware/auth_token.py index 1dd3e21e..2b8fce5e 100755 --- a/keystone/middleware/auth_token.py +++ b/keystone/middleware/auth_token.py @@ -58,6 +58,7 @@ from paste.deploy import loadapp from urlparse import urlparse from webob.exc import HTTPUnauthorized, HTTPUseProxy from webob.exc import Request, Response +import tools.tracer # @UnusedImport # module runs on import from keystone.common.bufferedhttp import http_connect_raw as http_connect @@ -99,18 +100,22 @@ class AuthProtocol(object): self.auth_host = conf.get('auth_host') self.auth_port = int(conf.get('auth_port')) self.auth_protocol = conf.get('auth_protocol', 'https') - self.auth_location = "%s://%s:%s" % (self.auth_protocol, - self.auth_host, - self.auth_port) + + # where to tell clients to find the auth service (default to url + # constructed based on endpoint we have for the service to use) + self.auth_location = conf.get('auth_uri', + "%s://%s:%s" % (self.auth_protocol, + self.auth_host, + self.auth_port)) # Credentials used to verify this component with the Auth service since - # validating tokens is a priviledged call + # validating tokens is a privileged call self.admin_token = conf.get('admin_token') def __init__(self, app, conf): """ Common initialization code """ - #TODO(ziad): maybe we rafactor this into a superclass + #TODO(ziad): maybe we refactor this into a superclass self._init_protocol_common(app, conf) # Applies to all protocols self._init_protocol(app, conf) # Specific to this protocol @@ -174,8 +179,8 @@ class AuthProtocol(object): # NOTE(todd): unused self.expanded = True - #Send request downstream - return self._forward_request() + #Send request downstream + return self._forward_request() # NOTE(todd): unused def get_admin_auth_token(self, username, password, tenant): @@ -203,8 +208,10 @@ class AuthProtocol(object): def _reject_request(self): """Redirect client to auth server""" - return HTTPUseProxy(location=self.auth_location)(self.env, - self.start_response) + return HTTPUnauthorized("Authentication required", + [("WWW-Authenticate", + "Keystone uri='%s'" % self.auth_location)])(self.env, + self.start_response) def _reject_claims(self): """Client sent bad claims""" @@ -297,6 +304,7 @@ class AuthProtocol(object): # We are forwarding to a remote service (no downstream WSGI app) req = Request(self.proxy_headers) parsed = urlparse(req.url) + conn = http_connect(self.service_host, self.service_port, req.method, @@ -305,10 +313,20 @@ class AuthProtocol(object): ssl=(self.service_protocol == 'https')) resp = conn.getresponse() data = resp.read() + #TODO(ziad): use a more sophisticated proxy # we are rewriting the headers now - return Response(status=resp.status, body=data)(self.proxy_headers, - self.start_response) + + if resp.status == 401 or resp.status == 305: + # Add our own headers to the list + headers = [("WWW_AUTHENTICATE", + "Keystone uri='%s'" % self.auth_location)] + return Response(status=resp.status, body=data, + headerlist=headers)(self.env, + self.start_response) + else: + return Response(status=resp.status, body=data)(self.env, + self.start_response) def filter_factory(global_conf, **local_conf): diff --git a/keystone/middleware/remoteauth.py b/keystone/middleware/remoteauth.py index 5919abd6..70501807 100644 --- a/keystone/middleware/remoteauth.py +++ b/keystone/middleware/remoteauth.py @@ -69,8 +69,8 @@ class RemoteAuth(object): # app is the next app in WSGI chain - eventually the OpenStack service self.app = app self.conf = conf - # where to redirect untrusted requests to go and auth - self.auth_location = conf.get('auth_location') + # where to redirect untrusted requests to + self.proxy_location = conf.get('proxy_location') # secret that will tell us a request is coming from a trusted auth # component self.remote_auth_pass = conf.get('remote_auth_pass') @@ -81,7 +81,10 @@ class RemoteAuth(object): # Authenticate the Auth component itself. headers = [('www-authenticate', 'Basic realm="API Auth"')] if 'HTTP_AUTHORIZATION' not in env: - return HTTPUnauthorized(headers=headers)(env, start_response) + # Redirect to proxy (auth component) and show that basic auth is + # required + return HTTPUseProxy(location=self.proxy_location, + headers=headers)(env, start_response) else: auth_type, encoded_creds = env['HTTP_AUTHORIZATION'].split(None, 1) if encoded_creds != self.remote_auth_pass: @@ -89,8 +92,7 @@ class RemoteAuth(object): # Make sure that the user has been authenticated by the Auth Service if 'HTTP_X_AUTHORIZATION' not in env: - return HTTPUseProxy(location=self.auth_location)(env, - start_response) + return HTTPUnauthorized()(env, start_response) return self.app(env, start_response) diff --git a/run_tests.py b/run_tests.py index 3816fcd5..6d10f9ee 100755 --- a/run_tests.py +++ b/run_tests.py @@ -12,7 +12,7 @@ TEST_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), CONFIG_FILES = ( 'sql.conf.template', - #'memcache.conf.template', + # not passing 'memcache.conf.template', 'ldap.conf.template') TEST_FILES = ( |
