ó
žA/Mc           @   sb  d  Z  e Z d d d d d d d g Z d d	 l Z 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 Z d d	 l Z d d l m Z d d l m Z m Z m Z m Z d d l m Z d Z d Z d Z d Z e e  e! f Z" d e f d „  ƒ  YZ# d e f d „  ƒ  YZ d e f d „  ƒ  YZ$ d e% f d „  ƒ  YZ& d e& f d „  ƒ  YZ' d e& f d „  ƒ  YZ( d e% f d „  ƒ  YZ) d e) f d „  ƒ  YZ* d e+ f d „  ƒ  YZ, d  e, f d! „  ƒ  YZ- d" e, f d# „  ƒ  YZ. d$ e, f d% „  ƒ  YZ/ d& e, f d' „  ƒ  YZ0 d( e, f d) „  ƒ  YZ1 d* e, f d+ „  ƒ  YZ2 d	 S(,   s4   launchpadlib credentials and authentication support.t   AccessTokent   AnonymousAccessTokent    AuthorizeRequestTokenWithBrowsert   CredentialStoret   RequestTokenAuthorizationEnginet   Consumert   CredentialsiÿÿÿÿN(   t   StringIO(   t	   urlencode(   t   urljoin(   t	   HTTPError(   R    R   t   OAuthAuthorizert   SystemWideConsumer(   t   uriss   +request-tokens   +access-tokens   +authorize-tokeni   c           B   s\   e  Z d  Z d Z d Z d Z d „  Z e d „  ƒ Z	 d e
 j e d „ Z e
 j d „ Z RS(   sè   Standard credentials storage and usage class.

    :ivar consumer: The consumer (application)
    :type consumer: `Consumer`
    :ivar access_token: Access information on behalf of the user
    :type access_token: `AccessToken`
    t   urit   dictc         C   s    t  ƒ  } |  j | ƒ | j ƒ  S(   se   Turn this object into a string.

        This should probably be moved into OAuthAuthorizer.
        (   R   t   savet   getvalue(   t   selft   sio(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyt	   serializeI   s    	c         C   s    |  ƒ  } | j  t | ƒ ƒ | S(   s}   Create a `Credentials` object from a serialized string.

        This should probably be moved into OAuthAuthorizer.
        (   t   loadR   (   t   clst   valuet   credentials(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyt   from_stringR   s    	c   	   	   C   s  |  j  d k	 s t d ‚ |  j d k s0 t d ‚ t j | ƒ } t d |  j  j d d d d ƒ } | t } i | d 6} | |  j	 k r“ d	 | d
 <n  t
 j ƒ  j | d d d | d t | ƒ ƒ\ } } | j d k rç t | | ƒ ‚ n  | |  j	 k r4t j | ƒ } | d k	 r| | d <n  t j | ƒ |  _ | St j | ƒ |  _ d | t |  j j f } | d k	 rˆ| |  j _ | d | 7} n  | Sd S(   sã  Request an OAuth token to Launchpad.

        Also store the token in self._request_token.

        This method must not be called on an object with no consumer
        specified or if an access token has already been obtained.

        :param context: The context of this token, that is, its scope of
            validity within Launchpad.
        :param web_root: The URL of the website on which the token
            should be requested.
        :token_format: How the token should be
            presented. URI_TOKEN_FORMAT means just return the URL to
            the page that authorizes the token.  DICT_TOKEN_FORMAT
            means return a dictionary describing the token
            and the site's authentication policy.

        :return: If token_format is URI_TOKEN_FORMAT, the URL for the
            user to authorize the `AccessToken` provided by
            Launchpad. If token_format is DICT_TOKEN_FORMAT, a dict of
            information about the new access token.
        s   Consumer not specified.s   Access token already obtained.t   oauth_consumer_keyt   oauth_signature_methodt	   PLAINTEXTt   oauth_signaturet   &t   Referers   application/jsont   Acceptt   methodt   POSTt   headerst   bodyiÈ   s
   lp.contexts   %s%s?oauth_token=%ss   &lp.context=%sN(   t   consumert   Nonet   AssertionErrort   access_tokenR   t   lookup_web_rootR   t   keyt   request_token_paget   DICT_TOKEN_FORMATt   httplib2t   Httpt   requestR   t   statusR
   t
   simplejsont   loadsR    t   from_paramst   _request_tokenR   t   authorize_token_paget   context(	   R   R6   t   web_roott   token_formatt   paramst   urlR#   t   responset   content(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyt   get_request_token\   s8    	
'	c      
   C   sß   |  j  d k	 s t d ‚ t j | ƒ } t d |  j j d d d |  j  j d d |  j  j ƒ } | t	 } i | d 6} t
 j ƒ  j | d	 d
 d | d t | ƒ ƒ\ } } | j d k rÉ t | | ƒ ‚ n  t j | ƒ |  _ d S(   sd  Exchange the previously obtained request token for an access token.

        This method must not be called unless get_request_token() has been
        called and completed successfully.

        The access token will be stored as self.access_token.

        :param web_root: The base URL of the website that granted the
            request token.
        s5   get_request_token() doesn't seem to have been called.R   R   R   t   oauth_tokenR   s   &%sR   R!   R"   R#   R$   iÈ   N(   R4   R&   R'   R   R)   R   R%   R*   t   secrett   access_token_pageR-   R.   R/   R   R0   R
   R    R   R(   (   R   R7   R9   R:   R#   R;   R<   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyt'   exchange_request_token_for_access_token’   s    
'N(   t   __name__t
   __module__t   __doc__R&   R4   t   URI_TOKEN_FORMATR,   R   t   classmethodR   R   t   STAGING_WEB_ROOTR=   RA   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR   <   s   		
	6c           B   s,   e  Z d  Z e d „  ƒ Z e d „  ƒ Z RS(   s   An OAuth access token.c         C   s3   | d } | d } | j  d ƒ } |  | | | ƒ S(   s:   Create and return a new `AccessToken` from the given dict.R>   t   oauth_token_secrets
   lp.context(   t   get(   R   R9   R*   R?   R6   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR3   ²   s    

c         C   sÆ   t  j | d t ƒ} | d } t | ƒ d k s: t d ‚ | d } | d } t | ƒ d k si t d ‚ | d } | j d ƒ } | d
 k	 r¶ t | ƒ d k s© t d	 ‚ | d } n  |  | | | ƒ S(   s<   Create and return a new `AccessToken` from the given string.t   keep_blank_valuesR>   i   s/   Query string must have exactly one oauth_token.i    RH   s*   Query string must have exactly one secret.s
   lp.contexts*   Query string must have exactly one contextN(   t   cgit   parse_qst   Falset   lenR'   RI   R&   (   R   t   query_stringR9   R*   R?   R6   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR   º   s    



(   RB   RC   RD   RF   R3   R   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR    ¯   s   c           B   s   e  Z d  Z d „  Z RS(   so   An OAuth access token that doesn't authenticate anybody.

    This token can be used for anonymous access.
    c         C   s   t  t |  ƒ j d d ƒ d  S(   Nt    (   t   superR   t   __init__(   R   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRR   Ò   s    (   RB   RC   RD   RR   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR   Í   s   c           B   s>   e  Z d  Z d d „ Z d „  Z d „  Z d „  Z d „  Z RS(   sÖ   Store OAuth credentials locally.

    This is a generic superclass. To implement a specific way of
    storing credentials locally you'll need to subclass this class,
    and implement `do_save` and `do_load`.
    c         C   s   | |  _  d S(   s  Constructor.

        :param credential_save_failed: A callback to be invoked if the
            save to local storage fails. You should never invoke this
            callback yourself! Instead, you should raise an exception
            from do_save().
        N(   t   credential_save_failed(   R   RS   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRR   Þ   s    c         C   sc   y |  j  | | ƒ WnH t k
 r* ‚  n5 t k
 r^ } |  j d k rQ | ‚ n  |  j ƒ  n X| S(   sœ   Save the credentials and invoke the callback on failure.

        Do not override this method when subclassing. Override
        do_save() instead.
        N(   t   do_savet   EXPLOSIVE_ERRORSt	   ExceptionRS   R&   (   R   R   t   unique_consumer_idt   e(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR   è   s    	c         C   s   t  ƒ  ‚ d S(   sõ   Store newly-authorized credentials locally for later use.

        :param credentials: A Credentials object to save.
        :param unique_consumer_id: A string uniquely identifying an
            OAuth consumer on a Launchpad instance.
        N(   t   NotImplementedError(   R   R   RW   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRT   ø   s    c         C   s   |  j  | ƒ S(   s0  Retrieve credentials from a local store.

        This method is the inverse of `save`.

        There's no special behavior in this method--it just calls
        `do_load`. There _is_ special behavior in `save`, and this
        way, developers can remember to implement `do_save` and
        `do_load`, not `do_save` and `load`.

        :param unique_key: A string uniquely identifying an OAuth consumer
            on a Launchpad instance.

        :return: A `Credentials` object if one is found in the local
            store, and None otherise.
        (   t   do_load(   R   t
   unique_key(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR     s    c         C   s   t  ƒ  ‚ d S(   s@  Retrieve credentials from a local store.

        This method is the inverse of `do_save`.

        :param unique_key: A string uniquely identifying an OAuth consumer
            on a Launchpad instance.

        :return: A `Credentials` object if one is found in the local
            store, and None otherise.
        N(   RY   (   R   R[   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRZ     s    N(	   RB   RC   RD   R&   RR   R   RT   R   RZ   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR   Ö   s   
				t   KeyringCredentialStorec           B   s/   e  Z d  Z e d „  ƒ Z d „  Z d „  Z RS(   sö   Store credentials in the GNOME keyring or KDE wallet.

    This is a good solution for desktop applications and interactive
    scripts. It doesn't work for non-interactive scripts, or for
    integrating third-party websites into Launchpad.
    c           C   s"   d t  ƒ  k r d d l a n  d S(   sG  Ensure the keyring module is imported (postponing side effects).

        The keyring module initializes the environment-dependent backend at
        import time (nasty).  We want to avoid that initialization because it
        may do things like prompt the user to unlock their password store
        (e.g., KWallet).
        t   keyringiÿÿÿÿN(   t   globalsR]   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyt   _ensure_keyring_imported)  s    	c         C   s'   |  j  ƒ  t j d | | j ƒ  ƒ d S(   s2   Store newly-authorized credentials in the keyring.t   launchpadlibN(   R_   R]   t   set_passwordR   (   R   R   R[   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRT   6  s    
c         C   s9   |  j  ƒ  t j d | ƒ } | d k	 r5 t j | ƒ Sd S(   s&   Retrieve credentials from the keyring.R`   N(   R_   R]   t   get_passwordR&   R   R   (   R   R[   t   credential_string(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRZ   <  s    
(   RB   RC   RD   t   staticmethodR_   RT   RZ   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR\   !  s   	t   UnencryptedFileCredentialStorec           B   s,   e  Z d  Z d d „ Z d „  Z d „  Z RS(   s‘   Store credentials unencrypted in a file on disk.

    This is a good solution for scripts that need to run without any
    user interaction.
    c         C   s#   t  t |  ƒ j | ƒ | |  _ d  S(   N(   RQ   Re   RR   t   filename(   R   Rf   RS   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRR   M  s    c         C   s   | j  |  j ƒ d S(   s   Save the credentials to disk.N(   t   save_to_pathRf   (   R   R   R[   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRT   R  s    c         C   sI   t  j j |  j ƒ rE t  j |  j ƒ t j d k rE t j |  j ƒ Sd S(   s   Load the credentials from disk.i    N(	   t   ost   patht   existsRf   t   statt   ST_SIZER   t   load_from_pathR&   (   R   R[   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRZ   V  s     N(   RB   RC   RD   R&   RR   RT   RZ   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRe   F  s   	c           B   sY   e  Z d  Z d Z d d d d „ Z e d „  ƒ Z d „  Z d „  Z	 d „  Z
 d „  Z RS(	   s/  The superclass of all request token authorizers.

    This base class does not implement request token authorization,
    since that varies depending on how you want the end-user to
    authorize a request token. You'll need to subclass this class and
    implement `make_end_user_authorize_token`.
    t   UNAUTHORIZEDc         C   s×   t  j | ƒ |  _ t  j | ƒ |  _ | d k rK | d k rK t d ƒ ‚ n  | d k	 r| | d k	 r| t d | | f ƒ ‚ n  | d k r  d g } t | ƒ } n t | ƒ } | } | |  _	 | |  _
 | pÍ g  |  _ d S(   sD  Base class initialization.

        :param service_root: The root of the Launchpad instance being
            used.

        :param application_name: The name of the application that
            wants to use launchpadlib. This is used in conjunction
            with a desktop-wide integration.

            If you specify this argument, your values for
            consumer_name and allow_access_levels are ignored.

        :param consumer_name: The OAuth consumer name, for an
            application that wants its own point of integration into
            Launchpad. In almost all cases, you want to specify
            application_name instead and do a desktop-wide
            integration. The exception is when you're integrating a
            third-party website into Launchpad.

        :param allow_access_levels: A list of the Launchpad access
            levels to present to the user. ('READ_PUBLIC' and so on.)
            Your value for this argument will be ignored during a
            desktop-wide integration.
        :type allow_access_levels: A list of strings.
        s:   You must provide either application_name or consumer_name.sZ   You must provide only one of application_name and consumer_name. (You provided %r and %r.)t   DESKTOP_INTEGRATIONN(   R   t   lookup_service_roott   service_roott   web_root_for_service_rootR7   R&   t
   ValueErrorR   R   R%   t   application_namet   allow_access_levels(   R   Rq   Rt   t   consumer_nameRu   R%   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRR   i  s"    			c         C   s   |  j  j d |  j S(   s7   Return a string identifying this consumer on this host.t   @(   R%   R*   Rq   (   R   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRW   ¢  s    c         C   sX   d t  | f } d } t |  j ƒ d k rH | | | j |  j ƒ 7} n  t |  j | ƒ S(   sÞ   Return the authorization URL for a request token.

        This is the URL the end-user must visit to authorize the
        token. How exactly does this happen? That depends on the
        subclass implementation.
        s   %s?oauth_token=%ss   &allow_permission=i    (   R5   RN   Ru   t   joinR	   R7   (   R   t   request_tokent   paget   allow_permission(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyt   authorization_url§  s    c         C   sI   |  j  | ƒ } |  j | | ƒ | j d k r2 d S| j | |  j ƒ | S(   sd  Authorize a token and associate it with the given credentials.

        If the credential store runs into a problem storing the
        credential locally, the `credential_save_failed` callback will
        be invoked. The callback will not be invoked if there's a
        problem authorizing the credentials.

        :param credentials: A `Credentials` object. If the end-user
            authorizes these credentials, this object will have its
            .access_token property set.

        :param credential_store: A `CredentialStore` object. If the
            end-user authorizes the credentials, they will be
            persisted locally using this object.

        :return: If the credentials are successfully authorized, the
            return value is the `Credentials` object originally passed
            in. Otherwise the return value is None.
        N(   R=   t   make_end_user_authorize_tokenR(   R&   R   RW   (   R   R   t   credential_storet   request_token_string(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyt   __call__¶  s    c         C   s&   | j  d |  j d t j ƒ } | d S(   s\   Get a new request token from the server.

        :param return: The request token.
        R7   R8   R>   (   R=   R7   R   R,   (   R   R   t   authorization_json(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR=   Ô  s    		c         C   s   t  ƒ  ‚ d S(   s5  Authorize the given request token using the given credentials.

        Your subclass must implement this method: it has no default
        implementation.

        Because an access token may expire or be revoked in the middle
        of a session, this method may be called at arbitrary points in
        a launchpadlib session, or even multiple times during a single
        session (with a different request token each time).

        In most cases, however, this method will be called at the
        beginning of a launchpadlib session, or not at all.
        N(   RY   (   R   R   Ry   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR}   Þ  s    N(   RB   RC   RD   t   UNAUTHORIZED_ACCESS_LEVELR&   RR   t   propertyRW   R|   R€   R=   R}   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR   ^  s   8			
c           B   s8   e  Z d  Z d Z d d d d „ Z d „  Z d „  Z RS(   sß   The simplest (and, right now, the only) request token authorizer.

    This authorizer simply opens up the end-user's web browser to a
    Launchpad URL and lets the end-user authorize the request token
    themselves.
    sÇ   The authorization page:
 (%s)
should be opening in your browser. Use your browser to authorize
this program to access Launchpad on your behalf. 

Waiting to hear from Launchpad about your decision...c         C   s#   t  t |  ƒ j | | d | ƒ d S(   so  Constructor.

        :param service_root: See `RequestTokenAuthorizationEngine`.
        :param application_name: See `RequestTokenAuthorizationEngine`.
        :param consumer_name: The value of this argument is
            ignored. If we have the capability to open the end-user's
            web browser, we must be running on the end-user's computer,
            so we should do a full desktop integration.
        :param credential_save_failed: See `RequestTokenAuthorizationEngine`.
        :param allow_access_levels: The value of this argument is
            ignored, for the same reason as consumer_name.
        N(   RQ   R   RR   R&   (   R   Rq   Rt   Rv   RS   Ru   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRR   ù  s    	c         C   s	   | GHd S(   s³   Display a message.

        By default, prints the message to standard output. The message
        does not require any user interaction--it's solely
        informative.
        N(    (   R   t   message(    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyt   output  s    c         C   sÅ   |  j  | ƒ } t j | ƒ |  j |  j | ƒ xŽ | j d k rÀ t j t	 ƒ y | j
 |  j ƒ PWq3 t k
 r¼ } | j j d k rš t | j ƒ ‚ q½ | j j d k r¯ q½ d GH| GHq3 Xq3 Wd S(   s7   Have the end-user authorize the token in their browser.i“  i‘  s#   Unexpected response from Launchpad:N(   R|   t
   webbrowsert   openR…   t   WAITING_FOR_USERR(   R&   t   timet   sleept   access_token_poll_timeRA   R7   R
   R;   R0   t   EndUserDeclinedAuthorizationR<   (   R   R   Ry   R|   RX   (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR}     s     
N(   RB   RC   RD   Rˆ   R&   RR   R…   R}   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR   ï  s   		t   TokenAuthorizationExceptionc           B   s   e  Z RS(    (   RB   RC   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR   1  s   t   RequestTokenAlreadyAuthorizedc           B   s   e  Z RS(    (   RB   RC   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRŽ   5  s   RŒ   c           B   s   e  Z RS(    (   RB   RC   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyRŒ   9  s   t   ClientErrorc           B   s   e  Z RS(    (   RB   RC   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR   =  s   t   ServerErrorc           B   s   e  Z RS(    (   RB   RC   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR   A  s   t   NoLaunchpadAccountc           B   s   e  Z RS(    (   RB   RC   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR‘   E  s   t   TooManyAuthenticationFailuresc           B   s   e  Z RS(    (   RB   RC   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyR’   I  s   (3   RD   t   typet   __metaclass__t   __all__RK   t	   cStringIOR   R-   Rh   Rk   R‰   t   urllibR   t   urlparseR	   R†   R1   t   lazr.restfulclient.errorsR
   t"   lazr.restfulclient.authorize.oauthR    t   _AccessTokenR   R   R   R`   R   R+   R@   R5   R‹   t   MemoryErrort   KeyboardInterruptt
   SystemExitRU   R   R   t   objectR   R\   Re   R   R   RV   R   RŽ   RŒ   R   R   R‘   R’   (    (    (    s<   /usr/lib/python2.7/dist-packages/launchpadlib/credentials.pyt   <module>   sR   	"s	K%‘B