
    Vh]                         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 Z G d de
      Z G d de      Zy)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                 H    t        j                  |       j                         S )N)base64	b64encodestrip)ss    Q/home/dcms/DCMS/lib/python3.12/site-packages/twisted/cred/test/test_digestauth.pyr   r      s    A$$&&    c                   .     e Zd ZdZ fdZd Zd Z xZS )FakeDigestCredentialFactoryz\
    A Fake Digest Credential Factory that generates a predictable
    nonce and opaque
    c                 2    t        |   |i | d| _        y )N   0)super__init__
privateKey)selfargskwargs	__class__s      r   r   z$FakeDigestCredentialFactory.__init__'   s    $)&)r   c                      y)z)
        Generate a static nonce
        s   178288758716122392881254770685 r   s    r   _generateNoncez*FakeDigestCredentialFactory._generateNonce+   s     1r   c                      y)z&
        Return a stable time
        r   r#   r$   s    r   _getTimez$FakeDigestCredentialFactory._getTime1   s     r   )__name__
__module____qualname____doc__r   r%   r'   __classcell__)r!   s   @r   r   r   !   s    
1r   r   c                      e Zd ZdZd ZdefdZd Zd ZdefdZ	defdZ
d	 Zd
 Zd Zd ZdefdZd Zd ZdefdZd Zd Zd)dZd Zd)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)y()*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                     d| _         d| _        d| _        d| _        d| _        d| _        d| _        t        dd	d
      | _        d| _	        t        | j                  | j                        | _        y)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$   s    r   setUpzDigestAuthTests.setUp?   sd     """
9(
EB!8!Tr   r1   c                 >   d}t        || j                  | j                  | j                  || j                        }dj                  | j                  | j                  | j                  f      }t         ||      j                               }| j                  ||       y)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	   r5   r7   r6   r9   joinr   digestassertEqual)r   
_algorithm_hashnoncehashA1a1expecteds          r   test_MD5HashA1zDigestAuthTests.test_MD5HashA1N   sz    
 tzz4==%
 YYtzz4==AB59++-.*r   c                    d}t        d| j                  | j                  | j                  || j                        }| j                  dz   | j                  z   dz   | j                  z   }t        t        |      j                               }|dz   |z   dz   | j                  z   }t        t        |      j                               }| j                  ||       y)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-sessrA   N)	r	   r5   r7   r6   r9   r   r   rC   rD   )r   rG   rH   rI   ha1rJ   s         r   test_MD5SessionHashA1z%DigestAuthTests.test_MD5SessionHashA1[   s    
 

DMM5$++
 ]]T!DJJ.5Ec"gnn&'4Z%$&43r7>>+,*r   c                 0    | j                  dt               y)z
        L{calcHA1} accepts the C{'sha'} algorithm and returns a SHA hash of its
        parameters, excluding the nonce and cnonce.
           shaN)rK   r   r$   s    r   test_SHAHashA1zDigestAuthTests.test_SHAHashA1j   s    
 	FD)r   c                     d}t        ||| j                  dd      }|dz   | j                  z   }t         ||      j                               }| j	                  ||       y)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'}.
        r4   r2   NrA   r
   r;   r   rC   rD   )r   rE   rF   r=   hashA2a2rJ   s          r   test_MD5HashA2Authz"DigestAuthTests.test_MD5HashA2Authq   sX     VTXXwEd]TXX%59++-.*r   c                     d}d}t        ||| j                  d|      }|dz   | j                  z   dz   |z   }t         ||      j                               }| j	                  ||       y)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'}.
        r4   s	   foobarbazs   auth-intrA   NrT   )r   rE   rF   r=   hentityrU   rV   rJ   s           r   test_MD5HashA2AuthIntz%DigestAuthTests.test_MD5HashA2AuthInt}   sg    
 VTXX{GLd]TXX%,w659++-.*r   c                 &    | j                  d       y)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.
        rM   N)rW   r$   s    r   test_MD5SessHashA2Authz&DigestAuthTests.test_MD5SessHashA2Auth   s    
 	,r   c                 &    | j                  d       y)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.
        rM   N)rZ   r$   s    r   test_MD5SessHashA2AuthIntz)DigestAuthTests.test_MD5SessHashA2AuthInt   s    
 	"";/r   c                 0    | j                  dt               y)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'}.
        rQ   N)rW   r   r$   s    r   test_SHAHashA2Authz"DigestAuthTests.test_SHAHashA2Auth   s     	-r   c                 0    | j                  dt               y)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'}.
        rQ   N)rZ   r   r$   s    r   test_SHAHashA2AuthIntz%DigestAuthTests.test_SHAHashA2AuthInt   s    
 	""640r   c           	          d}d}d}|dz   |z   dz   |z   }t         ||      j                               }t        ||||ddd      }| j                  ||       y)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   lmnopqrA   Nr   rC   r   rD   )	r   rE   rF   rH   rU   rG   responserJ   rC   s	            r   test_MD5HashResponsez$DigestAuthTests.test_MD5HashResponse   sh     D=5(4/&85?1134ffj%tTR6*r   c                 &    | j                  d       y)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}
        rM   N)ri   r$   s    r   test_MD5SessionHashResponsez+DigestAuthTests.test_MD5SessionHashResponse   s     	!!+.r   c                 0    | j                  dt               y)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}
        rQ   N)ri   r   r$   s    r   test_SHAHashResponsez$DigestAuthTests.test_SHAHashResponse   s     	!!&$/r   c           	          d}d}d}d}d}d}|dz   |z   dz   |z   dz   |z   dz   |z   dz   |z   }	t         ||	      j                               }
t        |||||||      }| j                  |
|       y)	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.
        rd   re   rf   s   00000004s	   abcxyz123r2   rA   Nrg   )r   rE   rF   rH   rU   rG   
nonceCountclientNoncer:   rh   rJ   rC   s               r   test_MD5HashResponseExtraz)DigestAuthTests.test_MD5HashResponseExtra   s      
"   	
     	 
 	 5?1134FJz;
 	6*r   c                 &    | j                  d       y)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.
        rM   N)rq   r$   s    r    test_MD5SessionHashResponseExtraz0DigestAuthTests.test_MD5SessionHashResponseExtra   s     	&&{3r   c                 0    | j                  dt               y)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.
        rQ   N)rq   r   r$   s    r   test_SHAHashResponseExtraz)DigestAuthTests.test_SHAHashResponseExtra   s     	&&vt4r   c                    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r| j
                  |d<   |rd}nd}d	j                  |j                         D cg c]&  \  }}|dj                  t        |      d
|||f      ( c}}      S c c}}w )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.
        r5   r7   r8   r:   r9   r;      "r   s   ,    =)	r5   r7   r8   r:   r9   r;   rB   itemsr   )r   quoteskwquotekvs         r   formatResponsezDigestAuthTests.formatResponse   s     R!]]BzN"**BwKb "nnB{O?BuI2;;BxL?BuIEEzz !hhjQ= -*D%EBC
 	
s   +C
c           	      `   |j                  d      }|j                  d      j                         }|j                  d      }t        || j                  | j                  | j
                  || j                        }t        |d| j                  |d      }t        |||||| j                  |      }|S )z@
        Calculate the response for the given challenge
        rG   r8   r:   r4   N)
getlowerr	   r5   r7   r6   r9   r
   r;   r   )	r   	challengencountrG   algor:   rN   ha2rJ   s	            r   getDigestResponsez!DigestAuthTests.getDigestResponse  s     g&}}[)//1mmE"$--T]]E4;;
 dFDHHc48S$vt{{CPr   c                    | j                   j                  | j                  j                        }d}| j	                  ||d   | j                  ||      ||d         }| j                   j                  || j                  | j                  j                        }| j                  |j                  | j                               | j                  |j                  | j                  dz                y)z
        L{DigestCredentialFactory.decode} accepts a digest challenge response
        and parses it into an L{IUsernameHashedPassword} provider.
           00000001rG   opaque)rz   rG   rh   ncr      wrongNr>   getChallenger<   hostr   r   decoder=   
assertTruecheckPasswordr6   assertFalse)r   rz   r   r   clientResponsecredss         r   test_responsezDigestAuthTests.test_response.  s    
 **778J8J8O8OP	,,G$++Ir:X& - 
 &&--DKK););)@)@
 	++DMM:;,,T]]X-EFGr   c                 &    | j                  d       y)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$   s    r   test_responseWithoutQuotesz*DigestAuthTests.test_responseWithoutQuotesC  s     	5!r   c                 4    d| _         | j                  d       y)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)r;   r   r$   s    r   test_responseWithCommaURIz)DigestAuthTests.test_responseWithCommaURIL  s     "4 r   c                 2    d| _         | j                          y)zs
        The case of the algorithm value in the response is ignored when
        checking the credentials.
        s   MD5Nr8   r   r$   s    r   test_caseInsensitiveAlgorithmz-DigestAuthTests.test_caseInsensitiveAlgorithmU  s    
  r   c                 2    d| _         | j                          y)zV
        The algorithm defaults to MD5 if it is not supplied in the response.
        Nr   r$   s    r   test_md5DefaultAlgorithmz(DigestAuthTests.test_md5DefaultAlgorithm]  s     r   c                    | j                   j                  d      }d}| j                  |d   | j                  ||      ||d         }| j                   j	                  || j
                  d      }| j                  |j                  | j                               | j                  |j                  | j                  dz                y)z
        L{DigestCredentialFactory.decode} accepts a digest challenge response
        even if the client address it is passed is L{None}.
        Nr   rG   r   rG   rh   r   r   r   )
r>   r   r   r   r   r=   r   r   r6   r   r   r   r   r   r   s        r   test_responseWithoutClientIPz,DigestAuthTests.test_responseWithoutClientIPd  s    
 **77=	,,G$++Ir:X&	 - 
 &&--ndkk4P++DMM:;,,T]]X-EFGr   c                 ^   | j                   j                  | j                  j                        }d}| j	                  |d   | j                  ||      ||d         }| j                   j                  || j                  | j                  j                        }| j                  |j                  | j                               | j                  |j                  | j                  dz                d}| j	                  |d   | j                  ||      ||d         }| j                   j                  || j                  | j                  j                        }| j                  |j                  | j                               | j                  |j                  | j                  dz                y)zm
        L{DigestCredentialFactory.decode} handles multiple responses to a
        single challenge.
        r   rG   r   r   r   s   00000002Nr   r   s        r   test_multiResponsez"DigestAuthTests.test_multiResponsev  s|   
 **778J8J8O8OP	,,G$++Ir:X&	 - 
 &&--DKK););)@)@
 	++DMM:;,,T]]X-EFG,,G$++Ir:X&	 - 
 &&--DKK););)@)@
 	++DMM:;,,T]]X-EFGr   c                    | j                   j                  | j                  j                        }d}| j	                  |d   | j                  ||      ||d         }| j                   j                  |d| j                  j                        }| j                  |j                  | j                               | j                  |j                  | j                  dz                y)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   rG   r   r   s   POSTr   N)
r>   r   r<   r   r   r   r   r   r   r6   r   s        r   test_failsWithDifferentMethodz-DigestAuthTests.test_failsWithDifferentMethod  s     **778J8J8O8OP	,,G$++Ir:X&	 - 
 &&--GT%7%7%<%<
 	,,T]];<,,T]]X-EFGr   c                    | j                  t        | j                  j                  | j	                  d      | j
                  | j                  j                        }| j                  t        |      d       | j                  t        | j                  j                  | j	                  d      | j
                  | j                  j                        }| j                  t        |      d       y)z
        L{DigestCredentialFactory.decode} raises L{LoginFailed} if the response
        has no username field or if the username field is empty.
        N)r5   z$Invalid response, no username given.r   
assertRaisesr   r>   r   r   r=   r<   r   rD   strr   es     r   test_noUsernamezDigestAuthTests.test_noUsername  s     "")).KK##
 	Q!GH ""))-KK##
 	Q!GHr   c                     | j                  t        | j                  j                  | j	                  d      | j
                  | j                  j                        }| j                  t        |      d       y)zo
        L{DigestCredentialFactory.decode} raises L{LoginFailed} if the response
        has no nonce.
        rd   )r   z!Invalid response, no nonce given.Nr   r   s     r   test_noNoncezDigestAuthTests.test_noNonce  sd    
 ""))y1KK##
 	Q!DEr   c                     | j                  t        | j                  j                  | j	                         | j
                  | j                  j                        }| j                  t        |      d       y)zp
        L{DigestCredentialFactory.decode} raises L{LoginFailed} if the response
        has no opaque.
        z"Invalid response, no opaque given.Nr   r   s     r   test_noOpaquezDigestAuthTests.test_noOpaque  s_    
 ""))!KK##
 	Q!EFr   c                    | j                   j                  | j                  j                        }d}| j	                  |d   | j                  ||      ||d         }| j                   j                  || j                  | j                  j                        }| j                  t        t        |             | j                  dz   | j                  z   dz   | j                  z   }t        |      }| j                  |j                  t!        |j#                                            |j%                  d       | j'                  |j                  t!        |j#                                            y)z
        L{DigestCredentialFactory.decode} returns an L{IUsernameDigestHash}
        provider which can verify a hash of the form 'username:realm:password'.
        r   rG   r   r   rA   r   N)r>   r   r<   r   r   r   r   r=   r   r   r   r5   r7   r6   r   	checkHashr   rC   updater   )r   r   r   r   r   	cleartexthashs          r   test_checkHashzDigestAuthTests.test_checkHash  s$   
 **778J8J8O8OP	,,G$++Ir:X&	 - 
 &&--DKK););)@)@
 	%8%@AMMD(4::5<t}}L	9~(>?@H)?@Ar   c           	         t        | j                  | j                        }|j                  | j                  j
                        }| j                  t        |j                  d|d   | j                  j
                        }| j                  t        |      d       dt        d      z   }| j                  t        |j                  ||d   | j                  j
                        }| j                  t        |      d       | j                  t        |j                  d|d   | j                  j
                        }| j                  t        |      d       dt        dj                  |d   t        | j                  j
                        df            z   }| j                  t        |j                  ||d   | j                  j
                        }| j                  t        |      d	       y
)z
        L{DigestCredentialFactory.decode} raises L{LoginFailed} when the opaque
        value does not contain all the required parts.
        s	   badOpaquerG   z&Invalid response, invalid opaque values   foo-s   nonce,clientipr      ,r0   z,Invalid response, invalid opaque/time valuesN)r   r8   r7   r   r<   r   r   r   _verifyOpaquerD   r   r   rB   r   )r   r>   r   exc	badOpaques        r   test_invalidOpaquez"DigestAuthTests.test_invalidOpaque  s   
 8

S%2243E3E3J3JK	++g##
 	S#KLi(9::	++g##
 	S#KL++g##
 	S#KLiII7#]43E3E3J3J%KYW
 
	
 ++g##
 	S#QRr   c                 (   t        | j                  | j                        }|j                  | j                  j
                        }|j                  d| j                  j
                        }| j                  t        |j                  ||d   | j                  j
                        }| j                  t        |      d       | j                  t        |j                  |d| j                  j
                        }| j                  t        |      d       y)z
        L{DigestCredentialFactory.decode} raises L{LoginFailed} when the given
        nonce from the response does not match the nonce encoded in the opaque.
        s
   1234567890rG   z2Invalid response, incompatible opaque/nonce valuesr   N)r   r8   r7   r   r<   r   _generateOpaquer   r   r   rD   r   )r   r>   r   badNonceOpaquer   s        r   test_incompatibleNoncez&DigestAuthTests.test_incompatibleNonce1  s    
 8

S%2243E3E3J3JK	*::4--22
 ++g##
 	S#WX++##
 	S#WXr   c                 |   t        | j                  | j                        }|j                  | j                  j
                        }d}| j                  | j                  j
                  |       |j                  |d   |      }| j                  t        |j                  ||d   | j                  j
                         y)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.1rG   N)r   r8   r7   r   r<   r   assertNotEqualr   r   r   r   )r   r>   r   
badAddressr   s        r   test_incompatibleClientIPz)DigestAuthTests.test_incompatibleClientIPO  s     8

S%2243E3E3J3JK	
D..33Z@*::g

 	++g##	
r   c                 "   t        | j                  | j                        }|j                  | j                  j
                        }dj                  |d   t        | j                  j
                        df      }t        t        ||j                  z         j                               }t        |      }dj                  ||j                  d      f      }| j                  t        |j                   ||d   | j                  j
                         y)z
        L{DigestCredentialFactory.decode} raises L{LoginFailed} when the given
        opaque is older than C{DigestCredentialFactory.CHALLENGE_LIFETIME_SECS}
        r   rG   s
   -137876876   -   
N)r   r8   r7   r   r<   r   rB   r   r   r   r   rC   r   r   r   r   r   )r   r>   r   keyrC   ekeyoldNonceOpaques          r   test_oldNoncezDigestAuthTests.test_oldNonceh  s    
 8

S%2243E3E3J3JK	iiwt/A/A/F/F!GW
 S#4#?#??@GGIJ~FDJJu,=#>?++g##	
r   c                    t        | j                  | j                        }|j                  | j                  j
                        }dj                  |d   t        | j                  j
                        df      }t        t        |dz         j                               }dj                  |t        |      f      }| j                  t        |j                  ||d   | j                  j
                         y)z~
        L{DigestCredentialFactory.decode} raises L{LoginFailed} when the opaque
        checksum fails verification.
        r   rG   r   s   this is not the right pkeyr   N)r   r8   r7   r   r<   r   rB   r   r   r   rC   r   r   r   r   )r   r>   r   r   rC   badChecksums         r   test_mismatchedOpaqueChecksumz-DigestAuthTests.test_mismatchedOpaqueChecksum  s    
 8

S%2243E3E3J3JK	iiwt/A/A/F/F!GN
 S#@@AHHJKii3 89++g##	
r   c                 d    d}|D ])  \  }}}}| j                  t        t        d|||dd|	       + y)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   r1   s   nonces   cnonce)preHA1N)r   	TypeErrorr	   )r   	argumentspszUsernamepszRealmpszPasswordr   s         r   test_incompatibleCalcHA1Optionsz/DigestAuthTests.test_incompatibleCalcHA1Options  sR    
	 ;D 	6K;  
	r   c                 `    | j                   j                  dd      }| j                  d|       y)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   )r>   r   assertNotIn)r   r   s     r   test_noNewlineOpaquez$DigestAuthTests.test_noNewlineOpaque  s-    
 ''778KTR'r   N)T)*r(   r)   r*   r+   r?   r   rK   rO   rR   rW   rZ   r\   r^   r`   rb   ri   rk   rm   rq   rs   ru   r   r   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   s    U )/c ++* -3# 
+ 06S 
+-0.1 /5C + /0 4: +B45&
PH*"!H$!HFH,I2FGB41SfY<
2
0
.2(r   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   <module>r      sP       .  + 0 / +'"9 .~	(h ~	(r   