aboutsummaryrefslogtreecommitdiffstats
path: root/rest_framework
diff options
context:
space:
mode:
Diffstat (limited to 'rest_framework')
-rw-r--r--rest_framework/authentication.py183
-rw-r--r--rest_framework/compat.py57
-rw-r--r--rest_framework/parsers.py76
-rw-r--r--rest_framework/permissions.py28
-rw-r--r--rest_framework/renderers.py88
5 files changed, 3 insertions, 429 deletions
diff --git a/rest_framework/authentication.py b/rest_framework/authentication.py
index 36d74dd9..124ef68a 100644
--- a/rest_framework/authentication.py
+++ b/rest_framework/authentication.py
@@ -3,14 +3,9 @@ Provides various authentication policies.
"""
from __future__ import unicode_literals
import base64
-
from django.contrib.auth import authenticate
-from django.core.exceptions import ImproperlyConfigured
from django.middleware.csrf import CsrfViewMiddleware
-from django.conf import settings
from rest_framework import exceptions, HTTP_HEADER_ENCODING
-from rest_framework.compat import oauth, oauth_provider, oauth_provider_store
-from rest_framework.compat import oauth2_provider, provider_now, check_nonce
from rest_framework.authtoken.models import Token
@@ -178,181 +173,3 @@ class TokenAuthentication(BaseAuthentication):
def authenticate_header(self, request):
return 'Token'
-
-
-class OAuthAuthentication(BaseAuthentication):
- """
- OAuth 1.0a authentication backend using `django-oauth-plus` and `oauth2`.
-
- Note: The `oauth2` package actually provides oauth1.0a support. Urg.
- We import it from the `compat` module as `oauth`.
- """
- www_authenticate_realm = 'api'
-
- def __init__(self, *args, **kwargs):
- super(OAuthAuthentication, self).__init__(*args, **kwargs)
-
- if oauth is None:
- raise ImproperlyConfigured(
- "The 'oauth2' package could not be imported."
- "It is required for use with the 'OAuthAuthentication' class.")
-
- if oauth_provider is None:
- raise ImproperlyConfigured(
- "The 'django-oauth-plus' package could not be imported."
- "It is required for use with the 'OAuthAuthentication' class.")
-
- def authenticate(self, request):
- """
- Returns two-tuple of (user, token) if authentication succeeds,
- or None otherwise.
- """
- try:
- oauth_request = oauth_provider.utils.get_oauth_request(request)
- except oauth.Error as err:
- raise exceptions.AuthenticationFailed(err.message)
-
- if not oauth_request:
- return None
-
- oauth_params = oauth_provider.consts.OAUTH_PARAMETERS_NAMES
-
- found = any(param for param in oauth_params if param in oauth_request)
- missing = list(param for param in oauth_params if param not in oauth_request)
-
- if not found:
- # OAuth authentication was not attempted.
- return None
-
- if missing:
- # OAuth was attempted but missing parameters.
- msg = 'Missing parameters: %s' % (', '.join(missing))
- raise exceptions.AuthenticationFailed(msg)
-
- if not self.check_nonce(request, oauth_request):
- msg = 'Nonce check failed'
- raise exceptions.AuthenticationFailed(msg)
-
- try:
- consumer_key = oauth_request.get_parameter('oauth_consumer_key')
- consumer = oauth_provider_store.get_consumer(request, oauth_request, consumer_key)
- except oauth_provider.store.InvalidConsumerError:
- msg = 'Invalid consumer token: %s' % oauth_request.get_parameter('oauth_consumer_key')
- raise exceptions.AuthenticationFailed(msg)
-
- if consumer.status != oauth_provider.consts.ACCEPTED:
- msg = 'Invalid consumer key status: %s' % consumer.get_status_display()
- raise exceptions.AuthenticationFailed(msg)
-
- try:
- token_param = oauth_request.get_parameter('oauth_token')
- token = oauth_provider_store.get_access_token(request, oauth_request, consumer, token_param)
- except oauth_provider.store.InvalidTokenError:
- msg = 'Invalid access token: %s' % oauth_request.get_parameter('oauth_token')
- raise exceptions.AuthenticationFailed(msg)
-
- try:
- self.validate_token(request, consumer, token)
- except oauth.Error as err:
- raise exceptions.AuthenticationFailed(err.message)
-
- user = token.user
-
- if not user.is_active:
- msg = 'User inactive or deleted: %s' % user.username
- raise exceptions.AuthenticationFailed(msg)
-
- return (token.user, token)
-
- def authenticate_header(self, request):
- """
- If permission is denied, return a '401 Unauthorized' response,
- with an appropraite 'WWW-Authenticate' header.
- """
- return 'OAuth realm="%s"' % self.www_authenticate_realm
-
- def validate_token(self, request, consumer, token):
- """
- Check the token and raise an `oauth.Error` exception if invalid.
- """
- oauth_server, oauth_request = oauth_provider.utils.initialize_server_request(request)
- oauth_server.verify_request(oauth_request, consumer, token)
-
- def check_nonce(self, request, oauth_request):
- """
- Checks nonce of request, and return True if valid.
- """
- oauth_nonce = oauth_request['oauth_nonce']
- oauth_timestamp = oauth_request['oauth_timestamp']
- return check_nonce(request, oauth_request, oauth_nonce, oauth_timestamp)
-
-
-class OAuth2Authentication(BaseAuthentication):
- """
- OAuth 2 authentication backend using `django-oauth2-provider`
- """
- www_authenticate_realm = 'api'
- allow_query_params_token = settings.DEBUG
-
- def __init__(self, *args, **kwargs):
- super(OAuth2Authentication, self).__init__(*args, **kwargs)
-
- if oauth2_provider is None:
- raise ImproperlyConfigured(
- "The 'django-oauth2-provider' package could not be imported. "
- "It is required for use with the 'OAuth2Authentication' class.")
-
- def authenticate(self, request):
- """
- Returns two-tuple of (user, token) if authentication succeeds,
- or None otherwise.
- """
-
- auth = get_authorization_header(request).split()
-
- if len(auth) == 1:
- msg = 'Invalid bearer header. No credentials provided.'
- raise exceptions.AuthenticationFailed(msg)
- elif len(auth) > 2:
- msg = 'Invalid bearer header. Token string should not contain spaces.'
- raise exceptions.AuthenticationFailed(msg)
-
- if auth and auth[0].lower() == b'bearer':
- access_token = auth[1]
- elif 'access_token' in request.POST:
- access_token = request.POST['access_token']
- elif 'access_token' in request.GET and self.allow_query_params_token:
- access_token = request.GET['access_token']
- else:
- return None
-
- return self.authenticate_credentials(request, access_token)
-
- def authenticate_credentials(self, request, access_token):
- """
- Authenticate the request, given the access token.
- """
-
- try:
- token = oauth2_provider.oauth2.models.AccessToken.objects.select_related('user')
- # provider_now switches to timezone aware datetime when
- # the oauth2_provider version supports to it.
- token = token.get(token=access_token, expires__gt=provider_now())
- except oauth2_provider.oauth2.models.AccessToken.DoesNotExist:
- raise exceptions.AuthenticationFailed('Invalid token')
-
- user = token.user
-
- if not user.is_active:
- msg = 'User inactive or deleted: %s' % user.get_username()
- raise exceptions.AuthenticationFailed(msg)
-
- return (user, token)
-
- def authenticate_header(self, request):
- """
- Bearer is the only finalized type currently
-
- Check details on the `OAuth2Authentication.authenticate` method
- """
- return 'Bearer realm="%s"' % self.www_authenticate_realm
diff --git a/rest_framework/compat.py b/rest_framework/compat.py
index 52db9625..08dd9df6 100644
--- a/rest_framework/compat.py
+++ b/rest_framework/compat.py
@@ -237,63 +237,6 @@ except ImportError:
apply_markdown = None
-# XML is optional
-try:
- import defusedxml.ElementTree as etree
-except ImportError:
- etree = None
-
-
-# OAuth2 is optional
-try:
- # Note: The `oauth2` package actually provides oauth1.0a support. Urg.
- import oauth2 as oauth
-except ImportError:
- oauth = None
-
-
-# OAuthProvider is optional
-try:
- import oauth_provider
- from oauth_provider.store import store as oauth_provider_store
-
- # check_nonce's calling signature in django-oauth-plus changes sometime
- # between versions 2.0 and 2.2.1
- def check_nonce(request, oauth_request, oauth_nonce, oauth_timestamp):
- check_nonce_args = inspect.getargspec(oauth_provider_store.check_nonce).args
- if 'timestamp' in check_nonce_args:
- return oauth_provider_store.check_nonce(
- request, oauth_request, oauth_nonce, oauth_timestamp
- )
- return oauth_provider_store.check_nonce(
- request, oauth_request, oauth_nonce
- )
-
-except (ImportError, ImproperlyConfigured):
- oauth_provider = None
- oauth_provider_store = None
- check_nonce = None
-
-
-# OAuth 2 support is optional
-try:
- import provider as oauth2_provider
- from provider import scope as oauth2_provider_scope
- from provider import constants as oauth2_constants
- if oauth2_provider.__version__ in ('0.2.3', '0.2.4'):
- # 0.2.3 and 0.2.4 are supported version that do not support
- # timezone aware datetimes
- import datetime
- provider_now = datetime.datetime.now
- else:
- # Any other supported version does use timezone aware datetimes
- from django.utils.timezone import now as provider_now
-except ImportError:
- oauth2_provider = None
- oauth2_provider_scope = None
- oauth2_constants = None
- provider_now = None
-
# `seperators` argument to `json.dumps()` differs between 2.x and 3.x
# See: http://bugs.python.org/issue22767
if six.PY3:
diff --git a/rest_framework/parsers.py b/rest_framework/parsers.py
index e6bb75f6..1960e5a8 100644
--- a/rest_framework/parsers.py
+++ b/rest_framework/parsers.py
@@ -12,12 +12,10 @@ from django.http import QueryDict
from django.http.multipartparser import MultiPartParser as DjangoMultiPartParser
from django.http.multipartparser import MultiPartParserError, parse_header, ChunkIter
from django.utils import six
-from rest_framework.compat import etree, force_text, urlparse
+from rest_framework.compat import force_text, urlparse
from rest_framework.exceptions import ParseError
from rest_framework import renderers
import json
-import datetime
-import decimal
class DataAndFiles(object):
@@ -113,78 +111,6 @@ class MultiPartParser(BaseParser):
raise ParseError('Multipart form parse error - %s' % six.text_type(exc))
-class XMLParser(BaseParser):
- """
- XML parser.
- """
-
- media_type = 'application/xml'
-
- def parse(self, stream, media_type=None, parser_context=None):
- """
- Parses the incoming bytestream as XML and returns the resulting data.
- """
- assert etree, 'XMLParser requires defusedxml to be installed'
-
- parser_context = parser_context or {}
- encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
- parser = etree.DefusedXMLParser(encoding=encoding)
- try:
- tree = etree.parse(stream, parser=parser, forbid_dtd=True)
- except (etree.ParseError, ValueError) as exc:
- raise ParseError('XML parse error - %s' % six.text_type(exc))
- data = self._xml_convert(tree.getroot())
-
- return data
-
- def _xml_convert(self, element):
- """
- convert the xml `element` into the corresponding python object
- """
-
- children = list(element)
-
- if len(children) == 0:
- return self._type_convert(element.text)
- else:
- # if the fist child tag is list-item means all children are list-item
- if children[0].tag == "list-item":
- data = []
- for child in children:
- data.append(self._xml_convert(child))
- else:
- data = {}
- for child in children:
- data[child.tag] = self._xml_convert(child)
-
- return data
-
- def _type_convert(self, value):
- """
- Converts the value returned by the XMl parse into the equivalent
- Python type
- """
- if value is None:
- return value
-
- try:
- return datetime.datetime.strptime(value, '%Y-%m-%d %H:%M:%S')
- except ValueError:
- pass
-
- try:
- return int(value)
- except ValueError:
- pass
-
- try:
- return decimal.Decimal(value)
- except decimal.InvalidOperation:
- pass
-
- return value
-
-
class FileUploadParser(BaseParser):
"""
Parser for file upload data.
diff --git a/rest_framework/permissions.py b/rest_framework/permissions.py
index 29f60d6d..7c498645 100644
--- a/rest_framework/permissions.py
+++ b/rest_framework/permissions.py
@@ -3,8 +3,7 @@ Provides a set of pluggable permission policies.
"""
from __future__ import unicode_literals
from django.http import Http404
-from rest_framework.compat import (get_model_name, oauth2_provider_scope,
- oauth2_constants)
+from rest_framework.compat import get_model_name
SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS']
@@ -199,28 +198,3 @@ class DjangoObjectPermissions(DjangoModelPermissions):
return False
return True
-
-
-class TokenHasReadWriteScope(BasePermission):
- """
- The request is authenticated as a user and the token used has the right scope
- """
-
- def has_permission(self, request, view):
- token = request.auth
- read_only = request.method in SAFE_METHODS
-
- if not token:
- return False
-
- if hasattr(token, 'resource'): # OAuth 1
- return read_only or not request.auth.resource.is_readonly
- elif hasattr(token, 'scope'): # OAuth 2
- required = oauth2_constants.READ if read_only else oauth2_constants.WRITE
- return oauth2_provider_scope.check(required, request.auth.scope)
-
- assert False, (
- 'TokenHasReadWriteScope requires either the'
- '`OAuthAuthentication` or `OAuth2Authentication` authentication '
- 'class to be used.'
- )
diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py
index a6e4f1bb..173e48dc 100644
--- a/rest_framework/renderers.py
+++ b/rest_framework/renderers.py
@@ -16,11 +16,8 @@ from django.http.multipartparser import parse_header
from django.template import Context, RequestContext, loader, Template
from django.test.client import encode_multipart
from django.utils import six
-from django.utils.xmlutils import SimplerXMLGenerator
from rest_framework import exceptions, serializers, status, VERSION
-from rest_framework.compat import (
- SHORT_SEPARATORS, LONG_SEPARATORS, StringIO, smart_text
-)
+from rest_framework.compat import SHORT_SEPARATORS, LONG_SEPARATORS
from rest_framework.exceptions import ParseError
from rest_framework.settings import api_settings
from rest_framework.request import is_form_media_type, override_method
@@ -106,89 +103,6 @@ class JSONRenderer(BaseRenderer):
return ret
-class JSONPRenderer(JSONRenderer):
- """
- Renderer which serializes to json,
- wrapping the json output in a callback function.
- """
-
- media_type = 'application/javascript'
- format = 'jsonp'
- callback_parameter = 'callback'
- default_callback = 'callback'
- charset = 'utf-8'
-
- def get_callback(self, renderer_context):
- """
- Determine the name of the callback to wrap around the json output.
- """
- request = renderer_context.get('request', None)
- params = request and request.query_params or {}
- return params.get(self.callback_parameter, self.default_callback)
-
- def render(self, data, accepted_media_type=None, renderer_context=None):
- """
- Renders into jsonp, wrapping the json output in a callback function.
-
- Clients may set the callback function name using a query parameter
- on the URL, for example: ?callback=exampleCallbackName
- """
- renderer_context = renderer_context or {}
- callback = self.get_callback(renderer_context)
- json = super(JSONPRenderer, self).render(data, accepted_media_type,
- renderer_context)
- return callback.encode(self.charset) + b'(' + json + b');'
-
-
-class XMLRenderer(BaseRenderer):
- """
- Renderer which serializes to XML.
- """
-
- media_type = 'application/xml'
- format = 'xml'
- charset = 'utf-8'
-
- def render(self, data, accepted_media_type=None, renderer_context=None):
- """
- Renders `data` into serialized XML.
- """
- if data is None:
- return ''
-
- stream = StringIO()
-
- xml = SimplerXMLGenerator(stream, self.charset)
- xml.startDocument()
- xml.startElement("root", {})
-
- self._to_xml(xml, data)
-
- xml.endElement("root")
- xml.endDocument()
- return stream.getvalue()
-
- def _to_xml(self, xml, data):
- if isinstance(data, (list, tuple)):
- for item in data:
- xml.startElement("list-item", {})
- self._to_xml(xml, item)
- xml.endElement("list-item")
-
- elif isinstance(data, dict):
- for key, value in six.iteritems(data):
- xml.startElement(key, {})
- self._to_xml(xml, value)
- xml.endElement(key)
-
- elif data is None:
- # Don't output any value
- pass
-
- else:
- xml.characters(smart_text(data))
-
-
class TemplateHTMLRenderer(BaseRenderer):
"""
An HTML renderer for use with templates.