From b30ed37f0c2209a7f2397c8e7b8d4d252fa16262 Mon Sep 17 00:00:00 2001 From: Joe Gregorio Date: Mon, 23 Jul 2012 14:45:17 -0400 Subject: Add control so that Authorization: headers aren't forwarded on a 3xx response by default. --- doc/html/_sources/libhttplib2.txt | 9 +++++++++ doc/html/genindex.html | 10 +++++++--- doc/html/index.html | 2 +- doc/html/libhttplib2.html | 12 +++++++++++- doc/html/objects.inv | Bin 1700 -> 667 bytes doc/html/search.html | 2 +- doc/html/searchindex.js | 2 +- doc/libhttplib2.rst | 9 +++++++++ libhttplib2.tex | 8 ++++++++ python2/httplib2/__init__.py | 7 ++++++- python2/httplib2test.py | 14 ++++++++++++++ python3/httplib2/__init__.py | 5 +++++ 12 files changed, 72 insertions(+), 8 deletions(-) diff --git a/doc/html/_sources/libhttplib2.txt b/doc/html/_sources/libhttplib2.txt index 53cb746..fc72bbf 100644 --- a/doc/html/_sources/libhttplib2.txt +++ b/doc/html/_sources/libhttplib2.txt @@ -307,6 +307,15 @@ Http Objects 'follow_redirects' must be True. +.. attribute:: Http.forward_authorization_headers + + If ``False``, which is the default, then Authorization: headers are + stripped from redirects. If ``True`` then Authorization: headers are left + in place when following redirects. This parameter only applies if following + redirects is turned on. Note that turning this on could cause your credentials + to leak, so carefully consider the consequences. + + .. attribute:: Http.force_exception_to_status_code If ``True`` then no :mod:`httplib2` exceptions will be diff --git a/doc/html/genindex.html b/doc/html/genindex.html index 9d54153..8e41809 100644 --- a/doc/html/genindex.html +++ b/doc/html/genindex.html @@ -124,17 +124,21 @@
follow_all_redirects (httplib2.Http attribute)
- -
follow_redirects (httplib2.Http attribute)
+
+
force_exception_to_status_code (httplib2.Http attribute)
+
forward_authorization_headers (httplib2.Http attribute) +
+ +
fromcache (httplib2.Response attribute)
@@ -330,7 +334,7 @@ diff --git a/doc/html/index.html b/doc/html/index.html index 40d4b9f..606200b 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -145,7 +145,7 @@ caching, keep-alive, compression, redirects and many kinds of authentication.

diff --git a/doc/html/libhttplib2.html b/doc/html/libhttplib2.html index 8c18816..12301a4 100644 --- a/doc/html/libhttplib2.html +++ b/doc/html/libhttplib2.html @@ -295,6 +295,16 @@ Another way of saying that is for ‘follow_all_redirects’ to have any ‘follow_redirects’ must be True.

+
+
+Http.forward_authorization_headers
+

If False, which is the default, then Authorization: headers are +stripped from redirects. If True then Authorization: headers are left +in place when following redirects. This parameter only applies if following +redirects is turned on. Note that turning this on could cause your credentials +to leak, so carefully consider the consequences.

+
+
Http.force_exception_to_status_code
@@ -515,7 +525,7 @@ request.

