Ϫf]dZddlZddlmZddlmZmZddlmZddl m Z m Z m Z m Z mZddlmZddlmZdd lmZdd lmZd ZGd d e ZGddeZy)z[ Tests for L{twisted.cred._digest} and the associated bits in L{twisted.cred.credentials}. N)hexlify)md5sha1) verifyObject)DigestCredentialFactoryIUsernameDigestHashcalcHA1calcHA2 calcResponse) LoginFailed) IPv4Address) networkString)TestCasecHtj|jS)N)base64 b64encodestrip)ss C/usr/lib/python3/dist-packages/twisted/cred/test/test_digestauth.pyrrs   A  $ $ &&c.eZdZdZfdZdZdZxZS)FakeDigestCredentialFactoryz\ A Fake Digest Credential Factory that generates a predictable nonce and opaque c2t||i|d|_y)N0)super__init__ privateKey)selfargskwargs __class__s rrz$FakeDigestCredentialFactory.__init__'s $)&)rcy)z) Generate a static nonce s178288758716122392881254770685rs r_generateNoncez*FakeDigestCredentialFactory._generateNonce+s1rcy)z& Return a stable time rr#r$s r_getTimez$FakeDigestCredentialFactory._getTime1sr)__name__ __module__ __qualname____doc__rr%r' __classcell__)r!s@rrr!s 1 rrceZdZdZdZdefdZdZdZdefdZ defdZ d Z d Z d Z d Zdefd ZdZdZdefdZdZdZd)dZdZd)dZdZdZdZdZdZdZdZdZdZ dZ!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}. cd|_d|_d|_d|_d|_d|_d|_tdd d |_d |_ t|j|j|_ y ) z> Create a DigestCredentialFactory for testing foobarsbazquuxs test realmmd5s 29fc54aa1641c6fa0e151419361c8f23auths/write/TCPz10.2.3.4iuGETN) usernamepasswordrealm algorithmcnonceqopurir clientAddressmethodrcredentialFactoryr$s rsetUpzDigestAuthTests.setUp?sd" " " 9 ( EB !8!Trr1c>d}t||j|j|j||j}dj |j|j|jf}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 r5r7r6r9joinrdigest assertEqual)r _algorithm_hashnoncehashA1a1expecteds rtest_MD5HashA1zDigestAuthTests.test_MD5HashA1Nsz   tzz4==% YY tzz4==A B59++-. *rcd}td|j|j|j||j}|jdz|jzdz|jz}t t |j}|dz|zdz|jz}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 xyz321abcmd5-sessrAN) r r5r7r6r9rrrCrD)rrGrHrIha1rJs rtest_MD5SessionHashA1z%DigestAuthTests.test_MD5SessionHashA1[s   DMM5$++ ]]T !DJJ . 5 Ec"gnn&' 4Z% $ & 43r7>>+, *rc0|jdty)z L{calcHA1} accepts the C{'sha'} algorithm and returns a SHA hash of its parameters, excluding the nonce and cnonce. shaN)rKrr$s rtest_SHAHashA1zDigestAuthTests.test_SHAHashA1js FD)rcd}t|||jdd}|dz|jz}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'}. r4r2NrAr r;rrCrD)rrErFr=hashA2a2rJs rtest_MD5HashA2Authz"DigestAuthTests.test_MD5HashA2AuthqsX VTXXwE d]TXX %59++-. *rcd}d}t|||jd|}|dz|jzdz|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'}. r4s foobarbazsauth-intrANrT)rrErFr=hentityrUrVrJs rtest_MD5HashA2AuthIntz%DigestAuthTests.test_MD5HashA2AuthInt}sg VTXX{GL d]TXX % ,w 659++-. *rc&|jdy)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. rMN)rWr$s rtest_MD5SessHashA2Authz&DigestAuthTests.test_MD5SessHashA2Auths  ,rc&|jdy)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. rMN)rZr$s rtest_MD5SessHashA2AuthIntz)DigestAuthTests.test_MD5SessHashA2AuthInts "";/rc0|jdty)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'}. rQN)rWrr$s rtest_SHAHashA2Authz"DigestAuthTests.test_SHAHashA2Auths -rc0|jdty)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'}. rQN)rZrr$s rtest_SHAHashA2AuthIntz%DigestAuthTests.test_SHAHashA2AuthInts ""640rc d}d}d}|dz|zdz|z}t||j}t||||ddd}|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} abc123789xyzlmnopqrANrrCr rD) rrErFrHrUrGresponserJrCs rtest_MD5HashResponsez$DigestAuthTests.test_MD5HashResponsesh D=5(4/&85?1134ffj%tTR 6*rc&|jdy)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} rMN)rir$s rtest_MD5SessionHashResponsez+DigestAuthTests.test_MD5SessionHashResponses !!+.rc0|jdty)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} rQN)rirr$s rtest_SHAHashResponsez$DigestAuthTests.test_SHAHashResponses !!&$/rc d}d}d}d}d}d}|dz|zdz|zdz|zdz|zdz|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. rdrerfs00000004s abcxyz123r2rANrg) rrErFrHrUrG nonceCount clientNoncer:rhrJrCs rtest_MD5HashResponseExtraz)DigestAuthTests.test_MD5HashResponseExtras  "                  5?1134 FJz;  6*rc&|jdy)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. rMN)rqr$s r test_MD5SessionHashResponseExtraz0DigestAuthTests.test_MD5SessionHashResponseExtras &&{3rc0|jdty)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. rQN)rqrr$s rtest_SHAHashResponseExtraz)DigestAuthTests.test_SHAHashResponseExtras &&vt4rc d|vr|j|d<d|vr|j|d<d|vr|j|d<d|vr|j|d<d|vr|j|d<d|vr|j |d<|rd}nd}d j |jDcgc]&\}}|dj t|d |||f(c}}Scc}}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. r5r7r8r:r9r;"rs, =) r5r7r8r:r9r;rBitemsr)rquoteskwquotekvs rformatResponsezDigestAuthTests.formatResponses R !]]BzN " **BwK b "nnB{O ?BuI 2 ;;BxL ?BuI EEzz!hhj Q=-*D%EBC    s+C c `|jd}|jdj}|jd}t||j|j|j ||j }t|d|j|d}t||||||j |}|S)z@ Calculate the response for the given challenge rGr8r:r4N) getlowerr r5r7r6r9r r;r ) r challengencountrGalgor:rNha2rJs rgetDigestResponsez!DigestAuthTests.getDigestResponses g&}}[)//1mmE" $--T]]E4;; dFDHHc48S$vt{{CPrc|jj|jj}d}|j ||d|j ||||d}|jj ||j|jj}|j|j|j|j|j|jdzy)z L{DigestCredentialFactory.decode} accepts a digest challenge response and parses it into an L{IUsernameHashedPassword} provider. 00000001rGopaque)rzrGrhncrwrongN r> getChallenger<hostrrdecoder= assertTrue checkPasswordr6 assertFalse)rrzrrclientResponsecredss r test_responsezDigestAuthTests.test_response.s **778J8J8O8OP ,,G$++Ir:X& - &&-- DKK););)@)@  ++DMM:; ,,T]]X-EFGrc&|jdy)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)rr$s rtest_responseWithoutQuotesz*DigestAuthTests.test_responseWithoutQuotesCs 5!rc4d|_|jdy)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;rr$s rtest_responseWithCommaURIz)DigestAuthTests.test_responseWithCommaURILs " 4 rc2d|_|jy)zs The case of the algorithm value in the response is ignored when checking the credentials. sMD5Nr8rr$s rtest_caseInsensitiveAlgorithmz-DigestAuthTests.test_caseInsensitiveAlgorithmUs   rc2d|_|jy)zV The algorithm defaults to MD5 if it is not supplied in the response. Nrr$s rtest_md5DefaultAlgorithmz(DigestAuthTests.test_md5DefaultAlgorithm]s rc|jjd}d}|j|d|j||||d}|jj ||j d}|j |j|j|j|j|jdzy)z L{DigestCredentialFactory.decode} accepts a digest challenge response even if the client address it is passed is L{None}. NrrGrrGrhrrr) r>rrrrr=rrr6rrrrrrs rtest_responseWithoutClientIPz,DigestAuthTests.test_responseWithoutClientIPds **77= ,,G$++Ir:X& -  &&--ndkk4P ++DMM:; ,,T]]X-EFGrc^|jj|jj}d}|j |d|j ||||d}|jj ||j|jj}|j|j|j|j|j|jdzd}|j |d|j ||||d}|jj ||j|jj}|j|j|j|j|j|jdzy)zm L{DigestCredentialFactory.decode} handles multiple responses to a single challenge. rrGrrrs00000002Nrrs rtest_multiResponsez"DigestAuthTests.test_multiResponsevs| **778J8J8O8OP ,,G$++Ir:X& - &&-- DKK););)@)@  ++DMM:; ,,T]]X-EFG ,,G$++Ir:X& - &&-- DKK););)@)@  ++DMM:; ,,T]]X-EFGrc|jj|jj}d}|j |d|j ||||d}|jj |d|jj}|j|j|j|j|j|jdzy)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. rrGrrsPOSTrN) r>rr<rrrrrrr6rs rtest_failsWithDifferentMethodz-DigestAuthTests.test_failsWithDifferentMethods**778J8J8O8OP ,,G$++Ir:X& -  &&-- GT%7%7%<%<  ,,T]];< ,,T]]X-EFGrc|jt|jj|j d|j |j j}|jt|d|jt|jj|j d|j |j j}|jt|dy)z L{DigestCredentialFactory.decode} raises L{LoginFailed} if the response has no username field or if the username field is empty. N)r5z$Invalid response, no username given.r assertRaisesr r>rrr=r<rrDstrres rtest_noUsernamezDigestAuthTests.test_noUsernames      " " ) )     . KK    # #   Q!GH      " " ) )     - KK    # #   Q!GHrc|jt|jj|j d|j |j j}|jt|dy)zo L{DigestCredentialFactory.decode} raises L{LoginFailed} if the response has no nonce. rd)rz!Invalid response, no nonce given.Nrrs r test_noNoncezDigestAuthTests.test_noNoncesd      " " ) )   y  1 KK    # #   Q!DErc|jt|jj|j |j |j j}|jt|dy)zp L{DigestCredentialFactory.decode} raises L{LoginFailed} if the response has no opaque. z"Invalid response, no opaque given.Nrrs r test_noOpaquezDigestAuthTests.test_noOpaques_      " " ) )    ! KK    # #   Q!EFrc|jj|jj}d}|j |d|j ||||d}|jj ||j|jj}|jtt||jdz|jzdz|jz}t|}|j|jt!|j#|j%d|j'|jt!|j#y)z L{DigestCredentialFactory.decode} returns an L{IUsernameDigestHash} provider which can verify a hash of the form 'username:realm:password'. rrGrrrArN)r>rr<rrrrr=rrrr5r7r6r checkHashrrCupdater)rrrrr cleartexthashs rtest_checkHashzDigestAuthTests.test_checkHashs$ **778J8J8O8OP ,,G$++Ir:X& - &&-- DKK););)@)@   %8%@AMMD(4::5?@ H )?@Arc t|j|j}|j|jj }|j t|jd|d|jj }|jt|ddtdz}|j t|j||d|jj }|jt|d|j t|jd|d|jj }|jt|ddtdj|dt|jj dfz}|j t|j||d|jj }|jt|d y ) z L{DigestCredentialFactory.decode} raises L{LoginFailed} when the opaque value does not contain all the required parts. s badOpaquerGz&Invalid response, invalid opaque valuesfoo-snonce,clientipr,r0z,Invalid response, invalid opaque/time valuesN)rr8r7rr<rrr _verifyOpaquerDrrrBr)rr>rexc badOpaques rtest_invalidOpaquez"DigestAuthTests.test_invalidOpaques 8 S%2243E3E3J3JK    + +  g     # #   S#KLi(9::    + +  g     # #   S#KL   + +  g     # #   S#KLi II7#]43E3E3J3J%KYW      + +  g     # #   S#QRrc(t|j|j}|j|jj }|j d|jj }|jt|j||d|jj }|jt|d|jt|j|d|jj }|jt|dy)z L{DigestCredentialFactory.decode} raises L{LoginFailed} when the given nonce from the response does not match the nonce encoded in the opaque. s 1234567890rGz2Invalid response, incompatible opaque/nonce valuesrN) rr8r7rr<r_generateOpaquerr rrDr)rr>rbadNonceOpaquers rtest_incompatibleNoncez&DigestAuthTests.test_incompatibleNonce1s 8 S%2243E3E3J3JK *:: 4--22    + +  g     # #   S#WX   + +      # #   S#WXrc|t|j|j}|j|jj }d}|j |jj ||j|d|}|jt|j||d|jj y)z L{DigestCredentialFactory.decode} raises L{LoginFailed} when the request comes from a client IP other than what is encoded in the opaque. z10.0.0.1rGN) rr8r7rr<rassertNotEqualrrr r)rr>r badAddressrs rtest_incompatibleClientIPz)DigestAuthTests.test_incompatibleClientIPOs 8 S%2243E3E3J3JK   D..33Z@*:: g       + +  g     # #  rc"t|j|j}|j|jj }dj |dt|jj df}tt||jzj}t|}dj ||jdf}|jt|j ||d|jj y)z L{DigestCredentialFactory.decode} raises L{LoginFailed} when the given opaque is older than C{DigestCredentialFactory.CHALLENGE_LIFETIME_SECS} rrGs -137876876- N)rr8r7rr<rrBrrrrrCrrrr r)rr>rkeyrCekeyoldNonceOpaques r test_oldNoncezDigestAuthTests.test_oldNoncehs 8 S%2243E3E3J3JK ii w t/A/A/F/F!G W S#4#?#??@GGIJ~FDJJu,=#>?    + +  g     # #  rct|j|j}|j|jj }dj |dt|jj df}tt|dzj}dj |t|f}|jt|j||d|jj y)z~ L{DigestCredentialFactory.decode} raises L{LoginFailed} when the opaque checksum fails verification. rrGrsthis is not the right pkeyrN)rr8r7rr<rrBrrrrCrrr r)rr>rrrC badChecksums rtest_mismatchedOpaqueChecksumz-DigestAuthTests.test_mismatchedOpaqueChecksums 8 S%2243E3E3J3JK ii w t/A/A/F/F!G N S#@@AHHJKii3 89     + +  g     # #  rc dd}|D])\}}}}|jttd|||dd| +y)z L{calcHA1} raises L{TypeError} when any of the pszUsername, pszRealm, or pszPassword arguments are specified with the preHA1 keyword argument. ))suserrealmpasswordpreHA1)NrNr)NNrrr1snoncescnonce)preHA1N)r TypeErrorr )r arguments pszUsernamepszRealm pszPasswordrs rtest_incompatibleCalcHA1Optionsz/DigestAuthTests.test_incompatibleCalcHA1OptionssR  ;D  6K;      rc`|jjdd}|jd|y)z L{DigestCredentialFactory._generateOpaque} returns a value without newlines, regardless of the length of the nonce. snlong nonce long nonce long nonce long nonce long nonce long nonce long nonce long nonce long nonce long nonce Nr)r>r assertNotIn)rrs rtest_noNewlineOpaquez$DigestAuthTests.test_noNewlineOpaques- ''778KTR 'rN)T)*r(r)r*r+r?rrKrOrRrWrZr\r^r`rbrirkrmrqrsrurrrrrrrrrrrrrrrrrrrrrr#rrr.r.8s U)/c + +*-3# +06S +-0.1/5C+ /04:+B45& P H*"!H$!HFH,I2 F GB41SfY< 2 0 .2(rr.)r+rbinasciirhashlibrrzope.interface.verifyrtwisted.cred.credentialsrrr r r twisted.cred.errorr twisted.internet.addressr twisted.python.compatrtwisted.trial.unittestrrrr.r#rrrsP .+0/+'"9.~ (h~ (r