/usr/share/pyshared/piston/authentication.py is in python-django-piston 0.2.3-1ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | import binascii
from oauth import oauth
from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth.models import User, AnonymousUser
from django.contrib.auth.decorators import login_required
from django.template import loader
from django.contrib.auth import authenticate
from django.conf import settings
from django.core.urlresolvers import get_callable
from django.core.exceptions import ImproperlyConfigured
from django.shortcuts import render_to_response
from django.template import RequestContext
from piston import forms
class NoAuthentication(object):
"""
Authentication handler that always returns
True, so no authentication is needed, nor
initiated (`challenge` is missing.)
"""
def is_authenticated(self, request):
return True
class HttpBasicAuthentication(object):
"""
Basic HTTP authenticater. Synopsis:
Authentication handlers must implement two methods:
- `is_authenticated`: Will be called when checking for
authentication. Receives a `request` object, please
set your `User` object on `request.user`, otherwise
return False (or something that evaluates to False.)
- `challenge`: In cases where `is_authenticated` returns
False, the result of this method will be returned.
This will usually be a `HttpResponse` object with
some kind of challenge headers and 401 code on it.
"""
def __init__(self, auth_func=authenticate, realm='API'):
self.auth_func = auth_func
self.realm = realm
def is_authenticated(self, request):
auth_string = request.META.get('HTTP_AUTHORIZATION', None)
if not auth_string:
return False
try:
(authmeth, auth) = auth_string.split(" ", 1)
if not authmeth.lower() == 'basic':
return False
auth = auth.strip().decode('base64')
(username, password) = auth.split(':', 1)
except (ValueError, binascii.Error):
return False
request.user = self.auth_func(username=username, password=password) \
or AnonymousUser()
return not request.user in (False, None, AnonymousUser())
def challenge(self):
resp = HttpResponse("Authorization Required")
resp['WWW-Authenticate'] = 'Basic realm="%s"' % self.realm
resp.status_code = 401
return resp
def __repr__(self):
return u'<HTTPBasic: realm=%s>' % self.realm
class HttpBasicSimple(HttpBasicAuthentication):
def __init__(self, realm, username, password):
self.user = User.objects.get(username=username)
self.password = password
super(HttpBasicSimple, self).__init__(auth_func=self.hash, realm=realm)
def hash(self, username, password):
if username == self.user.username and password == self.password:
return self.user
def load_data_store():
'''Load data store for OAuth Consumers, Tokens, Nonces and Resources
'''
path = getattr(settings, 'OAUTH_DATA_STORE', 'piston.store.DataStore')
# stolen from django.contrib.auth.load_backend
i = path.rfind('.')
module, attr = path[:i], path[i+1:]
try:
mod = __import__(module, {}, {}, attr)
except ImportError, e:
raise ImproperlyConfigured, 'Error importing OAuth data store %s: "%s"' % (module, e)
try:
cls = getattr(mod, attr)
except AttributeError:
raise ImproperlyConfigured, 'Module %s does not define a "%s" OAuth data store' % (module, attr)
return cls
# Set the datastore here.
oauth_datastore = load_data_store()
def initialize_server_request(request):
"""
Shortcut for initialization.
"""
if request.method == "POST": #and \
# request.META['CONTENT_TYPE'] == "application/x-www-form-urlencoded":
params = dict(request.REQUEST.items())
else:
params = { }
# Seems that we want to put HTTP_AUTHORIZATION into 'Authorization'
# for oauth.py to understand. Lovely.
request.META['Authorization'] = request.META.get('HTTP_AUTHORIZATION', '')
oauth_request = oauth.OAuthRequest.from_request(
request.method, request.build_absolute_uri(),
headers=request.META, parameters=params,
query_string=request.environ.get('QUERY_STRING', ''))
if oauth_request:
oauth_server = oauth.OAuthServer(oauth_datastore(oauth_request))
oauth_server.add_signature_method(oauth.OAuthSignatureMethod_PLAINTEXT())
oauth_server.add_signature_method(oauth.OAuthSignatureMethod_HMAC_SHA1())
else:
oauth_server = None
return oauth_server, oauth_request
def send_oauth_error(err=None):
"""
Shortcut for sending an error.
"""
response = HttpResponse(err.message.encode('utf-8'))
response.status_code = 401
realm = 'OAuth'
header = oauth.build_authenticate_header(realm=realm)
for k, v in header.iteritems():
response[k] = v
return response
def oauth_request_token(request):
oauth_server, oauth_request = initialize_server_request(request)
if oauth_server is None:
return INVALID_PARAMS_RESPONSE
try:
token = oauth_server.fetch_request_token(oauth_request)
response = HttpResponse(token.to_string())
except oauth.OAuthError, err:
response = send_oauth_error(err)
return response
def oauth_auth_view(request, token, callback, params):
form = forms.OAuthAuthenticationForm(initial={
'oauth_token': token.key,
'oauth_callback': token.get_callback_url() or callback,
})
return render_to_response('piston/authorize_token.html',
{ 'form': form }, RequestContext(request))
@login_required
def oauth_user_auth(request):
oauth_server, oauth_request = initialize_server_request(request)
if oauth_request is None:
return INVALID_PARAMS_RESPONSE
try:
token = oauth_server.fetch_request_token(oauth_request)
except oauth.OAuthError, err:
return send_oauth_error(err)
try:
callback = oauth_server.get_callback(oauth_request)
except:
callback = None
if request.method == "GET":
params = oauth_request.get_normalized_parameters()
oauth_view = getattr(settings, 'OAUTH_AUTH_VIEW', None)
if oauth_view is None:
return oauth_auth_view(request, token, callback, params)
else:
return get_callable(oauth_view)(request, token, callback, params)
elif request.method == "POST":
try:
form = forms.OAuthAuthenticationForm(request.POST)
if form.is_valid():
token = oauth_server.authorize_token(token, request.user)
args = '?'+token.to_string(only_key=True)
else:
args = '?error=%s' % 'Access not granted by user.'
print "FORM ERROR", form.errors
if not callback:
callback = getattr(settings, 'OAUTH_CALLBACK_VIEW')
return get_callable(callback)(request, token)
response = HttpResponseRedirect(callback+args)
except oauth.OAuthError, err:
response = send_oauth_error(err)
else:
response = HttpResponse('Action not allowed.')
return response
def oauth_access_token(request):
oauth_server, oauth_request = initialize_server_request(request)
if oauth_request is None:
return INVALID_PARAMS_RESPONSE
try:
token = oauth_server.fetch_access_token(oauth_request)
return HttpResponse(token.to_string())
except oauth.OAuthError, err:
return send_oauth_error(err)
INVALID_PARAMS_RESPONSE = send_oauth_error(oauth.OAuthError('Invalid request parameters.'))
class OAuthAuthentication(object):
"""
OAuth authentication. Based on work by Leah Culver.
"""
def __init__(self, realm='API'):
self.realm = realm
self.builder = oauth.build_authenticate_header
def is_authenticated(self, request):
"""
Checks whether a means of specifying authentication
is provided, and if so, if it is a valid token.
Read the documentation on `HttpBasicAuthentication`
for more information about what goes on here.
"""
if self.is_valid_request(request):
try:
consumer, token, parameters = self.validate_token(request)
except oauth.OAuthError, err:
print send_oauth_error(err)
return False
if consumer and token:
request.user = token.user
request.consumer = consumer
request.throttle_extra = token.consumer.id
return True
return False
def challenge(self):
"""
Returns a 401 response with a small bit on
what OAuth is, and where to learn more about it.
When this was written, browsers did not understand
OAuth authentication on the browser side, and hence
the helpful template we render. Maybe some day in the
future, browsers will take care of this stuff for us
and understand the 401 with the realm we give it.
"""
response = HttpResponse()
response.status_code = 401
realm = 'API'
for k, v in self.builder(realm=realm).iteritems():
response[k] = v
tmpl = loader.render_to_string('oauth/challenge.html',
{ 'MEDIA_URL': settings.MEDIA_URL })
response.content = tmpl
return response
@staticmethod
def is_valid_request(request):
"""
Checks whether the required parameters are either in
the http-authorization header sent by some clients,
which is by the way the preferred method according to
OAuth spec, but otherwise fall back to `GET` and `POST`.
"""
must_have = [ 'oauth_'+s for s in [
'consumer_key', 'token', 'signature',
'signature_method', 'timestamp', 'nonce' ] ]
is_in = lambda l: all([ (p in l) for p in must_have ])
auth_params = request.META.get("HTTP_AUTHORIZATION", "")
req_params = request.REQUEST
return is_in(auth_params) or is_in(req_params)
@staticmethod
def validate_token(request, check_timestamp=True, check_nonce=True):
oauth_server, oauth_request = initialize_server_request(request)
return oauth_server.verify_request(oauth_request)
|