Correct 401, 305, and www-authenticate responses
Change-Id: I6205567e7b68917d5ecabcf336a4891802ab7381
This commit is contained in:
parent
b1fd6aac34
commit
4e773aa9c9
|
@ -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
|
||||
|
|
|
@ -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/
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue