Correct 401, 305, and www-authenticate responses

Change-Id: I6205567e7b68917d5ecabcf336a4891802ab7381
This commit is contained in:
Ziad Sawalha 2011-08-11 02:03:26 -05:00
parent b1fd6aac34
commit 4e773aa9c9
8 changed files with 43 additions and 18 deletions

View File

@ -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

View File

@ -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/

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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):

View File

@ -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)