Advertisement
inqw

Untitled

Aug 6th, 2017
157
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.90 KB | None | 0 0
  1. from requests import request, ConnectionError
  2.  
  3. from social.utils import SSLHttpAdapter, module_member, parse_qs, user_agent
  4. from social.exceptions import AuthFailed
  5.  
  6.  
  7. class BaseAuth(object):
  8.     """A django.contrib.auth backend that authenticates the user based on
  9.    a authentication provider response"""
  10.     name = ''  # provider name, it's stored in database
  11.     supports_inactive_user = False  # Django auth
  12.     ID_KEY = None
  13.     EXTRA_DATA = None
  14.     REQUIRES_EMAIL_VALIDATION = False
  15.     SEND_USER_AGENT = False
  16.     SSL_PROTOCOL = None
  17.  
  18.     def __init__(self, strategy=None, redirect_uri=None):
  19.         self.strategy = strategy
  20.         self.redirect_uri = redirect_uri
  21.         self.data = {}
  22.         if strategy:
  23.             self.data = self.strategy.request_data()
  24.             self.redirect_uri = self.strategy.absolute_uri(
  25.                 self.redirect_uri
  26.             )
  27.  
  28.     def setting(self, name, default=None):
  29.         """Return setting value from strategy"""
  30.         return self.strategy.setting(name, default=default, backend=self)
  31.  
  32.     def start(self):
  33.         # Clean any partial pipeline info before starting the process
  34.         self.strategy.clean_partial_pipeline()
  35.         if self.uses_redirect():
  36.             return self.strategy.redirect(self.auth_url())
  37.         else:
  38.             return self.strategy.html(self.auth_html())
  39.  
  40.     def complete(self, *args, **kwargs):
  41.         return self.auth_complete(*args, **kwargs)
  42.  
  43.     def auth_url(self):
  44.         """Must return redirect URL to auth provider"""
  45.         raise NotImplementedError('Implement in subclass')
  46.  
  47.     def auth_html(self):
  48.         """Must return login HTML content returned by provider"""
  49.         raise NotImplementedError('Implement in subclass')
  50.  
  51.     def auth_complete(self, *args, **kwargs):
  52.         """Completes loging process, must return user instance"""
  53.         raise NotImplementedError('Implement in subclass')
  54.  
  55.     def process_error(self, data):
  56.         """Process data for errors, raise exception if needed.
  57.        Call this method on any override of auth_complete."""
  58.         pass
  59.  
  60.     def authenticate(self, *args, **kwargs):
  61.         """Authenticate user using social credentials
  62.  
  63.        Authentication is made if this is the correct backend, backend
  64.        verification is made by kwargs inspection for current backend
  65.        name presence.
  66.        """
  67.         # Validate backend and arguments. Require that the Social Auth
  68.         # response be passed in as a keyword argument, to make sure we
  69.         # don't match the username/password calling conventions of
  70.         # authenticate.
  71.         if 'backend' not in kwargs or kwargs['backend'].name != self.name or \
  72.            'strategy' not in kwargs or 'response' not in kwargs:
  73.             return None
  74.  
  75.         self.strategy = self.strategy or kwargs.get('strategy')
  76.         self.redirect_uri = self.redirect_uri or kwargs.get('redirect_uri')
  77.         self.data = self.strategy.request_data()
  78.         pipeline = self.strategy.get_pipeline()
  79.         kwargs.setdefault('is_new', False)
  80.         if 'pipeline_index' in kwargs:
  81.             pipeline = pipeline[kwargs['pipeline_index']:]
  82.         return self.pipeline(pipeline, *args, **kwargs)
  83.  
  84.     def pipeline(self, pipeline, pipeline_index=0, *args, **kwargs):
  85.         out = self.run_pipeline(pipeline, pipeline_index, *args, **kwargs)
  86.         if not isinstance(out, dict):
  87.             return out
  88.         user = out.get('user')
  89.         if user:
  90.             user.social_user = out.get('social')
  91.             user.is_new = out.get('is_new')
  92.         return user
  93.  
  94.     def disconnect(self, *args, **kwargs):
  95.         pipeline = self.strategy.get_disconnect_pipeline()
  96.         if 'pipeline_index' in kwargs:
  97.             pipeline = pipeline[kwargs['pipeline_index']:]
  98.         kwargs['name'] = self.name
  99.         kwargs['user_storage'] = self.strategy.storage.user
  100.         return self.run_pipeline(pipeline, *args, **kwargs)
  101.  
  102.     def run_pipeline(self, pipeline, pipeline_index=0, *args, **kwargs):
  103.         out = kwargs.copy()
  104.         out.setdefault('strategy', self.strategy)
  105.         out.setdefault('backend', out.pop(self.name, None) or self)
  106.         out.setdefault('request', self.strategy.request_data())
  107.         out.setdefault('details', {})
  108.  
  109.         if not isinstance(pipeline_index, int) or pipeline_index < 0 or pipeline_index >= len(pipeline):
  110.             pipeline_index = 0
  111.  
  112.         for idx, name in enumerate(pipeline):
  113.             out['pipeline_index'] = pipeline_index + idx
  114.             func = module_member(name)
  115.             result = func(*args, **out) or {}
  116.             if not isinstance(result, dict):
  117.                 return result
  118.             out.update(result)
  119.         self.strategy.clean_partial_pipeline()
  120.         return out
  121.  
  122.     def extra_data(self, user, uid, response, details=None, *args, **kwargs):
  123.         """Return default extra data to store in extra_data field"""
  124.         data = {}
  125.         for entry in (self.EXTRA_DATA or []) + self.setting('EXTRA_DATA', []):
  126.             if not isinstance(entry, (list, tuple)):
  127.                 entry = (entry,)
  128.             size = len(entry)
  129.             if size >= 1 and size <= 3:
  130.                 if size == 3:
  131.                     name, alias, discard = entry
  132.                 elif size == 2:
  133.                     (name, alias), discard = entry, False
  134.                 elif size == 1:
  135.                     name = alias = entry[0]
  136.                     discard = False
  137.                 value = response.get(name) or details.get(name)
  138.                 if discard and not value:
  139.                     continue
  140.                 data[alias] = value
  141.         return data
  142.  
  143.     def auth_allowed(self, response, details):
  144.         """Return True if the user should be allowed to authenticate, by
  145.        default check if email is whitelisted (if there's a whitelist)"""
  146.         emails = self.setting('WHITELISTED_EMAILS', [])
  147.         domains = self.setting('WHITELISTED_DOMAINS', [])
  148.         email = details.get('email')
  149.         allowed = True
  150.         if email and (emails or domains):
  151.             domain = email.split('@', 1)[1]
  152.             allowed = email in emails or domain in domains
  153.         return allowed
  154.  
  155.     def get_user_id(self, details, response):
  156.         """Return a unique ID for the current user, by default from server
  157.        response."""
  158.         return response.get(self.ID_KEY)
  159.  
  160.     def get_user_details(self, response):
  161.         """Must return user details in a know internal struct:
  162.            {'username': <username if any>,
  163.             'email': <user email if any>,
  164.             'fullname': <user full name if any>,
  165.             'first_name': <user first name if any>,
  166.             'last_name': <user last name if any>}
  167.        """
  168.         raise NotImplementedError('Implement in subclass')
  169.  
  170.     def get_user_names(self, fullname='', first_name='', last_name=''):
  171.         # Avoid None values
  172.         fullname = fullname or ''
  173.         first_name = first_name or ''
  174.         last_name = last_name or ''
  175.         if fullname and not (first_name or last_name):
  176.             try:
  177.                 first_name, last_name = fullname.split(' ', 1)
  178.             except ValueError:
  179.                 first_name = first_name or fullname or ''
  180.                 last_name = last_name or ''
  181.         fullname = fullname or ' '.join((first_name, last_name))
  182.         return fullname.strip(), first_name.strip(), last_name.strip()
  183.  
  184.     def get_user(self, user_id):
  185.         """
  186.        Return user with given ID from the User model used by this backend.
  187.        This is called by django.contrib.auth.middleware.
  188.        """
  189.         from social.strategies.utils import get_current_strategy
  190.         strategy = self.strategy or get_current_strategy()
  191.         return strategy.get_user(user_id)
  192.  
  193.     def continue_pipeline(self, *args, **kwargs):
  194.         """Continue previous halted pipeline"""
  195.         kwargs.update({'backend': self, 'strategy': self.strategy})
  196.         return self.authenticate(*args, **kwargs)
  197.  
  198.     def auth_extra_arguments(self):
  199.         """Return extra arguments needed on auth process. The defaults can be
  200.        overridden by GET parameters."""
  201.         extra_arguments = self.setting('AUTH_EXTRA_ARGUMENTS', {}).copy()
  202.         extra_arguments.update((key, self.data[key]) for key in extra_arguments
  203.                                     if key in self.data)
  204.         return extra_arguments
  205.  
  206.     def uses_redirect(self):
  207.         """Return True if this provider uses redirect url method,
  208.        otherwise return false."""
  209.         return True
  210.  
  211.     def request(self, url, method='GET', *args, **kwargs):
  212.         kwargs.setdefault('headers', {})
  213.         if self.setting('VERIFY_SSL') is not None:
  214.             kwargs.setdefault('verify', self.setting('VERIFY_SSL'))
  215.         kwargs.setdefault('timeout', self.setting('REQUESTS_TIMEOUT') or
  216.                                      self.setting('URLOPEN_TIMEOUT'))
  217.         if self.SEND_USER_AGENT and 'User-Agent' not in kwargs['headers']:
  218.             kwargs['headers']['User-Agent'] = user_agent()
  219.  
  220.         try:
  221.             if self.SSL_PROTOCOL:
  222.                 session = SSLHttpAdapter.ssl_adapter_session(self.SSL_PROTOCOL)
  223.                 response = session.request(method, url, *args, **kwargs)
  224.             else:
  225.                 response = request(method, url, *args, **kwargs)
  226.         except ConnectionError as err:
  227.             raise AuthFailed(self, str(err))
  228.         response.raise_for_status()
  229.         return response
  230.  
  231.     def get_json(self, url, *args, **kwargs):
  232.         return self.request(url, *args, **kwargs).json()
  233.  
  234.     def get_querystring(self, url, *args, **kwargs):
  235.         return parse_qs(self.request(url, *args, **kwargs).text)
  236.  
  237.     def get_key_and_secret(self):
  238.         """Return tuple with Consumer Key and Consumer Secret for current
  239.        service provider. Must return (key, secret), order *must* be respected.
  240.        """
  241.         return self.setting('KEY'), self.setting('SECRET')
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement