U
    
W[!_                     @   s   d Z ddlmZm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 ddlmZ dd	lmZ dd
lmZmZmZ ddlmZ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}.
    )divisionabsolute_importN)hexlify)md5sha1)verifyObject)TestCase)IPv4Address)LoginFailed)calcHA1calcHA2IUsernameDigestHash)calcResponseDigestCredentialFactory)networkStringc                 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 t| j|| d| _d S )N   0)superr   __init__
privateKey)selfargskwargs	__class__r   r   r   "   s    z$FakeDigestCredentialFactory.__init__c                 C   s   dS )z)
        Generate a static nonce
        s   178288758716122392881254770685r   r   r   r   r   _generateNonce'   s    z*FakeDigestCredentialFactory._generateNoncec                 C   s   dS )z&
        Return a stable time
        r   r   r!   r   r   r   _getTime.   s    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dPd(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 )Q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/Z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.   r0   r/   r2   joinr   digestassertEqual)r   
_algorithm_hashnoncehashA1a1expectedr   r   r   test_MD5HashA1M   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-sessr9   N)	r   r.   r0   r/   r2   r   r   r;   r<   )r   r?   r@   rA   ha1rB   r   r   r   test_MD5SessionHashA1Z   s     z%DigestAuthTests.test_MD5SessionHashA1c                 C   s   |  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)rC   r   r!   r   r   r   test_SHAHashA1i   s    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,   Nr9   r   r4   r   r;   r<   )r   r=   r>   r6   hashA2a2rB   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-intr9   NrI   )r   r=   r>   r6   ZhentityrJ   rK   rB   r   r   r   test_MD5HashA2AuthInt~   s    z%DigestAuthTests.test_MD5HashA2AuthIntc                 C   s   |  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.
        rD   N)rL   r!   r   r   r   test_MD5SessHashA2Auth   s    z&DigestAuthTests.test_MD5SessHashA2Authc                 C   s   |  d dS )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.
        rD   N)rM   r!   r   r   r   test_MD5SessHashA2AuthInt   s    z)DigestAuthTests.test_MD5SessHashA2AuthIntc                 C   s   |  dt dS )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'}.
        rG   N)rL   r   r!   r   r   r   test_SHAHashA2Auth   s    z"DigestAuthTests.test_SHAHashA2Authc                 C   s   |  dt dS )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'}.
        rG   N)rM   r   r!   r   r   r   test_SHAHashA2AuthInt   s    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   lmnopqr9   Nr   r;   r   r<   )	r   r=   r>   r@   rJ   r?   responserB   r;   r   r   r   test_MD5HashResponse   s    z$DigestAuthTests.test_MD5HashResponsec                 C   s   |  d dS )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}
        rD   N)rW   r!   r   r   r   test_MD5SessionHashResponse   s    z+DigestAuthTests.test_MD5SessionHashResponsec                 C   s   |  dt dS )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}
        rG   N)rW   r   r!   r   r   r   test_SHAHashResponse   s    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.
        rR   rS   rT   s   00000004s	   abcxyz123r,   r9   NrU   )r   r=   r>   r@   rJ   r?   Z
nonceCountZclientNoncer3   rV   rB   r;   r   r   r   test_MD5HashResponseExtra   s8          z)DigestAuthTests.test_MD5HashResponseExtrac                 C   s   |  d dS )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.
        rD   N)rZ   r!   r   r   r    test_MD5SessionHashResponseExtra   s    z0DigestAuthTests.test_MD5SessionHashResponseExtrac                 C   s   |  dt dS )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.
        rG   N)rZ   r   r!   r   r   r   test_SHAHashResponseExtra   s    z)DigestAuthTests.test_SHAHashResponseExtraTc                    s   d|kr| j |d< d|kr$| j|d< d|kr6| j|d< d|krH| j|d< d|krZ| j|d< d|krl| j|d< |rvd 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.   r0   r1   r3   r2   r4      "    s   , c              	      s0   g | ](\}}|d k	rd t|d | fqS )Nr^      =)r:   r   ).0kvZquoter   r   
<listcomp>  s   z2DigestAuthTests.formatResponse.<locals>.<listcomp>)r.   r0   r1   r3   r2   r4   r:   items)r   quoteskwr   rc   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?   r1   r3   r-   N)
getlowerr   r.   r0   r/   r2   r   r4   r   )	r   	challengeZncountr?   Zalgor3   rE   Zha2rB   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)rf   r?   rV   ncrn      wrongNr7   getChallenger5   hostrh   rl   decoder6   
assertTruecheckPasswordr/   assertFalse)r   rf   rk   ro   clientResponsecredsr   r   r   test_response/  s$    
  zDigestAuthTests.test_responsec                 C   s   |  d dS )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)rz   r!   r   r   r   test_responseWithoutQuotesD  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)r4   rz   r!   r   r   r   test_responseWithCommaURIN  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r1   rz   r!   r   r   r   test_caseInsensitiveAlgorithmX  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_md5DefaultAlgorithma  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}.
        Nrm   r?   rn   r?   rV   ro   rn   rp   )
r7   rr   rh   rl   rt   r6   ru   rv   r/   rw   r   rk   ro   rx   ry   r   r   r   test_responseWithoutClientIPi  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.
        rm   r?   rn   r   rp   s   00000002Nrq   r   r   r   r   test_multiResponse|  s6    

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.
        rm   r?   rn   r   s   POSTrp   N)
r7   rr   r5   rs   rh   rl   rt   rw   rv   r/   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.r^   
assertRaisesr
   r7   rt   rh   r6   r5   rs   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.
        rR   )rn   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'.
        rm   r?   rn   r   r9   rp   N)r7   rr   r5   rs   rh   rl   rt   r6   ru   r   r   r.   r0   r/   r   Z	checkHashr   r;   updaterw   )r   rk   ro   rx   ry   Z	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,clientipr^      ,r*   z,Invalid response, invalid opaque/time valuesN)r   r1   r0   rr   r5   rs   r   r
   _verifyOpaquer<   r   r   r:   r   )r   r7   rk   excZ	badOpaquer   r   r   test_invalidOpaque  s\    

 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 valuesr^   N)r   r1   r0   rr   r5   rs   _generateOpaquer   r
   r   r<   r   )r   r7   rk   badNonceOpaquer   r   r   r   test_incompatibleNonce.  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   r1   r0   rr   r5   rs   ZassertNotEqualr   r   r
   r   )r   r7   rk   Z
badAddressr   r   r   r   test_incompatibleClientIPP  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   r1   r0   rr   r5   rs   r:   r   r   r   r   r;   r   r   r   r
   r   )r   r7   rk   keyr;   ZekeyZoldNonceOpaquer   r   r   test_oldNoncei  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   r1   r0   rr   r5   rs   r:   r   r   r   r;   r   r   r
   r   )r   r7   rk   r   r;   Z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   Z	argumentsZpszUsernameZpszRealmZ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   )r7   r   ZassertNotIn)r   rn   r   r   r   test_noNewlineOpaque  s
     z$DigestAuthTests.test_noNewlineOpaqueN)T)T)*r$   r%   r&   r'   r8   r   rC   rF   rH   rL   rM   rN   rO   rP   rQ   rW   rX   rY   rZ   r[   r\   rh   rl   rz   r{   r|   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r)   6   sL   					
'


	!1"r)   )r'   Z
__future__r   r   r   Zbinasciir   Zhashlibr   r   Zzope.interface.verifyr   Ztwisted.trial.unittestr   Ztwisted.internet.addressr	   Ztwisted.cred.errorr
   Ztwisted.cred.credentialsr   r   r   r   r   Ztwisted.python.compatr   r   r   r)   r   r   r   r   <module>   s   