Ϫf\&dZddlZddlmZddlmZddlmZmZddl m Z m Z m Z ddl mZddlmZdd lmZdd lmZdd lmZdd lmZdd lmZddlmZmZddlmZddl m!Z!m"Z"ddl#m$Z$ddl%m&Z&m'Z'm(Z(ddl)m*Z*ddl+m,Z,ddl-m.Z.dZ/GddZ0GddZ1Gdde1e0ejdZ3Gdde1ejdZ4Gdd e1ejdZ5eejlGd!d"Z7Gd#d$ejdZ8y)%z! Tests for L{twisted.web._auth}. N) implementer) verifyObject)errorportal) ANONYMOUSAllowAnonymousAccess'InMemoryUsernamePasswordDatabaseDontUse)IUsernamePassword) IPv4Address)ConnectionDone)EventLoggingObserver)globalLogPublisher)Failure)unittest)basicdigest)BasicCredentialFactory)HTTPAuthSessionWrapperUnauthorizedResource)ICredentialFactory) IResourceResourcegetChildForRequest NOT_DONE_YET)Data) DummyRequestcHtj|jSN)base64 b64encodestrip)ss @/usr/lib/python3/dist-packages/twisted/web/test/test_httpauth.pyr!r!%s   A  $ $ &&c<eZdZdZdZd dZdZdZdZdZ d Z y) BasicAuthTestsMixinz L{TestCase} mixin class which defines a number of tests for L{basic.BasicCredentialFactory}. Because this mixin defines C{setUp}, it must be inherited before L{TestCase}. c|j|_d|_d|_d|_t j |j|_y)NsfoosdreidsS3CuR1Ty) makeRequestrequestrealmusernamepasswordrrcredentialFactoryselfs r$setUpzBasicAuthTestsMixin.setUp0s>'')    # !&!=!=djj!Ir%Nc2t|jd)z Create a request object to be passed to L{basic.BasicCredentialFactory.decode} along with a response value. Override this in a subclass. z did not implement makeRequest)NotImplementedError __class__)r0method clientAddresss r$r)zBasicAuthTestsMixin.makeRequest7s "T^^$66T"UVVr%cV|jtt|jy)zM L{BasicCredentialFactory} implements L{ICredentialFactory}. N assertTruerrr.r/s r$test_interfacez"BasicAuthTestsMixin.test_interface?  %79O9OPQr%ctdj|jd|jg}|jj ||j }|jtj||j|j|j|j|j|jdzy)z L{basic.BasicCredentialFactory.decode} turns a base64-encoded response into a L{UsernamePassword} object with a password which reflects the one which was encoded in the response. r%:swrongN) r!joinr,r-r.decoder*r9r providedBy checkPassword assertFalser0responsecredss r$test_usernamePasswordz)BasicAuthTestsMixin.test_usernamePasswordEs SXXt}}dDMM&JKL&&--h E )44U;< ++DMM:; ,,T]]X-EFGr%cftdj|jd|jg}|j d}|j j ||j}|jtt||j|j|jy)zz L{basic.BasicCredentialFactory.decode} decodes a base64-encoded response with incorrect padding. r%r==N) r!r>r,r-r"r.r?r*r9rr rArCs r$test_incorrectPaddingz)BasicAuthTestsMixin.test_incorrectPaddingRs SXXt}}dDMM&JKL>>$'&&--h E  %6>? ++DMM:;r%cd}|jtj|jj||j y)z L{basic.BasicCredentialFactory.decode} raises L{LoginFailed} if passed a response which is not base64-encoded. xN) assertRaisesr LoginFailedr.r?r)r0rDs r$test_invalidEncodingz(BasicAuthTestsMixin.test_invalidEncoding^s>       " " ) )       r%ctd}|jtj|jj ||j y)z L{basic.BasicCredentialFactory.decode} raises L{LoginFailed} when passed a response which is not valid base64-encoded text. s123abc+/N)r!rLrrMr.r?r)rNs r$test_invalidCredentialsz+BasicAuthTestsMixin.test_invalidCredentialsksC [)      " " ) )       r%GETN) __name__ __module__ __qualname____doc__r1r)r:rFrIrOrQr%r$r'r')s. JWR H <    r%r'ceZdZddZy) RequestMixinNcV| tddd}td}||_||_|S)zo Create a L{DummyRequest} (change me to create a L{twisted.web.http.Request} instead). TCP localhosti/)r rr5client)r0r5r6r*s r$r)zRequestMixin.makeRequestzs5  '{DAMt$&r%rR)rTrUrVr)rXr%r$rZrZys r%rZceZdZdZy)BasicAuthTestszK Basic authentication tests which use L{twisted.web.http.Request}. N)rTrUrVrWrXr%r$rarasr%rac.eZdZdZdZdZdZdZdZy)DigestAuthTestszL Digest authentication tests which use L{twisted.web.http.Request}. cd|_d|_tj|j|j|_|j |_y)z> Create a DigestCredentialFactory for testing test realmmd5N)r+ algorithmrDigestCredentialFactoryr.r)r*r/s r$r1zDigestAuthTests.setUpsD# !'!?!? NNDJJ" '') r%c*dddgtfd}jjjd|j t dd}jj |jdy ) z L{digest.DigestCredentialFactory.decode} calls the C{decode} method on L{twisted.cred.digest.DigestCredentialFactory} with the HTTP method and host of the request. s 169.254.0.1rSFc|j|j|j|dd<y)NTr) assertEqual) _response_method_hostdonehostr5rDr0s r$checkz*DigestAuthTests.test_decode..checks<   Xy 1   VW -   T5 )DGr%r?r\QrN)objectpatchr.rr)r r?r9)r0rqreqrorpr5rDs` @@@@r$ test_decodezDigestAuthTests.test_decodes w8   4))00(EBv{5$'CD %%h4 Q r%cV|jtt|jy)zN L{DigestCredentialFactory} implements L{ICredentialFactory}. Nr8r/s r$r:zDigestAuthTests.test_interfacer;r%cb|jj|j}|j|dd|j|dd|j|dd|j d||j d||j D]}|j d |y ) ah The challenge issued by L{DigestCredentialFactory.getChallenge} must include C{'qop'}, C{'realm'}, C{'algorithm'}, C{'nonce'}, and C{'opaque'} keys. The values for the C{'realm'} and C{'algorithm'} keys must match the values supplied to the factory's initializer. None of the values may have newlines in them. qopauthr+rergrfnonceopaque N)r. getChallenger*rkassertInvalues assertNotIn)r0 challengevs r$test_getChallengez!DigestAuthTests.test_getChallenges**77 E  5)73 7+]; ;/8 gy) h *!!# 'A   UA & 'r%c$|jdd}|jj|}|j|dd|j|dd|j|dd|j d ||j d |y) z L{DigestCredentialFactory.getChallenge} can issue a challenge even if the L{Request} it is passed returns L{None} from C{getClientIP}. rSNryrzr+rergrfr{r|)r)r.r~rkr)r0r*rs r$ test_getChallengeWithoutClientIPz0DigestAuthTests.test_getChallengeWithoutClientIPs ""640**77@  5)73 7+]; ;/8 gy) h *r%N) rTrUrVrWr1rvr:rrrXr%r$rcrcs! *!,R '" +r%rcc4eZdZdZdZdZdZdZdZdZ y) UnauthorizedResourceTestsz, Tests for L{UnauthorizedResource}. ctg}|j|jdd||j|jdd|y)zF An L{UnauthorizedResource} is every child of itself. fooNbar)rassertIdenticalgetChildWithDefault)r0resources r$test_getChildWithDefaultz2UnauthorizedResourceTests.test_getChildWithDefaultsH(+ X99%FQ X99%FQr%cttdg}|j||j|jd|j|j j ddgy)z Render L{UnauthorizedResource} for the given request object and verify that the response code is I{Unauthorized} and that a I{WWW-Authenticate} header is set in the response containing a challenge. example.comwww-authenticatesbasic realm="example.com"N)rrrenderrk responseCoderesponseHeaders getRawHeaders)r0r*rs r$_unauthorizedRenderTestz1UnauthorizedResourceTests._unauthorizedRenderTestsb ()? )N(OPx  --s3   # # 1 12E F ) * r%c|j}|j||jddj|jy)z L{UnauthorizedResource} renders with a 401 response code and a I{WWW-Authenticate} header and puts a simple unauthorized message into the response body. s Unauthorizedr%Nr)rrkr>writtenr0r*s r$ test_renderz%UnauthorizedResourceTests.test_renders= ""$ $$W- #((7??*CDr%c|jd}|j||jddj|jy)z The rendering behavior of L{UnauthorizedResource} for a I{HEAD} request is like its handling of a I{GET} request, but no response body is written. sHEAD)r5r%Nrrs r$test_renderHEADz)UnauthorizedResourceTests.test_renderHEADsB ""'"2 $$W- chhw78r%cttdg}|j}|j||j |j j ddgy)z The realm value included in the I{WWW-Authenticate} header set in the response when L{UnauthorizedResounrce} is rendered has quotes and backslashes escaped. z example\"foorsbasic realm="example\\\"foo"N)rrr)rrkrr)r0rr*s r$test_renderQuotesRealmz0UnauthorizedResourceTests.test_renderQuotesRealmsZ ()?)P(QR""$x    # # 1 12E F / 0 r%c ttjddg}|j}|j ||j j dd}|jd||jd|y)z The digest value included in the I{WWW-Authenticate} header set in the response when L{UnauthorizedResource} is rendered has quotes and backslashes escaped. rfs example\"foorrsrealm="example\\\"foo"shm="md5N)rrrhr)rrrr)r0rr* authHeaders r$test_renderQuotesDigestz1UnauthorizedResourceTests.test_renderQuotesDigestsx (  + +F4D E F ""$x ,,::;NOPQR  2J? j*-r%N) rTrUrVrWrrrrrrrXr%r$rrs'R  E9   .r%rc"eZdZdZdZdZdZy)RealmaJ A simple L{IRealm} implementation which gives out L{WebAvatar} for any avatarId. @type loggedIn: C{int} @ivar loggedIn: The number of times C{requestAvatar} has been invoked for L{IResource}. @type loggedOut: C{int} @ivar loggedOut: The number of times the logout callback has been invoked. c.d|_d|_||_y)Nr) loggedOutloggedIn avatarFactory)r0rs r$__init__zRealm.__init__5s *r%ct|vr7|xjdz c_t|j||jfSt N)rrrlogoutr3)r0avatarIdmind interfacess r$ requestAvatarzRealm.requestAvatar:s=  " MMQ Md00:DKKG G!##r%c.|xjdz c_yr)rr/s r$rz Realm.logout@s !r%N)rTrUrVrWrrrrXr%r$rr(s + $ r%rceZdZdZeZdZdZdZdZ dZ dZ dZ d Z d Zd Zd Zd ZdZdZdZdZdZdZy)HTTPAuthHeaderTestsz. Tests for L{HTTPAuthSessionWrapper}. cd|_d|_d|_d|_d|_t |_|j j|j|jt|jd|_ |jj|jt|jd|j|ji|_ t|jj|_tj |j|j g|_g|_t%|j|j"|_y)z\ Create a realm, portal, and L{HTTPAuthSessionWrapper} to use in the tests. sfoo barsbar bazs&contents of the avatar resource itselfs foo-childs'contents of the foo child of the avatar text/plainN)r,r- avatarContent childName childContentr checkeraddUserravatarputChildavatarsrgetr+rPortalcredentialFactoriesrwrapperr/s r$r1zHTTPAuthHeaderTests.setUpKs# " F%F>@  T]]DMM:4--|<  T^^T$2C2C\-RS t{{3 4<<++, mmDJJ? #% -dkk4;S;ST r%ct|jdz|jz}|jj dd|zt |j |S)z Add an I{basic authorization} header to the given request and then dispatch it, starting from C{self.wrapper} and returning the resulting L{IResource}. r= authorizationBasic )r!r,r-requestHeaders addRawHeaderrr)r0r* authorizations r$_authorizedBasicLoginz)HTTPAuthHeaderTests._authorizedBasicLogin^sM "$--$"6"FG ++,WX!$,,88r%cjjgtj}j }fd}|j |j ||S)z Resource traversal which encounters an L{HTTPAuthSessionWrapper} results in an L{UnauthorizedResource} instance when the request does not have the required I{Authorization} headers. c>jjdyNrrkrresultr*r0s r$ cbFinishedz@HTTPAuthHeaderTests.test_getChildWithDefault..cbFinishedr   W113 7r%)r)rrr notifyFinish addCallbackrr0childdrr*s` @r$rz,HTTPAuthHeaderTests.test_getChildWithDefaulths^ ""DNN#34"4<<9  " 8 j!ur%c^jjtdjjgj j d|tj}j}fd}|j|j||S)a( Create a request with the given value as the value of an I{Authorization} header and perform resource traversal with it, starting at C{self.wrapper}. Assert that the result is a 401 response code. Return a L{Deferred} which fires when this is all done. rrc>jjdyrrrs r$rzAHTTPAuthHeaderTests._invalidAuthorizationTest..cbFinishedrr%) rappendrr)rrrrrrrr)r0rDrrrr*s` @r$_invalidAuthorizationTestz-HTTPAuthHeaderTests._invalidAuthorizationTestys   ''(>}(MN""DNN#34++,HTTPAuthHeaderTests.test_getChildWithDefaultUnrecognizedSchemes --.ABBr%cjjtdjjgj }j }fd}|j|j||S)z Resource traversal which encounters an L{HTTPAuthSessionWrapper} results in an L{IResource} which renders the L{IResource} avatar retrieved from the portal when the request has a valid I{Authorization} header. rcTjjjgyr)rkrrignoredr*r0s r$rzJHTTPAuthHeaderTests.test_getChildWithDefaultAuthorized..cbFinisheds   W__t/@/@.A Br%) rrrr)rrrrrrs` @r$"test_getChildWithDefaultAuthorizedz6HTTPAuthHeaderTests.test_getChildWithDefaultAuthorizedsy   ''(>}(MN""DNN#34**73  " C j!ur%cjjtdjgj }j }fd}|j |j||S)a Resource traversal which terminates at an L{HTTPAuthSessionWrapper} and includes correct authentication headers results in the L{IResource} avatar (not one of its children) retrieved from the portal being rendered. rcTjjjgyr)rkrrrs r$rz=HTTPAuthHeaderTests.test_renderAuthorized..cbFinisheds   W__t/A/A.B Cr%)rrrr)rrrrrs` @r$test_renderAuthorizedz)HTTPAuthHeaderTests.test_renderAuthorizedsr   ''(>}(MN""2&**73  " D j!ur%c^ttGdd}|jjj j gt j}j}fd}|j|j||S)z When L{HTTPAuthSessionWrapper} finds an L{ICredentialFactory} to issue a challenge, it calls the C{getChallenge} method with the request as an argument. ceZdZdZdZdZy)UHTTPAuthHeaderTests.test_getChallengeCalledWithRequest..DumbCredentialFactorysdumbcg|_yr)requestsr/s r$rz^HTTPAuthHeaderTests.test_getChallengeCalledWithRequest..DumbCredentialFactory.__init__s " r%c<|jj|iSr)rrrs r$r~zbHTTPAuthHeaderTests.test_getChallengeCalledWithRequest..DumbCredentialFactory.getChallenges $$W- r%N)rTrUrVschemerr~rXr%r$DumbCredentialFactoryrsF # r%rc@jjgyr)rkr)rfactoryr*r0s r$rzJHTTPAuthHeaderTests.test_getChallengeCalledWithRequest..cbFinisheds   W--y 9r%) rrrrr)rrrrrr)r0rrrrrr*s` @@r$"test_getChallengeCalledWithRequestz6HTTPAuthHeaderTests.test_getChallengeCalledWithRequests ' (   ) ()   ''0""DNN#34"4<<9  " : j!ur%c|jjtdGddt}|jj |j ||j|j g}|j|}|j||j|jjd|S)a Issue a request for an authentication-protected resource using valid credentials and then return the C{DummyRequest} instance which was used. This is a helper for tests about the behavior of the logout callback. rceZdZdZy)7HTTPAuthHeaderTests._logoutTest..SlowerResourcectSrrrs r$rz>HTTPAuthHeaderTests._logoutTest..SlowerResource.renders##r%N)rTrUrVrrXr%r$SlowerResourcers $r%rr) rrrrrrrr)rrrkr+r)r0rr*rs r$ _logoutTestzHTTPAuthHeaderTests._logoutTests   ''(>}(MN $X $ T^^^-=>""DNN#34**73u --q1r%c|j}|j|j|jjdy)zX The realm's logout callback is invoked after the resource is rendered. rN)rfinishrkr+rrs r$ test_logoutzHTTPAuthHeaderTests.test_logouts6""$ --q1r%c|j}|jttd|j |j j dy)z The realm's logout callback is also invoked if there is an error generating the response (for example, if the client disconnects early). zSimulated disconnectrN)rprocessingFailedrr rkr+rrs r$test_logoutOnErrorz&HTTPAuthHeaderTests.test_logoutOnError sE ""$  8N)O!PQ --q1r%c|jjtd|j|jg}|j j ddt|j|}|j|ty)z Resource traversal which enouncters an L{HTTPAuthSessionWrapper} results in an L{UnauthorizedResource} when the request has a I{Basic Authorization} header which cannot be decoded using base64. rrsBasic decode should failN) rrrr)rrrrrassertIsInstancer)r0r*rs r$test_decodeRaisesz%HTTPAuthHeaderTests.test_decodeRaisessr   ''(>}(MN""DNN#34++ 9 #4<<9 e%9:r%cd}|j|jj|dtd}|jj ||j|jj||dfy)z L{HTTPAuthSessionWrapper._selectParseHeader} returns a two-tuple giving the L{ICredentialFactory} to use to parse the header and a string containing the portion of the header which remains to be parsed. sBasic abcdef123456)NNrs abcdef123456N)rkr_selectParseHeaderrrr)r0basicAuthorizationrs r$test_selectParseResponsez,HTTPAuthHeaderTests.test_selectParseResponse$sv 3  LL + +,> ? )7   ''0  LL + +,> ? o & r%cttj|t}GddtGfdd}|jj ||j |jg}|jjddt|j|}|j||j|jd|jdt!||j#|d d j$|jt!|j'dy ) z Any unexpected exception raised by the credential factory's C{decode} method results in a 500 response code and causes the exception to be logged. c eZdZy)KHTTPAuthHeaderTests.test_unexpectedDecodeError..UnexpectedExceptionNrTrUrVrXr%r$UnexpectedExceptionr = r%r c"eZdZdZdZfdZy)BHTTPAuthHeaderTests.test_unexpectedDecodeError..BadFactorysbadciSrrX)r0r_s r$r~zOHTTPAuthHeaderTests.test_unexpectedDecodeError..BadFactory.getChallengeCs r%crrX)r0rDr*r s r$r?zIHTTPAuthHeaderTests.test_unexpectedDecodeError..BadFactory.decodeF )++r%N)rTrUrVrr~r?r sr$ BadFactoryr@sF  ,r%rrsBad abcrr log_failureN)r createWithCleanupr Exceptionrrr)rrrrrrrkr assertEqualslenrvalueflushLoggedErrors)r0 logObserverrr*rr s @r$test_unexpectedDecodeErrorz.HTTPAuthHeaderTests.test_unexpectedDecodeError5s +<.UnexpectedExceptionNr rXr%r$r r"Zrr%r ceZdZefZfdZy)DHTTPAuthHeaderTests.test_unexpectedLoginError..BrokenCheckercrrX)r0 credentialsr s r$requestAvatarIdzTHTTPAuthHeaderTests.test_unexpectedLoginError..BrokenChecker.requestAvatarId`rr%N)rTrUrVr credentialInterfacesr'rsr$ BrokenCheckerr$]s$5#7  ,r%r)rrrrrN)r rrrrregisterCheckerrrrr)rrrrkrrrrrr)r0rr)r*rr s @r$test_unexpectedLoginErrorz-HTTPAuthHeaderTests.test_unexpectedLoginErrorSs +<}(MN""DNN#34**73u --s3 !S-. k!n];AACVW T334GHI1Mr%cdtjt<jtjjt dj jtjjtdjjgtj}j}fd}|j!|j#||S)zl Anonymous requests are allowed if a L{Portal} has an anonymous checker registered. s*contents of the unprotected child resourcerrc@jjgyr)rkr)rr*r0unprotectedContentss r$rz.cbFinisheds   W__/B.C Dr%)rrrrrrrr*rrrrr)rrrrr)r0rrrr*r.s` @@r$test_anonymousAccessz(HTTPAuthHeaderTests.test_anonymousAccessms L"** Y Y(( NND!4lC  ##$8$:;   ''(>}(MN""DNN#34"4<<9  " E j!ur%N)rTrUrVrWrr)r1rrrrrrrrrrrrrrrr+r/rXr%r$rrDsmKU&9"(Q  C&(>,22 ; "N<N4r%r)9rWr zope.interfacerzope.interface.verifyr twisted.credrrtwisted.cred.checkersrrr twisted.cred.credentialsr twisted.internet.addressr twisted.internet.errorr twisted.internet.testingr twisted.loggerrtwisted.python.failurer twisted.trialrtwisted.web._authrrtwisted.web._auth.basicrtwisted.web._auth.wrapperrrtwisted.web.iwebrtwisted.web.resourcerrrtwisted.web.serverrtwisted.web.staticrtwisted.web.test.test_webrr!r'rZTestCaserarcrIRealmrrrXr%r$rEs &.& 7019-*"+:R/HH+#2'M M `  \#68I8I H+lH$5$5H+VJ. h.?.?J.Z FMM8@(++@r%