Advertisement
Guest User

Untitled

a guest
Aug 22nd, 2019
208
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.43 KB | None | 0 0
  1. from django.conf import settings
  2. from firebase_admin import auth as firebase_auth
  3. from django.utils.encoding import smart_text
  4. from django.utils import timezone
  5. from django.contrib.auth import get_user_model
  6. from django.contrib.auth.models import AnonymousUser
  7. from rest_framework import (
  8.     authentication,
  9.     exceptions
  10. )
  11. from rest_framework.settings import api_settings
  12. from django.utils.translation import ugettext_lazy as _
  13.  
  14. User = get_user_model()
  15.  
  16.  
  17. class BaseFirebaseAuthentication(authentication.BaseAuthentication):
  18.     """
  19.    Token based authentication using firebase.
  20.    """
  21.  
  22.     def authenticate(self, request):
  23.         """
  24.        With ALLOW_ANONYMOUS_REQUESTS, set request.user to an AnonymousUser,
  25.        allowing us to configure access at the permissions level.
  26.        """
  27.         authorization_header = authentication.get_authorization_header(request)
  28.         if getattr(api_settings, 'ALLOW_ANONYMOUS_REQUESTS', False) and not authorization_header:
  29.             return AnonymousUser(), None
  30.  
  31.         """
  32.        Returns a tuple of len(2) of `User` and the decoded firebase token if
  33.        a valid signature has been supplied using Firebase authentication.
  34.        """
  35.         firebase_token = self.get_token(request)
  36.  
  37.         decoded_token = self.decode_token(firebase_token)
  38.  
  39.         uid = self.authenticate_token(decoded_token)
  40.  
  41.         local_user = self.get_local_user(uid)
  42.  
  43.         return local_user, decoded_token
  44.  
  45.     def get_token(self, request):
  46.         raise NotImplementedError('get_token() has not been implemented.')
  47.  
  48.     def decode_token(self, firebase_token):
  49.         raise NotImplementedError('decode_token() has not been implemented.')
  50.  
  51.     def authenticate_token(self, decoded_token):
  52.         raise NotImplementedError('authenticate_token() has not been implemented.')
  53.  
  54.     def get_local_user(self, firebase_user):
  55.         raise NotImplementedError('get_or_create_local_user() has not been implemented.')
  56.  
  57.  
  58. class FirebaseAuthentication(BaseFirebaseAuthentication):
  59.     """
  60.    Clients should authenticate by passing the token key in the
  61.    'Authorization' HTTP header, prepended with the string specified in the
  62.    settings.FIREBASE_AUTH_HEADER_PREFIX setting (Default = 'Token')
  63.    """
  64.     www_authenticate_realm = 'api'
  65.  
  66.     def get_token(self, request):
  67.         """
  68.        Parse Authorization header and retrieve JWT
  69.        """
  70.         authorization_header = \
  71.             authentication.get_authorization_header(request).split()
  72.         auth_header_prefix = settings.FIREBASE_AUTH_HEADER_PREFIX.lower()
  73.  
  74.         if not authorization_header or len(authorization_header) != 2:
  75.             raise exceptions.AuthenticationFailed(
  76.                 _('Invalid Authorization header format, expecting: JWT <token>.')
  77.             )
  78.  
  79.         if smart_text(authorization_header[0].lower()) != auth_header_prefix:
  80.             raise exceptions.AuthenticationFailed(
  81.                 _('Invalid Authorization header prefix, expecting: JWT.')
  82.             )
  83.  
  84.         return authorization_header[1]
  85.  
  86.     def decode_token(self, firebase_token):
  87.         """
  88.        Attempt to verify JWT from Authorization header with Firebase and
  89.        return the decoded token
  90.        """
  91.         try:
  92.             return firebase_auth.verify_id_token(
  93.                 firebase_token,
  94.                 check_revoked=True
  95.             )
  96.         except ValueError as exc:
  97.             raise exceptions.AuthenticationFailed(
  98.                _('JWT was found to be invalid, or the App’s project ID cannot be determined.')
  99.             )
  100.         except firebase_auth.AuthError as exc:
  101.             if exc.code == 'ID_TOKEN_REVOKED':
  102.                 raise exceptions.AuthenticationFailed(
  103.                     _('Token revoked, inform the user to reauthenticate or signOut().')
  104.                 )
  105.             else:
  106.                 raise exceptions.AuthenticationFailed(
  107.                     _('Token is invalid.')
  108.                 )
  109.  
  110.     def authenticate_token(self, decoded_token):
  111.         """
  112.        Returns firebase user uid if token is authenticated
  113.        """
  114.         try:
  115.             uid = decoded_token.get('uid')
  116.             return uid
  117.         except ValueError:
  118.             raise exceptions.AuthenticationFailed(
  119.                 _('User ID is None, empty or malformed')
  120.             )
  121.         except firebase_auth.AuthError:
  122.             raise exceptions.AuthenticationFailed(
  123.                 _('Error retrieving the user, or the specified user ID does not exist')
  124.             )
  125.  
  126.     def get_local_user(self, uid):
  127.         try:
  128.             user = User.objects.get(username=uid)
  129.             if not user.is_active:
  130.                 raise exceptions.AuthenticationFailed(
  131.                     _('User account is not currently active.')
  132.                 )
  133.             user.last_login = timezone.now()
  134.             user.save()
  135.  
  136.             return user
  137.         except User.DoesNotExist:
  138.             raise exceptions.AuthenticationFailed(_('Invalid token.'))
  139.  
  140.     def authenticate_header(self, request):
  141.         """
  142.        Return a string to be used as the value of the `WWW-Authenticate`
  143.        header in a `401 Unauthenticated` response, or `None` if the
  144.        authentication scheme should return `403 Permission Denied` responses.
  145.        """
  146.         auth_header_prefix = settings.FIREBASE_AUTH_HEADER_PREFIX.lower()
  147.         return '{} realm="{}"'.format(auth_header_prefix, self.www_authenticate_realm)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement