diff options
| author | Jorge L. Williams <jorge.williams@rackspace.com> | 2011-04-21 16:53:57 -0500 |
|---|---|---|
| committer | Jorge L. Williams <jorge.williams@rackspace.com> | 2011-04-21 16:53:57 -0500 |
| commit | 8bb4887abf9a56291fe38bd43ece5d5cbc8aebd5 (patch) | |
| tree | 94eb7749de1e374d61310bfd83c7cf22e0cec21c | |
| parent | c03f897ce59b437f0fea5c00671997d8a1cab9a0 (diff) | |
| parent | 35fb99ec78f3c30a13036b550284b9f26de2bca0 (diff) | |
| download | keystone-8bb4887abf9a56291fe38bd43ece5d5cbc8aebd5.tar.gz keystone-8bb4887abf9a56291fe38bd43ece5d5cbc8aebd5.tar.xz keystone-8bb4887abf9a56291fe38bd43ece5d5cbc8aebd5.zip | |
Merge branch 'master' of github.com:khussein/keystone
| -rw-r--r-- | docs/guide/src/docbkx/samples/auth.json | 2 | ||||
| -rw-r--r-- | echo/echo/echo.ini | 7 | ||||
| -rw-r--r-- | keystone/auth_protocol/__init__.py | 0 | ||||
| -rw-r--r-- | keystone/auth_protocol/auth_protocol_token.py | 73 | ||||
| -rw-r--r-- | keystone/common/__init__.py | 0 | ||||
| -rw-r--r-- | keystone/common/bufferedhttp.py | 165 | ||||
| -rw-r--r-- | keystone/identity.py | 1 | ||||
| -rw-r--r-- | setup.py | 1 |
8 files changed, 247 insertions, 2 deletions
diff --git a/docs/guide/src/docbkx/samples/auth.json b/docs/guide/src/docbkx/samples/auth.json index 697c4664..fa56c131 100644 --- a/docs/guide/src/docbkx/samples/auth.json +++ b/docs/guide/src/docbkx/samples/auth.json @@ -13,7 +13,7 @@ } ]}, "username": "jqsmith", - "tenantId": "1234", + "tenantId": "1234" } } } diff --git a/echo/echo/echo.ini b/echo/echo/echo.ini index 10e09712..020198b5 100644 --- a/echo/echo/echo.ini +++ b/echo/echo/echo.ini @@ -6,6 +6,7 @@ use = egg:echo [pipeline:main] pipeline = + auth papiauth echo @@ -14,3 +15,9 @@ use = egg:keystone#papiauth auth_ip = 127.0.0.1 auth_port = 8080 auth_pass = dTpw + +[filter:auth] +use = egg:keystone#tokenauth +auth_ip = 127.0.0.1 +auth_port = 8080 +auth_pass = dTpw diff --git a/keystone/auth_protocol/__init__.py b/keystone/auth_protocol/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/keystone/auth_protocol/__init__.py diff --git a/keystone/auth_protocol/auth_protocol_token.py b/keystone/auth_protocol/auth_protocol_token.py new file mode 100644 index 00000000..1c8ab7cf --- /dev/null +++ b/keystone/auth_protocol/auth_protocol_token.py @@ -0,0 +1,73 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# Copyright (c) 2010-2011 OpenStack, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Not Yet PEP8 standardized + +import simplejson as json +from webob.exc import HTTPUnauthorized, Request + +from keystone.common.bufferedhttp import http_connect_raw as http_connect + +class TokenAuth(object): + """Auth Middleware that uses the dev auth server.""" + + def __init__(self, app, conf): + print "Starting the new one" + self.app = app + self.conf = conf + self.auth_host = conf.get('auth_ip', '127.0.0.1') + self.auth_port = int(conf.get('auth_port', 8080)) + self.auth_pass = conf.get('auth_pass', 'dTpw') + self.delegated = int(conf.get('delegated', 0)) + + def __call__(self, env, start_response): + + def custom_start_response(status, headers): + if self.delegated: + headers.append(('WWW-Authenticate', "Basic realm='API Realm'")) + return start_response(status, headers) + + token = env.get('HTTP_X_AUTH_TOKEN', env.get('HTTP_X_STORAGE_TOKEN')) + if token: + #conn = http_connect(self.auth_host, self.auth_port, 'GET', + # '/token/%s' % token) + #resp = conn.getresponse() + path = 'http://%s:%s/token/%s' % \ + (self.auth_host, self.auth_port, token) + resp = Request.blank(path).get_response(self.app) + user = json.loads(resp.body) + #resp.read() + #conn.close() + if not resp.status.startswith('20'): + if self.delegated: + env['HTTP_X_IDENTITY_STATUS'] = "Invalid" + else: + env['HTTP_X_AUTHORIZATION'] = "Proxy " + user + if self.delegated: + env['HTTP_X_IDENTITY_STATUS'] = "Confirmed" + return HTTPUnauthorized()(env, custom_start_response) + + env['HTTP_AUTHORIZATION'] = "Basic dTpw" + return self.app(env, custom_start_response) + + +def filter_factory(global_conf, **local_conf): + """Returns a WSGI filter app for use with paste.deploy.""" + conf = global_conf.copy() + conf.update(local_conf) + + def auth_filter(app): + return TokenAuth(app, conf) + return auth_filter diff --git a/keystone/common/__init__.py b/keystone/common/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/keystone/common/__init__.py diff --git a/keystone/common/bufferedhttp.py b/keystone/common/bufferedhttp.py new file mode 100644 index 00000000..fdb35ee6 --- /dev/null +++ b/keystone/common/bufferedhttp.py @@ -0,0 +1,165 @@ +# Copyright (c) 2010-2011 OpenStack, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Monkey Patch httplib.HTTPResponse to buffer reads of headers. This can improve +performance when making large numbers of small HTTP requests. This module +also provides helper functions to make HTTP connections using +BufferedHTTPResponse. + +.. warning:: + + If you use this, be sure that the libraries you are using do not access + the socket directly (xmlrpclib, I'm looking at you :/), and instead + make all calls through httplib. +""" + +from urllib import quote +import logging +import time + +from eventlet.green.httplib import CONTINUE, HTTPConnection, HTTPMessage, \ + HTTPResponse, HTTPSConnection, _UNKNOWN + + +class BufferedHTTPResponse(HTTPResponse): + """HTTPResponse class that buffers reading of headers""" + + def __init__(self, sock, debuglevel=0, strict=0, + method=None): # pragma: no cover + self.sock = sock + self.fp = sock.makefile('rb') + self.debuglevel = debuglevel + self.strict = strict + self._method = method + + self.msg = None + + # from the Status-Line of the response + self.version = _UNKNOWN # HTTP-Version + self.status = _UNKNOWN # Status-Code + self.reason = _UNKNOWN # Reason-Phrase + + self.chunked = _UNKNOWN # is "chunked" being used? + self.chunk_left = _UNKNOWN # bytes left to read in current chunk + self.length = _UNKNOWN # number of bytes left in response + self.will_close = _UNKNOWN # conn will close at end of response + + def expect_response(self): + self.fp = self.sock.makefile('rb', 0) + version, status, reason = self._read_status() + if status != CONTINUE: + self._read_status = lambda: (version, status, reason) + self.begin() + else: + self.status = status + self.reason = reason.strip() + self.version = 11 + self.msg = HTTPMessage(self.fp, 0) + self.msg.fp = None + + +class BufferedHTTPConnection(HTTPConnection): + """HTTPConnection class that uses BufferedHTTPResponse""" + response_class = BufferedHTTPResponse + + def connect(self): + self._connected_time = time.time() + return HTTPConnection.connect(self) + + def putrequest(self, method, url, skip_host=0, skip_accept_encoding=0): + self._method = method + self._path = url + return HTTPConnection.putrequest(self, method, url, skip_host, + skip_accept_encoding) + + def getexpect(self): + response = BufferedHTTPResponse(self.sock, strict=self.strict, + method=self._method) + response.expect_response() + return response + + def getresponse(self): + response = HTTPConnection.getresponse(self) + logging.debug(("HTTP PERF: %(time).5f seconds to %(method)s " + "%(host)s:%(port)s %(path)s)"), + {'time': time.time() - self._connected_time, 'method': self._method, + 'host': self.host, 'port': self.port, 'path': self._path}) + return response + + +def http_connect(ipaddr, port, device, partition, method, path, + headers=None, query_string=None, ssl=False): + """ + Helper function to create an HTTPConnection object. If ssl is set True, + HTTPSConnection will be used. However, if ssl=False, BufferedHTTPConnection + will be used, which is buffered for backend Swift services. + + :param ipaddr: IPv4 address to connect to + :param port: port to connect to + :param device: device of the node to query + :param partition: partition on the device + :param method: HTTP method to request ('GET', 'PUT', 'POST', etc.) + :param path: request path + :param headers: dictionary of headers + :param query_string: request query string + :param ssl: set True if SSL should be used (default: False) + :returns: HTTPConnection object + """ + if ssl: + conn = HTTPSConnection('%s:%s' % (ipaddr, port)) + else: + conn = BufferedHTTPConnection('%s:%s' % (ipaddr, port)) + path = quote('/' + device + '/' + str(partition) + path) + if query_string: + path += '?' + query_string + conn.path = path + conn.putrequest(method, path) + if headers: + for header, value in headers.iteritems(): + conn.putheader(header, value) + conn.endheaders() + return conn + + +def http_connect_raw(ipaddr, port, method, path, headers=None, + query_string=None, ssl=False): + """ + Helper function to create an HTTPConnection object. If ssl is set True, + HTTPSConnection will be used. However, if ssl=False, BufferedHTTPConnection + will be used, which is buffered for backend Swift services. + + :param ipaddr: IPv4 address to connect to + :param port: port to connect to + :param method: HTTP method to request ('GET', 'PUT', 'POST', etc.) + :param path: request path + :param headers: dictionary of headers + :param query_string: request query string + :param ssl: set True if SSL should be used (default: False) + :returns: HTTPConnection object + """ + if ssl: + conn = HTTPSConnection('%s:%s' % (ipaddr, port)) + else: + conn = BufferedHTTPConnection('%s:%s' % (ipaddr, port)) + if query_string: + path += '?' + query_string + conn.path = path + conn.putrequest(method, path) + if headers: + for header, value in headers.iteritems(): + conn.putheader(header, value) + conn.endheaders() + return conn diff --git a/keystone/identity.py b/keystone/identity.py index 434e7fa6..bc9415fb 100644 --- a/keystone/identity.py +++ b/keystone/identity.py @@ -22,7 +22,6 @@ from bottle import request from bottle import debug from bottle import abort from bottle import Bottle -from bottle import EventletServer import ConfigParser from datetime import datetime from datetime import timedelta @@ -36,6 +36,7 @@ setup( 'paste.app_factory': ['main=identity:app_factory'], 'paste.filter_factory': [ 'papiauth=keystone.middleware.papiauth:filter_factory', + 'tokenauth=keystone.auth_protocol.auth_protocol_token:filter_factory', ], }, ) |
