Package restkit :: Module filters
[hide private]
[frames] | no frames]

Source Code for Module restkit.filters

  1  # -*- coding: utf-8 - 
  2  # 
  3  # This file is part of restkit released under the MIT license.  
  4  # See the NOTICE for more information. 
  5   
  6  import base64 
  7  import os 
  8  import re 
  9  import urlparse 
 10  try: 
 11      from urlparse import parse_qsl 
 12  except ImportError: 
 13      from cgi import parse_qsl 
 14  from urlparse import urlunparse 
 15   
 16  from . import __version__  
 17  from .errors import ProxyError 
 18  from .http import Request, Unreader 
 19  from .oauth2 import Consumer, Request, SignatureMethod_HMAC_SHA1,\ 
 20  Token 
 21  from .sock import send 
 22  from .util import parse_netloc 
 23   
 24   
25 -class Filters(object):
26
27 - def __init__(self, filters=None):
28 self.filters = filters or []
29
30 - def add(self, obj):
31 if not hasattr(obj, "on_request") and not hasattr(obj, "on_response"): 32 raise TypeError("%s is not a filter object." % obj.__class__.__name__) 33 34 self.filters.append(obj)
35
36 - def remove(self, obj):
37 for i, f in enumerate(self.filters): 38 if obj == f: del self.filters[i]
39
40 - def apply(self, kind, *args):
41 for f in self.filters: 42 try: 43 func = getattr(f, kind) 44 except AttributeError: 45 continue 46 func(*args)
47
48 -class BasicAuth(object):
49 """ Simple filter to manage basic authentification""" 50
51 - def __init__(self, username, password):
52 self.credentials = (username, password)
53
54 - def on_request(self, client):
55 encode = base64.b64encode("%s:%s" % self.credentials) 56 client.headers['Authorization'] = 'Basic %s' % encode
57 58 59
60 -class SimpleProxy(object):
61 """ Simple proxy filter. 62 This filter find proxy from environment and if it exists it 63 connect to the proxy and modify connection headers. 64 """ 65
66 - def on_connect(self, client, sck, ssl):
67 proxy = os.environ.get('https_proxy') 68 if proxy: 69 proxy_uri = urlparse.urlparse(proxy) 70 proxy_auth = _get_proxy_auth() 71 if proxy_auth: 72 proxy_auth = 'Proxy-authorization: %s' % proxy_auth 73 proxy_connect = 'CONNECT %s:%s HTTP/1.0\r\n' % parse_netloc(proxy_uri) 74 75 user_agent = "User-Agent: restkit/%s\r\n" % __version__ 76 proxy_pieces = '%s%s%s\r\n' % (proxy_connect, proxy_auth, 77 user_agent) 78 79 send(sck, proxy_pieces) 80 unreader = http.Unreader(sck) 81 resp = http.Request(unreader) 82 body = resp.body.read() 83 if resp.status_int != 200: 84 raise ProxyError("Tunnel connection failed: %d %s" % 85 (resp.status_int, body))
86 87
88 -def _get_proxy_auth():
89 proxy_username = os.environ.get('proxy-username') 90 if not proxy_username: 91 proxy_username = os.environ.get('proxy_username') 92 proxy_password = os.environ.get('proxy-password') 93 if not proxy_password: 94 proxy_password = os.environ.get('proxy_password') 95 if proxy_username: 96 user_auth = base64.encodestring('%s:%s' % (proxy_username, 97 proxy_password)) 98 return 'Basic %s\r\n' % (user_auth.strip()) 99 else: 100 return ''
101
102 -def validate_consumer(consumer):
103 """ validate a consumer agains oauth2.Consumer object """ 104 if not hasattr(consumer, "key"): 105 raise ValueError("Invalid consumer.") 106 return consumer
107
108 -def validate_token(token):
109 """ validate a token agains oauth2.Token object """ 110 if token is not None and not hasattr(token, "key"): 111 raise ValueError("Invalid token.") 112 return token
113 114
115 -class OAuthFilter(object):
116 """ oauth filter """ 117
118 - def __init__(self, path, consumer, token=None, method=None):
119 """ Init OAuthFilter 120 121 :param path: path or regexp. * mean all path on wicth oauth can be 122 applied. 123 :param consumer: oauth consumer, instance of oauth2.Consumer 124 :param token: oauth token, instance of oauth2.Token 125 :param method: oauth signature method 126 127 token and method signature are optionnals. Consumer should be an 128 instance of `oauth2.Consumer`, token an instance of `oauth2.Toke` 129 signature method an instance of `oauth2.SignatureMethod`. 130 131 """ 132 133 if path.endswith('*'): 134 self.match = re.compile("%s.*" % path.rsplit('*', 1)[0]) 135 else: 136 self.match = re.compile("%s$" % path) 137 self.consumer = validate_consumer(consumer) 138 self.token = validate_token(token) 139 self.method = method or SignatureMethod_HMAC_SHA1()
140
141 - def on_path(self, client):
142 path = client.parsed_url.path or "/" 143 return (self.match.match(path) is not None)
144
145 - def on_request(self, client):
146 if not self.on_path(client): 147 return 148 149 params = {} 150 form = False 151 parsed_url = client.parsed_url 152 153 if client.body and client.body is not None: 154 ctype = client.headers.iget('content-ype') 155 if ctype is not None and \ 156 ctype.startswith('application/x-www-form-urlencoded'): 157 # we are in a form try to get oauth params from here 158 form = True 159 params = dict(parse_qsl(client.body)) 160 161 # update params from quey parameters 162 params.update(parse_qsl(parsed_url.query)) 163 164 raw_url = urlunparse((parsed_url.scheme, parsed_url.netloc, 165 parsed_url.path, '', '', '')) 166 167 oauth_req = Request.from_consumer_and_token(self.consumer, 168 token=self.token, http_method=client.method, 169 http_url=raw_url, parameters=params) 170 171 oauth_req.sign_request(self.method, self.consumer, self.token) 172 173 if form: 174 client.body = oauth_req.to_postdata() 175 client.headers['Content-Length'] = len(client.body) 176 elif client.method in ('GET', 'HEAD'): 177 client.original_url = client.url 178 client.url = oauth_req.to_url() 179 else: 180 oauth_headers = oauth_req.to_header() 181 client.headers.update(oauth_headers)
182