66
60
"""Create a WSGI server object for a particular web service."""
67
61
cls.configure_server(host, port, config_package, config_file)
68
62
return wsgi_make_server(host, int(port), cls)
71
class AuthenticationMiddleware(object):
72
"""A base class for middleware that authenticates HTTP requests.
74
This class implements a generic HTTP authentication workflow:
75
check whether the requested resource is protected, get credentials
76
from the WSGI environment, validate them (using a callback
77
function) and either allow or deny acces.
80
def __init__(self, application, authenticate_with,
81
realm="Restricted area", protect_path_pattern='.*'):
84
:param application: A WSGI application.
86
:param authenticate_with: A callback function that takes some
87
number of credential arguemnts (the number and type
88
depends on the implementation of
89
getCredentialsFromEnvironment()) and returns an object
90
representing the authenticated user. If the credentials
91
are invalid or don't identify any existing user, the
92
function should return None.
94
:param realm: The string to give out as the authentication realm.
95
:param protect_path_pattern: A regular expression string. URL
96
paths matching this string will be protected with the
97
authentication method. URL paths not matching this string
98
can be accessed without authenticating.
100
self.application = application
101
self.authenticate_with = authenticate_with
103
self.protect_path_pattern = re.compile(protect_path_pattern)
105
def _unauthorized(self, start_response):
106
"""Short-circuit the request with a 401 error code."""
107
start_response("401 Unauthorized",
108
[('WWW-Authenticate',
109
'Basic realm="%s"' % self.realm)])
110
return ['401 Unauthorized']
112
def __call__(self, environ, start_response):
113
"""Protect certain resources by checking auth credentials."""
114
path_info = environ.get('PATH_INFO', '/')
115
if not self.protect_path_pattern.match(path_info):
116
environ['authenticated_user'] = None
117
return self.application(environ, start_response)
120
credentials = self.getCredentialsFromEnvironment(environ)
123
if credentials is None:
124
return self._unauthorized(start_response)
126
authenticated_user = self.authenticate_with(*credentials)
127
if authenticated_user is None:
128
return self._unauthorized(start_response)
130
environ['authenticated_user'] = authenticated_user
132
return self.application(environ, start_response)
134
def getCredentialsFromEnvironment(self, environment):
135
"""Retrieve a set of credentials from the environment.
137
This superclass implementation ignores the environment
138
entirely, and so never authenticates anybody.
140
:param environment: The WSGI environment.
141
:return: A list of objects to be passed into the authenticate_with
142
callback function, or None if the credentials could not
148
class BasicAuthMiddleware(AuthenticationMiddleware):
149
"""WSGI middleware that implements HTTP Basic Auth."""
151
def getCredentialsFromEnvironment(self, environ):
152
authorization = environ.get('HTTP_AUTHORIZATION')
153
if authorization is None:
156
method, auth = authorization.split(' ', 1)
157
if method.lower() != 'basic':
160
auth = auth.strip().decode('base64')
161
username, password = auth.split(':', 1)
162
return username, password
165
class OAuthMiddleware(AuthenticationMiddleware):
166
"""WSGI middleware that implements (part of) OAuth.
168
This middleware only protects resources by making sure requests
169
are signed with a valid consumer and access token. It does not
170
help clients get request tokens or exchange request tokens for
174
def __init__(self, application, authenticate_with, data_store=None,
175
realm="Restricted area", protect_path_pattern='.*'):
176
"""See `AuthenticationMiddleware.`
178
:param data_store: An OAuthDataStore.
180
super(OAuthMiddleware, self).__init__(
181
application, authenticate_with, realm, protect_path_pattern)
182
self.data_store = data_store
184
def getCredentialsFromEnvironment(self, environ):
185
http_method = environ['REQUEST_METHOD']
188
url_scheme = environ['wsgi.url_scheme']
189
hostname = environ['HTTP_HOST']
190
path = environ['PATH_INFO']
191
query_string = environ['QUERY_STRING']
192
original_url = urlparse.urlunparse(
193
(url_scheme, hostname, path, '', query_string, ''))
194
headers = {'Authorization' : environ.get('HTTP_AUTHORIZATION', '')}
195
request = OAuthRequest().from_request(
196
http_method, original_url, headers=headers,
197
query_string=query_string)
200
server = OAuthServer(self.data_store)
201
server.add_signature_method(OAuthSignatureMethod_PLAINTEXT())
203
consumer, token, parameters = server.verify_request(request)
204
except OAuthError, e:
206
return consumer, token, parameters