o
    ¯b¤]  ã                   @   s¬   d Z ddlZddlmZ ddlmZ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 ddlmZ dd	lmZ dd
lmZ dd„ ZG dd„ de
ƒZG dd„ deƒZdS )z[
Tests for L{twisted.cred._digest} and the associated bits in
L{twisted.cred.credentials}.
é    N)Úhexlify)Úmd5Úsha1)ÚverifyObject)ÚDigestCredentialFactoryÚIUsernameDigestHashÚcalcHA1ÚcalcHA2ÚcalcResponse)ÚLoginFailed)ÚIPv4Address)ÚnetworkString)ÚTestCasec                 C   s   t  | ¡ ¡ S )N)Úbase64Ú	b64encodeÚstrip)Ús© r   úC/usr/lib/python3/dist-packages/twisted/cred/test/test_digestauth.pyr      s   r   c                       s0   e Zd ZdZ‡ fdd„Zdd„ Zdd„ Z‡  ZS )ÚFakeDigestCredentialFactoryz\
    A Fake Digest Credential Factory that generates a predictable
    nonce and opaque
    c                    s   t ƒ j|i |¤Ž d| _d S )Nó   0)ÚsuperÚ__init__Ú
privateKey)ÚselfÚargsÚkwargs©Ú	__class__r   r   r   '   s   
z$FakeDigestCredentialFactory.__init__c                 C   ó   dS )z)
        Generate a static nonce
        s   178288758716122392881254770685r   ©r   r   r   r   Ú_generateNonce+   ó   z*FakeDigestCredentialFactory._generateNoncec                 C   r   )z&
        Return a stable time
        r   r   r    r   r   r   Ú_getTime1   r"   z$FakeDigestCredentialFactory._getTime)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r!   r#   Ú__classcell__r   r   r   r   r   !   s
    r   c                   @   sZ  e Zd ZdZdd„ Zdefdd„Zdd„ Zd	d
„ Zdefdd„Z	defdd„Z
dd„ Zdd„ Zdd„ Zdd„ Zdefdd„Zdd„ Zdd„ Zdefdd„Zdd „ Zd!d"„ ZdOd$d%„Zd&d'„ ZdOd(d)„Zd*d+„ Zd,d-„ Zd.d/„ Zd0d1„ Zd2d3„ Zd4d5„ Zd6d7„ Zd8d9„ Zd:d;„ Z d<d=„ Z!d>d?„ Z"d@dA„ Z#dBdC„ Z$dDdE„ Z%dFdG„ Z&dHdI„ Z'dJdK„ Z(dLdM„ Z)dNS )PÚDigestAuthTestsz¸
    L{TestCase} mixin class which defines a number of tests for
    L{DigestCredentialFactory}.  Because this mixin defines C{setUp}, it
    must be inherited before L{TestCase}.
    c                 C   sR   d| _ d| _d| _d| _d| _d| _d| _tdd	d
ƒ| _d| _	t
| j| jƒ| _dS )z>
        Create a DigestCredentialFactory for testing
        ó   foobars   bazquuxs
   test realmó   md5s    29fc54aa1641c6fa0e151419361c8f23ó   auths   /write/ÚTCPz10.2.3.4iu¨  ó   GETN)ÚusernameÚpasswordÚrealmÚ	algorithmÚcnonceÚqopÚurir   ÚclientAddressÚmethodr   ÚcredentialFactoryr    r   r   r   ÚsetUp?   s   zDigestAuthTests.setUpr+   c                 C   sT   d}t || j| j| j|| jƒ}d | j| j| jf¡}t||ƒ ¡ ƒ}|  ||¡ dS )zŽ
        L{calcHA1} accepts the C{'md5'} algorithm and returns an MD5 hash of
        its parameters, excluding the nonce and cnonce.
        s	   abc123xyzó   :N)	r   r/   r1   r0   r3   Újoinr   ÚdigestÚassertEqual)r   Ú
_algorithmÚ_hashÚnonceÚhashA1Úa1Úexpectedr   r   r   Útest_MD5HashA1N   s   ÿzDigestAuthTests.test_MD5HashA1c                 C   s~   d}t d| j| j| j|| jƒ}| jd | j d | j }tt|ƒ ¡ ƒ}|d | d | j }tt|ƒ ¡ ƒ}|  ||¡ dS )z“
        L{calcHA1} accepts the C{'md5-sess'} algorithm and returns an MD5 hash
        of its parameters, including the nonce and cnonce.
        s	   xyz321abcó   md5-sessr:   N)	r   r/   r1   r0   r3   r   r   r<   r=   )r   r@   rA   rB   Úha1rC   r   r   r   Útest_MD5SessionHashA1[   s   ÿz%DigestAuthTests.test_MD5SessionHashA1c                 C   ó   |   dt¡ dS )z
        L{calcHA1} accepts the C{'sha'} algorithm and returns a SHA hash of its
        parameters, excluding the nonce and cnonce.
        ó   shaN)rD   r   r    r   r   r   Útest_SHAHashA1j   ó   zDigestAuthTests.test_SHAHashA1c                 C   sD   d}t ||| jddƒ}|d | j }t||ƒ ¡ ƒ}|  ||¡ dS )z±
        L{calcHA2} accepts the C{'md5'} algorithm and returns an MD5 hash of
        its arguments, excluding the entity hash for QOP other than
        C{'auth-int'}.
        r.   r,   Nr:   ©r	   r5   r   r<   r=   )r   r>   r?   r7   ÚhashA2Úa2rC   r   r   r   Útest_MD5HashA2Authq   s
   z"DigestAuthTests.test_MD5HashA2Authc                 C   sP   d}d}t ||| jd|ƒ}|d | j d | }t||ƒ ¡ ƒ}|  ||¡ dS )z¡
        L{calcHA2} accepts the C{'md5'} algorithm and returns an MD5 hash of
        its arguments, including the entity hash for QOP of C{'auth-int'}.
        r.   s	   foobarbazs   auth-intr:   NrL   )r   r>   r?   r7   ÚhentityrM   rN   rC   r   r   r   Útest_MD5HashA2AuthInt}   s   z%DigestAuthTests.test_MD5HashA2AuthIntc                 C   ó   |   d¡ dS )zŸ
        L{calcHA2} accepts the C{'md5-sess'} algorithm and QOP of C{'auth'} and
        returns the same value as it does for the C{'md5'} algorithm.
        rE   N)rO   r    r   r   r   Útest_MD5SessHashA2Auth‰   ó   z&DigestAuthTests.test_MD5SessHashA2Authc                 C   rR   )z£
        L{calcHA2} accepts the C{'md5-sess'} algorithm and QOP of C{'auth-int'}
        and returns the same value as it does for the C{'md5'} algorithm.
        rE   N)rQ   r    r   r   r   Útest_MD5SessHashA2AuthInt   rT   z)DigestAuthTests.test_MD5SessHashA2AuthIntc                 C   rH   )z°
        L{calcHA2} accepts the C{'sha'} algorithm and returns a SHA hash of
        its arguments, excluding the entity hash for QOP other than
        C{'auth-int'}.
        rI   N)rO   r   r    r   r   r   Útest_SHAHashA2Auth—   ó   z"DigestAuthTests.test_SHAHashA2Authc                 C   rH   )z 
        L{calcHA2} accepts the C{'sha'} algorithm and returns a SHA hash of
        its arguments, including the entity hash for QOP of C{'auth-int'}.
        rI   N)rQ   r   r    r   r   r   Útest_SHAHashA2AuthIntŸ   rK   z%DigestAuthTests.test_SHAHashA2AuthIntc           	      C   sT   d}d}d}|d | d | }t ||ƒ ¡ ƒ}t||||dddƒ}|  ||¡ dS )zâ
        L{calcResponse} accepts the C{'md5'} algorithm and returns an MD5 hash
        of its parameters, excluding the nonce count, client nonce, and QoP
        value if the nonce count and client nonce are L{None}
        ó   abc123ó   789xyzó   lmnopqr:   N©r   r<   r
   r=   )	r   r>   r?   rA   rM   r@   ÚresponserC   r<   r   r   r   Útest_MD5HashResponse¦   s   z$DigestAuthTests.test_MD5HashResponsec                 C   rR   )zç
        L{calcResponse} accepts the C{'md5-sess'} algorithm and returns an MD5
        hash of its parameters, excluding the nonce count, client nonce, and
        QoP value if the nonce count and client nonce are L{None}
        rE   N)r^   r    r   r   r   Útest_MD5SessionHashResponse¶   ó   z+DigestAuthTests.test_MD5SessionHashResponsec                 C   rH   )zá
        L{calcResponse} accepts the C{'sha'} algorithm and returns a SHA hash
        of its parameters, excluding the nonce count, client nonce, and QoP
        value if the nonce count and client nonce are L{None}
        rI   N)r^   r   r    r   r   r   Útest_SHAHashResponse¾   rW   z$DigestAuthTests.test_SHAHashResponsec                 C   sx   d}d}d}d}d}d}|d | d | d | d | d | }	t ||	ƒ ¡ ƒ}
t|||||||ƒ}|  |
|¡ dS )	zÉ
        L{calcResponse} accepts the C{'md5'} algorithm and returns an MD5 hash
        of its parameters, including the nonce count, client nonce, and QoP
        value if they are specified.
        rY   rZ   r[   s   00000004s	   abcxyz123r,   r:   Nr\   )r   r>   r?   rA   rM   r@   Ú
nonceCountÚclientNoncer4   r]   rC   r<   r   r   r   Útest_MD5HashResponseExtraÆ   sB   ÿþýüûúùø	÷
öÿÿz)DigestAuthTests.test_MD5HashResponseExtrac                 C   rR   )zÎ
        L{calcResponse} accepts the C{'md5-sess'} algorithm and returns an MD5
        hash of its parameters, including the nonce count, client nonce, and
        QoP value if they are specified.
        rE   N)rd   r    r   r   r   Ú test_MD5SessionHashResponseExtraç   r`   z0DigestAuthTests.test_MD5SessionHashResponseExtrac                 C   rH   )zÈ
        L{calcResponse} accepts the C{'sha'} algorithm and returns a SHA hash
        of its parameters, including the nonce count, client nonce, and QoP
        value if they are specified.
        rI   N)rd   r   r    r   r   r   Útest_SHAHashResponseExtraï   rW   z)DigestAuthTests.test_SHAHashResponseExtraTc                    s–   d|vr	| j |d< d|vr| j|d< d|vr| j|d< d|vr$| j|d< d|vr-| j|d< d|vr6| j|d< |r;d‰ nd‰ d	 ‡ fd
d„| ¡ D ƒ¡S )aþ  
        Format all given keyword arguments and their values suitably for use as
        the value of an HTTP header.

        @types quotes: C{bool}
        @param quotes: A flag indicating whether to quote the values of each
            field in the response.

        @param **kw: Keywords and C{bytes} values which will be treated as field
            name/value pairs to include in the result.

        @rtype: C{bytes}
        @return: The given fields formatted for use as an HTTP header value.
        r/   r1   r2   r4   r3   r5   ó   "ó    s   , c              	      s0   g | ]\}}|d urd  t|ƒdˆ |ˆ f¡‘qS )Nrh   ó   =)r;   r   )Ú.0ÚkÚv©Úquoter   r   Ú
<listcomp>  s
    þz2DigestAuthTests.formatResponse.<locals>.<listcomp>)r/   r1   r2   r4   r3   r5   r;   Úitems)r   ÚquotesÚkwr   rm   r   ÚformatResponse÷   s(   






þÿzDigestAuthTests.formatResponsec           	      C   sh   |  d¡}|  d¡ ¡ }|  d¡}t|| j| j| j|| jƒ}t|d| j|dƒ}t	|||||| j|ƒ}|S )z@
        Calculate the response for the given challenge
        r@   r2   r4   r.   N)
ÚgetÚlowerr   r/   r1   r0   r3   r	   r5   r
   )	r   Ú	challengeÚncountr@   Úalgor4   rF   Úha2rC   r   r   r   ÚgetDigestResponse  s   

ÿz!DigestAuthTests.getDigestResponsec                 C   sz   | j  | jj¡}d}| j||d |  ||¡||d d}| j  || j| jj¡}|  | 	| j
¡¡ |  | 	| j
d ¡¡ dS )zš
        L{DigestCredentialFactory.decode} accepts a digest challenge response
        and parses it into an L{IUsernameHashedPassword} provider.
        ó   00000001r@   Úopaque)rq   r@   r]   Úncr|   ó   wrongN©r8   ÚgetChallenger6   Úhostrs   rz   Údecoder7   Ú
assertTrueÚcheckPasswordr0   ÚassertFalse)r   rq   rv   r}   ÚclientResponseÚcredsr   r   r   Útest_response.  s   
ûÿzDigestAuthTests.test_responsec                 C   rR   )a  
        L{DigestCredentialFactory.decode} accepts a digest challenge response
        which does not quote the values of its fields and parses it into an
        L{IUsernameHashedPassword} provider in the same way it would a
        response which included quoted field values.
        FN)rˆ   r    r   r   r   Útest_responseWithoutQuotesC  s   z*DigestAuthTests.test_responseWithoutQuotesc                 C   s   d| _ |  d¡ dS )z¶
        L{DigestCredentialFactory.decode} accepts a digest challenge response
        which quotes the values of its fields and includes a C{b","} in the URI
        field.
        s   /some,path/TN)r5   rˆ   r    r   r   r   Útest_responseWithCommaURIL  s   z)DigestAuthTests.test_responseWithCommaURIc                 C   s   d| _ |  ¡  dS )zs
        The case of the algorithm value in the response is ignored when
        checking the credentials.
        s   MD5N©r2   rˆ   r    r   r   r   Útest_caseInsensitiveAlgorithmU  s   z-DigestAuthTests.test_caseInsensitiveAlgorithmc                 C   s   d| _ |  ¡  dS )zV
        The algorithm defaults to MD5 if it is not supplied in the response.
        Nr‹   r    r   r   r   Útest_md5DefaultAlgorithm]  s   z(DigestAuthTests.test_md5DefaultAlgorithmc                 C   sp   | j  d¡}d}| j|d |  ||¡||d d}| j  || jd¡}|  | | j¡¡ |  	| | jd ¡¡ dS )z“
        L{DigestCredentialFactory.decode} accepts a digest challenge response
        even if the client address it is passed is L{None}.
        Nr{   r@   r|   ©r@   r]   r}   r|   r~   )
r8   r€   rs   rz   r‚   r7   rƒ   r„   r0   r…   ©r   rv   r}   r†   r‡   r   r   r   Útest_responseWithoutClientIPd  s   
üz,DigestAuthTests.test_responseWithoutClientIPc                 C   sÜ   | j  | jj¡}d}| j|d |  ||¡||d d}| j  || j| jj¡}|  | 	| j
¡¡ |  | 	| j
d ¡¡ d}| j|d |  ||¡||d d}| j  || j| jj¡}|  | 	| j
¡¡ |  | 	| j
d ¡¡ dS )zm
        L{DigestCredentialFactory.decode} handles multiple responses to a
        single challenge.
        r{   r@   r|   rŽ   r~   s   00000002Nr   r   r   r   r   Útest_multiResponsev  s2   
üÿ
üÿz"DigestAuthTests.test_multiResponsec                 C   sv   | j  | jj¡}d}| j|d |  ||¡||d d}| j  |d| jj¡}|  | | j	¡¡ |  | | j	d ¡¡ dS )a&  
        L{DigestCredentialFactory.decode} returns an L{IUsernameHashedPassword}
        provider which rejects a correct password for the given user if the
        challenge response request is made using a different HTTP method than
        was used to request the initial challenge.
        r{   r@   r|   rŽ   s   POSTr~   N)
r8   r€   r6   r   rs   rz   r‚   r…   r„   r0   r   r   r   r   Útest_failsWithDifferentMethod™  s   
ü
ÿz-DigestAuthTests.test_failsWithDifferentMethodc                 C   sl   |   t| jj| jdd| j| jj¡}|  t	|ƒd¡ |   t| jj| jdd| j| jj¡}|  t	|ƒd¡ dS )zš
        L{DigestCredentialFactory.decode} raises L{LoginFailed} if the response
        has no username field or if the username field is empty.
        N)r/   z$Invalid response, no username given.rh   ©
ÚassertRaisesr   r8   r‚   rs   r7   r6   r   r=   Ústr©r   Úer   r   r   Útest_noUsername¯  s    
û
ûzDigestAuthTests.test_noUsernamec                 C   s8   |   t| jj| jdd| j| jj¡}|  t	|ƒd¡ dS )zo
        L{DigestCredentialFactory.decode} raises L{LoginFailed} if the response
        has no nonce.
        rY   )r|   z!Invalid response, no nonce given.Nr“   r–   r   r   r   Útest_noNonceÈ  s   
ûzDigestAuthTests.test_noNoncec                 C   s4   |   t| jj|  ¡ | j| jj¡}|  t	|ƒd¡ dS )zp
        L{DigestCredentialFactory.decode} raises L{LoginFailed} if the response
        has no opaque.
        z"Invalid response, no opaque given.Nr“   r–   r   r   r   Útest_noOpaqueÖ  s   ûzDigestAuthTests.test_noOpaquec                 C   s¼   | j  | jj¡}d}| j|d |  ||¡||d d}| j  || j| jj¡}|  t	t
|ƒ¡ | jd | j d | j }t|ƒ}|  | t| ¡ ƒ¡¡ | d¡ |  | t| ¡ ƒ¡¡ dS )z¥
        L{DigestCredentialFactory.decode} returns an L{IUsernameDigestHash}
        provider which can verify a hash of the form 'username:realm:password'.
        r{   r@   r|   rŽ   r:   r~   N)r8   r€   r6   r   rs   rz   r‚   r7   rƒ   r   r   r/   r1   r0   r   Ú	checkHashr   r<   Úupdater…   )r   rv   r}   r†   r‡   Ú	cleartextÚhashr   r   r   Útest_checkHashä  s"   
üÿ
zDigestAuthTests.test_checkHashc                 C   s   t | j| jƒ}| | jj¡}|  t|jd|d | jj¡}|  	t
|ƒd¡ dtdƒ }|  t|j||d | jj¡}|  	t
|ƒd¡ |  t|jd|d | jj¡}|  	t
|ƒd¡ dtd |d t| jjƒdf¡ƒ }|  t|j||d | jj¡}|  	t
|ƒd	¡ d
S )z
        L{DigestCredentialFactory.decode} raises L{LoginFailed} when the opaque
        value does not contain all the required parts.
        s	   badOpaquer@   z&Invalid response, invalid opaque values   foo-s   nonce,clientiprh   ó   ,r*   z,Invalid response, invalid opaque/time valuesN)r   r2   r1   r€   r6   r   r”   r   Ú_verifyOpaquer=   r•   r   r;   r   )r   r8   rv   ÚexcÚ	badOpaquer   r   r   Útest_invalidOpaqueþ  sP   ûûûÿÿûz"DigestAuthTests.test_invalidOpaquec                 C   s„   t | j| jƒ}| | jj¡}| d| jj¡}|  t|j	||d | jj¡}|  
t|ƒd¡ |  t|j	|d| jj¡}|  
t|ƒd¡ dS )z¨
        L{DigestCredentialFactory.decode} raises L{LoginFailed} when the given
        nonce from the response does not match the nonce encoded in the opaque.
        s
   1234567890r@   z2Invalid response, incompatible opaque/nonce valuesrh   N)r   r2   r1   r€   r6   r   Ú_generateOpaquer”   r   r¡   r=   r•   )r   r8   rv   ÚbadNonceOpaquer¢   r   r   r   Útest_incompatibleNonce1  s*   ÿûûz&DigestAuthTests.test_incompatibleNoncec                 C   s`   t | j| jƒ}| | jj¡}d}|  | jj|¡ | |d |¡}|  t	|j
||d | jj¡ dS )z«
        L{DigestCredentialFactory.decode} raises L{LoginFailed} when the
        request comes from a client IP other than what is encoded in the
        opaque.
        z10.0.0.1r@   N)r   r2   r1   r€   r6   r   ÚassertNotEqualr¥   r”   r   r¡   )r   r8   rv   Ú
badAddressr¦   r   r   r   Útest_incompatibleClientIPO  s   ÿûz)DigestAuthTests.test_incompatibleClientIPc                 C   sŠ   t | j| jƒ}| | jj¡}d |d t| jjƒdf¡}tt	||j
 ƒ ¡ ƒ}t|ƒ}d || d¡f¡}|  t|j||d | jj¡ dS )z¨
        L{DigestCredentialFactory.decode} raises L{LoginFailed} when the given
        opaque is older than C{DigestCredentialFactory.CHALLENGE_LIFETIME_SECS}
        r    r@   s
   -137876876ó   -ó   
N)r   r2   r1   r€   r6   r   r;   r   r   r   r   r<   r   r   r”   r   r¡   )r   r8   rv   Úkeyr<   ÚekeyÚoldNonceOpaquer   r   r   Útest_oldNonceh  s   ÿûzDigestAuthTests.test_oldNoncec                 C   s~   t | j| jƒ}| | jj¡}d |d t| jjƒdf¡}tt	|d ƒ 
¡ ƒ}d |t|ƒf¡}|  t|j||d | jj¡ dS )z~
        L{DigestCredentialFactory.decode} raises L{LoginFailed} when the opaque
        checksum fails verification.
        r    r@   r   s   this is not the right pkeyr«   N)r   r2   r1   r€   r6   r   r;   r   r   r   r<   r   r”   r   r¡   )r   r8   rv   r­   r<   ÚbadChecksumr   r   r   Útest_mismatchedOpaqueChecksum€  s   ÿûz-DigestAuthTests.test_mismatchedOpaqueChecksumc                 C   s6   d}|D ]\}}}}| j ttd|||dd|d	 qdS )z°
        L{calcHA1} raises L{TypeError} when any of the pszUsername, pszRealm,
        or pszPassword arguments are specified with the preHA1 keyword
        argument.
        ))s   useró   realmó   passwordó   preHA1)Nr³   Nrµ   )NNr´   rµ   r+   s   nonces   cnonce)ÚpreHA1N)r”   Ú	TypeErrorr   )r   Ú	argumentsÚpszUsernameÚpszRealmÚpszPasswordr¶   r   r   r   Útest_incompatibleCalcHA1Options—  s   ÷ÿz/DigestAuthTests.test_incompatibleCalcHA1Optionsc                 C   s   | j  dd¡}|  d|¡ dS )z
        L{DigestCredentialFactory._generateOpaque} returns a value without
        newlines, regardless of the length of the nonce.
        sn   long nonce long nonce long nonce long nonce long nonce long nonce long nonce long nonce long nonce long nonce Nr¬   )r8   r¥   ÚassertNotIn)r   r|   r   r   r   Útest_noNewlineOpaque°  s   z$DigestAuthTests.test_noNewlineOpaqueN)T)*r$   r%   r&   r'   r9   r   rD   rG   rJ   rO   rQ   rS   rU   rV   rX   r^   r_   ra   rd   re   rf   rs   rz   rˆ   r‰   rŠ   rŒ   r   r   r‘   r’   r˜   r™   rš   rŸ   r¤   r§   rª   r°   r²   r¼   r¾   r   r   r   r   r)   8   sN    !
(
		#3r)   )r'   r   Úbinasciir   Úhashlibr   r   Úzope.interface.verifyr   Útwisted.cred.credentialsr   r   r   r	   r
   Útwisted.cred.errorr   Útwisted.internet.addressr   Útwisted.python.compatr   Útwisted.trial.unittestr   r   r   r)   r   r   r   r   Ú<module>   s   