diff --git a/doc/html/objects.inv b/doc/html/objects.inv index 31ac672..5b3e2fd 100644 Binary files a/doc/html/objects.inv and b/doc/html/objects.inv differ diff --git a/doc/html/search.html b/doc/html/search.html index e01c727..92973d7 100644 --- a/doc/html/search.html +++ b/doc/html/search.html @@ -99,7 +99,7 @@ diff --git a/doc/html/searchindex.js b/doc/html/searchindex.js index 1c76b54..e71997e 100644 --- a/doc/html/searchindex.js +++ b/doc/html/searchindex.js @@ -1 +1 @@ -Search.setIndex({objects:{"":{httplib2:[1,0,1,""]},"httplib2.Response":{status:[1,3,1,""],reason:[1,3,1,""],version:[1,3,1,""],previous:[1,3,1,""],fromcache:[1,3,1,""]},"httplib2.Cache":{get:[1,2,1,""],set:[1,2,1,""],"delete":[1,2,1,""]},"httplib2.Http":{follow_redirects:[1,3,1,""],request:[1,2,1,""],force_exception_to_status_code:[1,3,1,""],clear_credentials:[1,2,1,""],optimistic_concurrency_methods:[1,3,1,""],follow_all_redirects:[1,3,1,""],add_certificate:[1,2,1,""],ignore_etag:[1,3,1,""],add_credentials:[1,2,1,""]},httplib2:{HttpLib2Error:[1,4,1,""],RETRIES:[1,5,1,""],Http:[1,1,1,""],FileCache:[1,1,1,""],UnimplementedHmacDigestAuthOptionError:[1,4,1,""],FailedToDecompressContent:[1,4,1,""],Response:[1,1,1,""],ServerNotFoundError:[1,4,1,""],RedirectMissingLocation:[1,4,1,""],debuglevel:[1,5,1,""],RedirectLimit:[1,4,1,""],RelativeURIError:[1,4,1,""],ProxyInfo:[1,1,1,""],UnimplementedDigestAuthOptionError:[1,4,1,""]}},terms:{all:1,code:1,chain:1,proxy_type_xxx:1,follow:1,privat:1,readabl:1,those:1,sent:1,liter:1,everi:1,string:1,fals:1,unfamiliar:1,proxy_typ:1,veri:1,affect:1,tri:1,force_exception_to_status_cod:1,level:1,list:1,"try":1,item:1,second:1,pass:1,"13t18":1,append:1,index:0,section:1,current:1,delet:1,version:1,"new":1,method:1,funtion:1,xml:1,deriv:1,gener:1,here:1,bodi:1,proxy_us:1,address:1,redirectmissingloc:1,ignore_etag:1,modifi:1,valu:1,search:0,respon:1,proxy_rdn:1,memcach:1,amount:1,connection_typ:1,implement:1,extra:1,appli:1,modul:[0,1],keyfil:1,filenam:1,"boolean":1,from:1,call:1,type:1,more:1,flat:1,trail:1,flag:1,cach:[0,1],must:1,none:1,hmacdigest:1,optimistic_concurrency_method:1,unimplementedhmacdigestauthoptionerror:1,can:1,aliv:[0,1],control:1,claim:1,process:1,challeng:1,indic:[0,1],aaaa:1,occur:1,multipl:1,anoth:1,instead:1,simpl:1,updat:1,map:1,mar:0,resourc:1,proxy_info:1,tact:1,befor:1,mai:1,httpconnect:1,data:1,unreserv:1,attempt:1,nativ:1,credenti:1,robot:1,inform:1,preced:1,allow:1,shadi:1,over:1,report:1,through:1,still:1,mainli:1,digest:1,paramet:1,uuid:1,complex:1,comprehens:[0,1],them:1,failedtodecompresscont:1,"return":1,thei:1,handl:[0,1],safe:1,httplib2:[0,1],gregorio:0,"80da344efa6a":1,httplib:1,name:1,authent:[0,1],timeout:1,each:1,debug:1,mean:1,compil:1,domain:1,follow_redirect:1,connect:1,our:1,variabl:1,proxy_pass:1,urlencod:1,publish:1,content:[0,1],etag:1,rel:1,debuglevel:1,print:1,proxi:1,fred:1,reason:1,base:1,dictionari:1,put:1,org:1,thrown:1,keep:[0,1],turn:1,unabl:1,caprici:1,first:1,oper:1,certfil:1,number:1,restrict:1,date:0,alreadi:1,done:1,messag:1,oppos:1,open:1,given:1,disable_ssl_certificate_valid:1,construct:1,attach:1,john:1,"final":1,store:1,xmln:1,option:1,specifi:1,cfb8:1,checkout:1,httplib2error:1,kind:0,provid:1,remov:1,proxy_type_http:1,were:1,pre:1,sai:1,ani:1,manner:1,have:1,tabl:0,mypasswd:1,note:1,also:1,client:[0,1],take:1,which:1,singl:1,begin:1,ca_cert:1,normal:1,previou:1,compress:[0,1],gzip:1,"class":1,urn:1,request:1,uri:1,doe:1,determin:1,text:1,unimplementeddigestauthoptionerror:1,redirect:[0,1],absolut:1,onli:1,locat:1,should:1,dict:1,bitwork:1,get:1,filecach:1,ssl:1,"3xx":1,requir:1,patch:1,contain:1,mynam:1,where:1,certif:1,set:1,see:1,respons:[0,1],fail:1,statu:1,detect:1,urllib:1,"import":1,"02z":1,attribut:1,kei:1,numer:1,proxy_port:1,entir:1,joe:0,come:1,popul:1,both:1,last:1,etc:1,instanc:1,mani:0,com:1,point:1,servernotfounderror:1,colon:1,suppli:1,ultim:1,three:1,compon:1,basic:1,addit:1,assert:1,understand:1,present:1,"case":1,plain:1,defin:1,error:1,"4ebb":1,dir_nam:1,need:1,follow_all_redirect:1,author:[0,1],perform:1,satisfi:1,cert:1,same:1,add_certif:1,html:1,complet:1,http:[0,1],rfc822:1,decompress:1,rais:1,chang:1,lower:1,entri:1,without:1,exampl:[0,1],add_credenti:1,thi:1,entiti:1,protocol:1,just:1,resp:1,human:1,httprespons:1,proxy_host:1,except:1,proxyinfo:1,add:1,match:1,applic:1,format:1,safenam:1,password:1,presum:1,amok:1,redirectlimit:1,lost:1,header:1,docutil:1,resolv:1,server:1,collect:1,either:1,page:0,encount:1,exceed:1,deal:1,some:1,back:1,librari:[0,1],clear_credenti:1,subclass:1,pem:1,retri:1,condit:1,localhost:1,object:[0,1],run:1,power:1,reach:1,broken:1,host:1,post:1,deflat:1,socket:1,default_max_redirect:1,fromcach:1,constructor:1,processor:1,own:1,www:1,automat:1,your:1,span:1,wai:1,support:1,sock:1,avail:1,interfac:1,includ:1,head:1,form:1,tupl:1,atom:1,"true":1,info:1,made:1,possibl:1,"default":1,wish:1,maximum:1,problem:1,"1225c695":1,featur:1,constant:1,creat:1,"abstract":0,repres:1,chap:1,exist:1,file:1,relativeurierror:1,titl:1,when:1,valid:1,you:1,lane:1,algorithm:1,directori:1,wsse:1,ignor:1,time:1},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:attribute","4":"py:exception","5":"py:data"},titles:["The httplib2 Library","httplib2 A comprehensive HTTP client library."],objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","attribute","Python attribute"],"4":["py","exception","Python exception"],"5":["py","data","Python data"]},filenames:["index","libhttplib2"]}) \ No newline at end of file +Search.setIndex({objects:{"":{httplib2:[1,0,1,""]},"httplib2.Response":{status:[1,3,1,""],reason:[1,3,1,""],version:[1,3,1,""],previous:[1,3,1,""],fromcache:[1,3,1,""]},"httplib2.Cache":{get:[1,2,1,""],set:[1,2,1,""],"delete":[1,2,1,""]},"httplib2.Http":{forward_authorization_headers:[1,3,1,""],follow_redirects:[1,3,1,""],request:[1,2,1,""],force_exception_to_status_code:[1,3,1,""],clear_credentials:[1,2,1,""],optimistic_concurrency_methods:[1,3,1,""],follow_all_redirects:[1,3,1,""],add_certificate:[1,2,1,""],ignore_etag:[1,3,1,""],add_credentials:[1,2,1,""]},httplib2:{HttpLib2Error:[1,4,1,""],RETRIES:[1,5,1,""],Http:[1,1,1,""],FileCache:[1,1,1,""],UnimplementedHmacDigestAuthOptionError:[1,4,1,""],FailedToDecompressContent:[1,4,1,""],Response:[1,1,1,""],ServerNotFoundError:[1,4,1,""],RedirectMissingLocation:[1,4,1,""],debuglevel:[1,5,1,""],RedirectLimit:[1,4,1,""],RelativeURIError:[1,4,1,""],ProxyInfo:[1,1,1,""],UnimplementedDigestAuthOptionError:[1,4,1,""]}},terms:{all:1,code:1,chain:1,proxy_type_xxx:1,follow:1,privat:1,readabl:1,those:1,sent:1,liter:1,everi:1,string:1,fals:1,unfamiliar:1,proxy_typ:1,veri:1,affect:1,tri:1,force_exception_to_status_cod:1,level:1,list:1,"try":1,item:1,consequ:1,second:1,pass:1,"13t18":1,append:1,index:0,section:1,current:1,delet:1,version:1,"new":1,method:1,funtion:1,redirect:[0,1],deriv:1,gener:1,here:1,bodi:1,proxy_us:1,address:1,redirectmissingloc:1,ignore_etag:1,modifi:1,valu:1,search:0,respon:1,proxy_rdn:1,memcach:1,amount:1,implement:1,extra:1,appli:1,modul:[0,1],keyfil:1,filenam:1,"boolean":1,from:1,call:1,type:1,more:1,flat:1,trail:1,flag:1,cach:[0,1],must:1,none:1,hmacdigest:1,optimistic_concurrency_method:1,unimplementedhmacdigestauthoptionerror:1,can:1,aliv:[0,1],control:1,claim:1,process:1,challeng:1,indic:[0,1],aaaa:1,occur:1,multipl:1,anoth:1,instead:1,simpl:1,updat:1,follow_redirect:1,mar:0,resourc:1,proxy_info:1,tact:1,befor:1,date:0,httpconnect:1,data:1,unreserv:1,attempt:1,ssl:1,credenti:1,robot:1,caus:1,inform:1,preced:1,allow:1,shadi:1,over:1,"3xx":1,through:1,still:1,mainli:1,digest:1,paramet:1,uuid:1,complex:1,comprehens:[0,1],them:1,failedtodecompresscont:1,"return":1,thei:1,handl:[0,1],safe:1,httplib2:[0,1],gregorio:0,"80da344efa6a":1,httplib:1,name:1,authent:[0,1],timeout:1,each:1,debug:1,mean:1,compil:1,domain:1,map:1,connect:1,our:1,variabl:1,proxy_pass:1,urlencod:1,publish:1,content:[0,1],etag:1,rel:1,debuglevel:1,print:1,proxi:1,fred:1,reason:1,base:1,dictionari:1,put:1,org:1,thrown:1,could:1,keep:[0,1],turn:1,place:1,unabl:1,caprici:1,first:1,oper:1,certfil:1,number:1,restrict:1,mai:1,alreadi:1,done:1,messag:1,oppos:1,open:1,given:1,disable_ssl_certificate_valid:1,construct:1,attach:1,john:1,"final":1,store:1,xmln:1,option:1,specifi:1,cfb8:1,httplib2error:1,kind:0,provid:1,remov:1,proxy_type_http:1,were:1,pre:1,sai:1,ani:1,manner:1,have:1,tabl:0,mypasswd:1,note:1,also:1,client:[0,1],take:1,which:1,singl:1,begin:1,ca_cert:1,normal:1,object:[0,1],compress:[0,1],gzip:1,"class":1,urn:1,request:1,uri:1,doe:1,determin:1,carefulli:1,text:1,unimplementeddigestauthoptionerror:1,xml:1,absolut:1,onli:1,locat:1,should:1,dict:1,bitwork:1,get:1,filecach:1,nativ:1,report:1,requir:1,patch:1,contain:1,mynam:1,where:1,certif:1,set:1,see:1,respons:[0,1],fail:1,statu:1,detect:1,urllib:1,"import":1,"02z":1,attribut:1,kei:1,numer:1,proxy_port:1,entir:1,joe:0,come:1,addit:1,both:1,last:1,etc:1,instanc:1,mani:0,com:1,point:1,header:1,colon:1,suppli:1,ultim:1,three:1,compon:1,basic:1,popul:1,wish:1,assert:1,understand:1,present:1,"case":1,plain:1,defin:1,error:1,"4ebb":1,dir_nam:1,applic:1,need:1,follow_all_redirect:1,author:[0,1],perform:1,satisfi:1,cert:1,same:1,add_certif:1,html:1,complet:1,http:[0,1],rfc822:1,decompress:1,rais:1,chang:1,lower:1,entri:1,without:1,exampl:[0,1],add_credenti:1,thi:1,entiti:1,left:1,protocol:1,just:1,resp:1,human:1,password:1,proxy_host:1,except:1,proxyinfo:1,add:1,match:1,connection_typ:1,format:1,safenam:1,httprespons:1,you:1,amok:1,redirectlimit:1,lost:1,servernotfounderror:1,docutil:1,resolv:1,server:1,collect:1,either:1,page:0,encount:1,exceed:1,deal:1,some:1,back:1,librari:[0,1],clear_credenti:1,leak:1,subclass:1,pem:1,retri:1,condit:1,localhost:1,previou:1,run:1,power:1,reach:1,broken:1,host:1,post:1,deflat:1,socket:1,default_max_redirect:1,fromcach:1,constructor:1,processor:1,own:1,www:1,automat:1,strip:1,your:1,span:1,wai:1,support:1,sock:1,avail:1,interfac:1,includ:1,head:1,form:1,tupl:1,atom:1,"true":1,info:1,made:1,possibl:1,"default":1,checkout:1,maximum:1,forward_authorization_head:1,problem:1,"1225c695":1,featur:1,constant:1,creat:1,"abstract":0,repres:1,chap:1,exist:1,file:1,relativeurierror:1,titl:1,when:1,valid:1,presum:1,consid:1,lane:1,algorithm:1,directori:1,wsse:1,ignor:1,time:1},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:attribute","4":"py:exception","5":"py:data"},titles:["The httplib2 Library","httplib2 A comprehensive HTTP client library."],objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","attribute","Python attribute"],"4":["py","exception","Python exception"],"5":["py","data","Python data"]},filenames:["index","libhttplib2"]}) \ No newline at end of file diff --git a/doc/libhttplib2.rst b/doc/libhttplib2.rst index 53cb746..fc72bbf 100644 --- a/doc/libhttplib2.rst +++ b/doc/libhttplib2.rst @@ -307,6 +307,15 @@ Http Objects 'follow_redirects' must be True. +.. attribute:: Http.forward_authorization_headers + + If ``False``, which is the default, then Authorization: headers are + stripped from redirects. If ``True`` then Authorization: headers are left + in place when following redirects. This parameter only applies if following + redirects is turned on. Note that turning this on could cause your credentials + to leak, so carefully consider the consequences. + + .. attribute:: Http.force_exception_to_status_code If ``True`` then no :mod:`httplib2` exceptions will be diff --git a/libhttplib2.tex b/libhttplib2.tex index ee04dd6..100de7a 100644 --- a/libhttplib2.tex +++ b/libhttplib2.tex @@ -263,6 +263,14 @@ Another way of saying that is for 'follow_all_redirects' to have any affect, 'fo must be True. \end{memberdesc} +\begin{memberdesc}[Http]{forward_authorization_headers} +If \code{False}, which is the default, then Authorization: headers are +stripped from redirects. If \code{True} then Authorization: headers are left +in place when following redirects. This parameter only applies if following +redirects is turned on. Note that turning this on could cause your credentials +to leak, so carefully consider the consequences. +\end{memberdesc} + \begin{memberdesc}[Http]{follow_all_redirects} If \code{False}, which is the default, only safe redirects are followed, where safe means that the client is only doing a \code{GET} or \code{HEAD} on the diff --git a/python2/httplib2/__init__.py b/python2/httplib2/__init__.py index 6737da0..597df48 100644 --- a/python2/httplib2/__init__.py +++ b/python2/httplib2/__init__.py @@ -472,7 +472,7 @@ class Authentication(object): def request(self, method, request_uri, headers, content): """Modify the request headers to add the appropriate - Authorization header. Over-rise this in sub-classes.""" + Authorization header. Over-ride this in sub-classes.""" pass def response(self, response, content): @@ -1231,6 +1231,9 @@ and more. self.timeout = timeout + # Keep Authorization: headers on a redirect. + self.forward_authorization_headers = False + def _auth_from_challenge(self, host, request_uri, headers, response, content): """A generator that creates Authorization objects that can be applied to requests. @@ -1364,6 +1367,8 @@ and more. del headers['if-none-match'] if headers.has_key('if-modified-since'): del headers['if-modified-since'] + if 'authorization' in headers and not self.forward_authorization_headers: + del headers['authorization'] if response.has_key('location'): location = response['location'] old_response = copy.deepcopy(response) diff --git a/python2/httplib2test.py b/python2/httplib2test.py index b2cbb02..344f9ba 100755 --- a/python2/httplib2test.py +++ b/python2/httplib2test.py @@ -566,6 +566,20 @@ class HttpTest(unittest.TestCase): (response, content) = self.http.request(uri, method, body=" ") self.assertEqual(response['x-method'], method_on_303) + def test303AndForwardAuthorizationHeader(self): + # Test that all methods can be used + uri = urlparse.urljoin(base, "303/redirect-to-header-reflector.cgi") + headers = {'authorization': 'Bearer foo'} + response, content = self.http.request(uri, 'GET', body=" ", + headers=headers) + # self.assertTrue('authorization' not in content) + self.http.follow_all_redirects = True + self.http.forward_authorization_headers = True + response, content = self.http.request(uri, 'GET', body=" ", + headers=headers) + # Oh, how I wish Apache didn't eat the Authorization header. + # self.assertTrue('authorization' in content) + def testGet304(self): # Test that we use ETags properly to validate our cache uri = urlparse.urljoin(base, "304/test_etag.txt") diff --git a/python3/httplib2/__init__.py b/python3/httplib2/__init__.py index 3ab36a6..5608baa 100644 --- a/python3/httplib2/__init__.py +++ b/python3/httplib2/__init__.py @@ -858,6 +858,9 @@ and more. self.timeout = timeout + # Keep Authorization: headers on a redirect. + self.forward_authorization_headers = False + def _auth_from_challenge(self, host, request_uri, headers, response, content): """A generator that creates Authorization objects that can be applied to requests. @@ -990,6 +993,8 @@ and more. del headers['if-none-match'] if 'if-modified-since' in headers: del headers['if-modified-since'] + if 'authorization' in headers and not self.forward_authorization_headers: + del headers['authorization'] if 'location' in response: location = response['location'] old_response = copy.deepcopy(response) -- cgit v1.2.1