ó
O'—^c           @  sG  d  d l  m Z d  d l Z d  d l Z d  d l Z d  d l Z d  d l m Z d  d l m	 Z	 d  d l
 m Z d  d l m Z d  d l m Z d d	 l m Z d d
 l m Z m Z m Z m Z m Z d d l m Z e j d ƒ Z i e j f d 6e j f d 6e j f d 6e j e j e j f d 6Z d e f d „  ƒ  YZ  d S(   iÿÿÿÿ(   t   unicode_literalsN(   t	   timedelta(   t   timezone(   t   authenticate(   t   ObjectDoesNotExist(   t   RequestValidatori   (   t   unquote_plus(   t   Grantt   AccessTokent   RefreshTokent   get_application_modelt   AbstractApplication(   t   oauth2_settingsu   oauth2_provideru   authorization_codeu   passwordu   client_credentialsu   refresh_tokent   OAuth2Validatorc           B  sà   e  Z d  „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z	 d „  Z
 d	 „  Z d
 „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z RS(   c         C  sg   | j  j d d ƒ } | s d S| j d d ƒ } t | ƒ d k rG d S| \ } } | d k rc d S| S(   uk   
        Return authentication string if request contains basic auth credentials, else return None
        u   HTTP_AUTHORIZATIONu    i   i   u   BasicN(   t   headerst   gett   Nonet   splitt   len(   t   selft   requestt   autht   splittedt	   auth_typet   auth_string(    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   _extract_basic_auth   s    c         C  s]  |  j  | ƒ } | s t Sy | j } Wn t k
 r? d } n Xt | t j ƒ rd | j | ƒ } n  y t j	 | ƒ } Wn+ t
 t j f k
 r¤ t j d | ƒ t SXy | j | ƒ } Wn% t k
 rß t j d | | ƒ t SXt t | j d d ƒ ƒ \ } } |  j | | ƒ d k r.t j d | ƒ t S| j j | k rUt j d | ƒ t St Sd S(	   uÏ   
        Authenticates with HTTP Basic Auth.

        Note: as stated in rfc:`2.3.1`, client_id and client_secret must be encoded with
        "application/x-www-form-urlencoded" encoding algorithm.
        u   utf-8u0   Failed basic auth: %s can't be decoded as base64u7   Failed basic auth: %s can't be decoded as unicode by %su   :i   u0   Failed basic auth: Application %s does not existu)   Failed basic auth: wrong client secret %sN(   R   t   Falset   encodingt   AttributeErrort
   isinstancet   sixt   string_typest   encodet   base64t	   b64decodet	   TypeErrort   binasciit   Errort   logt   debugt   decodet   UnicodeDecodeErrort   mapR   R   t   _load_applicationR   t   clientt   client_secrett   True(   R   R   R   R   t   b64_decodedt   auth_string_decodedt	   client_idR-   (    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   _authenticate_basic_auth0   s:    
	!c         C  s‡   y | j  } | j } Wn t k
 r* t SX|  j | | ƒ d k rX t j d | ƒ t S| j j | k r t j d | ƒ t St	 Sd S(   u9  
        Try to authenticate the client using client_id and client_secret parameters
        included in body.

        Remember that this method is NOT RECOMMENDED and SHOULD be limited to clients unable to
        directly utilize the HTTP Basic authentication scheme. See rfc:`2.3.1` for more details.
        u0   Failed body auth: Application %s does not existsu(   Failed body auth: wrong client secret %sN(
   R1   R-   R   R   R+   R   R&   R'   R,   R.   (   R   R   R1   R-   (    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   _authenticate_request_body^   s    		c         C  s}   t  | d ƒ s t d ƒ ‚ t ƒ  } y, | j pB | j j d | ƒ | _ | j SWn& | j k
 rx t j d | ƒ d SXd S(   u…   
        If request.client was not set, load application instance for given client_id and store it
        in request.client
        u   clientu,   'request' instance has no 'client' attributeR1   u9   Failed body authentication: Application %s does not existN(
   t   hasattrt   AssertionErrorR
   R,   t   objectsR   t   DoesNotExistR&   R'   R   (   R   R1   R   t   Application(    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyR+   v   s    	!c         O  s™   |  j  | ƒ r t Sy | j r, | j r, t SWn t k
 rM t j d ƒ n X|  j | j | ƒ | j r} | j j	 t
 j k St t |  ƒ j | | | Ž S(   uh  
        Determine if the client has to be authenticated

        This method is called only for grant types that supports client authentication:
            * Authorization code grant
            * Resource owner password grant
            * Refresh token grant

        If the request contains authorization headers, always authenticate the client no matter
        the grant type.

        If the request does not contain authorization headers, proceed with authentication only if
        the client is of type `Confidential`.

        If something goes wrong, call oauthlib implementation of the method.
        u\   Client id or client secret not provided, proceed evaluating if authentication is required...(   R   R.   R1   R-   R   R&   R'   R+   R,   t   client_typeR   t   CLIENT_CONFIDENTIALt   superR   t   client_authentication_required(   R   R   t   argst   kwargs(    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyR<   ‡   s    	c         O  s+   |  j  | ƒ } | s' |  j | ƒ } n  | S(   uà  
        Check if client exists and it's authenticating itself as in rfc:`3.2.1`

        First we try to authenticate with HTTP Basic Auth, and that is the PREFERRED
        authentication method.
        Whether this fails we support including the client credentials in the request-body, but
        this method is NOT RECOMMENDED and SHOULD be limited to clients unable to directly utilize
        the HTTP Basic authentication scheme. See rfc:`2.3.1` for more details
        (   R2   R3   (   R   R   R=   R>   t   authenticated(    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   authenticate_client©   s    
c         O  sL   |  j  | | ƒ d k	 rH t j d | | j j f ƒ | j j t j k St S(   uð   
        If we are here, the client did not authenticate itself as in rfc:`3.2.1` and we can
        proceed only if the client exists and it's not of type 'Confidential'.
        Also assign Application instance to request.client.
        u   Application %s has type %sN(	   R+   R   R&   R'   R,   R9   R   R:   R   (   R   R1   R   R=   R>   (    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   authenticate_client_idº   s    c         O  s(   t  j j d | d | ƒ } | j | ƒ S(   uc   
        Ensure the redirect_uri is listed in the Application instance redirect_uris field
        t   codet   application(   R   R6   R   t   redirect_uri_allowed(   R   R1   RB   t   redirect_uriR,   R=   R>   t   grant(    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   confirm_redirect_uriÅ   s    c         O  s,   t  j j d | d | j ƒ } | j ƒ  d S(   uQ   
        Remove the temporary grant used to swap the authorization token
        RB   RC   N(   R   R6   R   R,   t   delete(   R   R1   RB   R   R=   R>   RF   (    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   invalidate_authorization_codeÌ   s    c         O  s   |  j  | | ƒ d k	 S(   u{   
        Ensure an Application exists with given client_id. If it exists, it's assigned to
        request.client.
        N(   R+   R   (   R   R1   R   R=   R>   (    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   validate_client_idÓ   s    c         O  s
   | j  j S(   N(   R,   t   default_redirect_uri(   R   R1   R   R=   R>   (    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   get_default_redirect_uriÚ   s    c         C  sŒ   | s
 t  Syf t j j d d ƒ j d | ƒ } | j | ƒ rk | j | _ | j | _ | | _	 | | _
 t St  SWn t j k
 r‡ t  SXd S(   uX   
        When users try to access resources, check that provided token is valid
        u   applicationu   usert   tokenN(   R   R   R6   t   select_relatedR   t   is_validRC   R,   t   usert   scopest   access_tokenR.   R7   (   R   RM   RQ   R   RR   (    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   validate_bearer_tokenÝ   s    			c         O  sp   yT t  j j d | d | ƒ } | j ƒ  sO | j j d ƒ | _ | j | _ t St	 SWn t  j
 k
 rk t	 SXd  S(   NRB   RC   u    (   R   R6   R   t
   is_expiredt   scopeR   RQ   RP   R.   R   R7   (   R   R1   RB   R,   R   R=   R>   RF   (    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   validate_codeó   s    c         O  s&   | t  k s t ‚ | j j t  | k S(   uk   
        Validate both grant_type is a valid string and grant_type is allowed for current workflow
        (   t   GRANT_TYPE_MAPPINGR5   R,   t   authorization_grant_type(   R   R1   t
   grant_typeR,   R   R=   R>   (    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   validate_grant_typeÿ   s    c         O  s@   | d k r | j  t j k S| d k r8 | j  t j k St Sd S(   u¼   
        We currently do not support the Authorization Endpoint Response Types registry as in
        rfc:`8.4`, so validate the response_type only if it matches 'code' or 'token'
        u   codeu   tokenN(   RX   R   t   GRANT_AUTHORIZATION_CODEt   GRANT_IMPLICITR   (   R   R1   t   response_typeR,   R   R=   R>   (    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   validate_response_type  s
    c         O  s   t  | ƒ j t  t j ƒ ƒ S(   uZ   
        Ensure required scopes are permitted (as specified in the settings file)
        (   t   sett   issubsetR   t   _SCOPES(   R   R1   RQ   R,   R   R=   R>   (    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   validate_scopes  s    c         O  s   t  j S(   N(   R   t   _DEFAULT_SCOPES(   R   R1   R   R=   R>   (    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   get_default_scopes  s    c         O  s   | j  j | ƒ S(   N(   R,   RD   (   R   R1   RE   R   R=   R>   (    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   validate_redirect_uri  s    c         O  sp   t  j ƒ  t d t j ƒ } t d | j d | j d | d d | d | j d d	 j	 | j
 ƒ ƒ } | j ƒ  d  S(
   Nt   secondsRC   RP   RB   u   codet   expiresRE   RU   u    (   R   t   nowR   R   t!   AUTHORIZATION_CODE_EXPIRE_SECONDSR   R,   RP   RE   t   joinRQ   t   save(   R   R1   RB   R   R=   R>   Rg   t   g(    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   save_authorization_code  s    "c         O  s  | j  rO y  t j j d | j  ƒ j ƒ  WqO t j k
 rK d sL t ‚ qO Xn  t j ƒ  t	 d t
 j ƒ } | j d k r† d | _ n  t d | j d | d d | d | d d	 | j ƒ } | j ƒ  d
 | k r	t d | j d | d
 d	 | j d | ƒ } | j ƒ  n  t
 j | d <d S(   u|   
        Save access and refresh token, If refresh token is issued, remove old refresh tokens as
        in rfc:`6`
        RM   Rf   u   client_credentialsRP   RU   u   scopeRg   u   access_tokenRC   u   refresh_tokenRR   u
   expires_inN(    (   t   refresh_tokenR	   R6   R   t   revokeR7   R5   R   Rh   R   R   t   ACCESS_TOKEN_EXPIRE_SECONDSRY   R   RP   R   R,   Rk   (   R   RM   R   R=   R>   Rg   RR   Rn   (    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   save_bearer_token&  s.    	 	


	
		c   
      O  sË   | d k r d } n  i t d 6t d 6} | j | t ƒ } y | j j d | ƒ j ƒ  Wnl t k
 rÆ x\ g  | j ƒ  D] } | | k rx | ^ qx D]+ }	 t t	 d „  |	 j j
 d | ƒ ƒ ƒ q” Wn Xd S(   uß   
        Revoke an access or refresh token.

        :param token: The token string.
        :param token_type_hint: access_token or refresh_token.
        :param request: The HTTP Request (oauthlib.common.Request)
        u   access_tokenu   refresh_tokenRM   c         S  s
   |  j  ƒ  S(   N(   Ro   (   t   t(    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   <lambda>`  t    N(   u   access_tokenu   refresh_token(   R   R   R	   R   R6   Ro   R   t   valuest   listR*   t   filter(
   R   RM   t   token_type_hintR   R=   R>   t   token_typest
   token_typet   _tt
   other_type(    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   revoke_tokenJ  s    	
2c         O  s;   t  d | d | ƒ } | d k	 r7 | j r7 | | _ t St S(   uS   
        Check username and password correspond to a valid and active User
        t   usernamet   passwordN(   R   R   t	   is_activeRP   R.   R   (   R   R~   R   R,   R   R=   R>   t   u(    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   validate_userb  s
    	c         O  s   | j  } | j j S(   N(   t   refresh_token_instanceRR   RU   (   R   Rn   R   R=   R>   t   rt(    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   get_original_scopesl  s    	c         O  sc   yG t  j j d | ƒ } | j | _ | j | _ | | _ | j | k SWn t  j k
 r^ t	 SXd S(   u„   
        Check refresh_token exists and refers to the right client.
        Also attach User instance to the request object
        RM   N(
   R	   R6   R   RP   RM   Rn   Rƒ   RC   R7   R   (   R   Rn   R,   R   R=   R>   R„   (    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   validate_refresh_tokenr  s    	(   t   __name__t
   __module__R   R2   R3   R+   R<   R@   RA   RG   RI   RJ   RL   RS   RV   RZ   R^   Rb   Rd   Re   Rm   Rq   R}   R‚   R…   R†   (    (    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyR      s0   		.			"															$		
	(!   t
   __future__R    R   R!   R$   t   loggingt   datetimeR   t   django.utilsR   t   django.contrib.authR   t   django.core.exceptionsR   t   oauthlib.oauth2R   t   compatR   t   modelsR   R   R	   R
   R   t   settingsR   t	   getLoggerR&   R[   t   GRANT_PASSWORDt   GRANT_CLIENT_CREDENTIALSRW   R   (    (    (    sC   /tmp/pip-unpacked-wheel-ndW12l/oauth2_provider/oauth2_validators.pyt   <module>   s(   (