def assert_decode(self, data, cls): # manual decode request, realm, _ = codec.asn1mod.decode_proxymessage(data) self.assertEqual(realm, self.realm) inst = cls.parse_request(realm, request) self.assertIsInstance(inst, cls) self.assertEqual(inst.realm, self.realm) self.assertEqual(inst.request, request) if cls is codec.KPASSWDProxyRequest: self.assertEqual(inst.version, 1) # codec decode outer = codec.decode(data) self.assertEqual(outer.realm, self.realm) self.assertIsInstance(outer, cls) # re-decode der = codec.encode(outer.request) self.assertIsInstance(der, bytes) decoded = codec.decode(der) self.assertIsInstance(decoded, cls) return outer
def assert_decode(self, data, cls): outer = codec.decode(data) self.assertEqual(outer.realm, self.realm) self.assertIsInstance(outer, cls) if cls is not codec.KPASSWDProxyRequest: inner, err = decoder.decode(outer.request[outer.OFFSET :], asn1Spec=outer.TYPE()) if err: # pragma: no cover self.fail(err) self.assertIsInstance(inner, outer.TYPE) der = encoder.encode(inner) encoded = codec.encode(der) self.assertIsInstance(encoded, bytes) return outer
def assert_decode(self, data, cls): outer = codec.decode(data) self.assertEqual(outer.realm, self.realm) self.assertIsInstance(outer, cls) if cls is not codec.KPASSWDProxyRequest: inner, err = decoder.decode(outer.request[outer.OFFSET:], asn1Spec=outer.TYPE()) if err: # pragma: no cover self.fail(err) self.assertIsInstance(inner, outer.TYPE) der = encoder.encode(inner) encoded = codec.encode(der) self.assertIsInstance(encoded, bytes) return outer
def __call__(self, env, start_response): try: # Validate the method method = env["REQUEST_METHOD"].upper() if method != "POST": raise HTTPException(405, "Method not allowed (%s)." % method) # Parse the request length = -1 try: length = int(env["CONTENT_LENGTH"]) except KeyError: pass except ValueError: pass if length < 0: raise HTTPException(411, "Length required.") if length > self.MAX_LENGTH: raise HTTPException(413, "Request entity too large.") try: pr = codec.decode(env["wsgi.input"].read(length)) except codec.ParsingError as e: raise HTTPException(400, e.message) # Find the remote proxy servers = self.__resolver.lookup(pr.realm, kpasswd=isinstance( pr, codec.KPASSWDProxyRequest)) if not servers: raise HTTPException(503, "Can't find remote (%s)." % pr) # Contact the remote server reply = None wsocks = [] rsocks = [] for server in map(urlparse.urlparse, servers): # Enforce valid, supported URIs scheme = server.scheme.lower().split("+", 1) if scheme[0] not in ("kerberos", "kpasswd"): continue if len(scheme) > 1 and scheme[1] not in ("tcp", "udp"): continue # Do the DNS lookup try: port = server.port if port is None: port = scheme[0] addrs = socket.getaddrinfo(server.hostname, port) except socket.gaierror: continue # Sort addresses so that we get TCP first. # # Stick a None address on the end so we can get one # more attempt after all servers have been contacted. addrs = tuple( sorted(filter(self.__filter_addr, addrs), key=lambda a: a[2])) for addr in addrs + (None, ): if addr is not None: # Bypass unspecified socktypes if len(scheme) > 1 and \ addr[1] != self.SOCKTYPES[scheme[1]]: continue # Create the socket sock = socket.socket(*addr[:3]) sock.setblocking(0) # Connect try: # In Python 2.x, non-blocking connect() throws # socket.error() with errno == EINPROGRESS. In # Python 3.x, it throws io.BlockingIOError(). sock.connect(addr[4]) except socket.error as e: if e.errno != 115: # errno != EINPROGRESS sock.close() continue except io.BlockingIOError: pass wsocks.append(sock) # Resend packets to UDP servers for sock in tuple(rsocks): if self.sock_type(sock) == socket.SOCK_DGRAM: wsocks.append(sock) rsocks.remove(sock) # Call select() timeout = time.time() + (15 if addr is None else 2) reply = self.__await_reply(pr, rsocks, wsocks, timeout) if reply is not None: break if reply is not None: break for sock in rsocks + wsocks: sock.close() if reply is None: raise HTTPException(503, "Remote unavailable (%s)." % pr) # Return the result to the client raise HTTPException(200, codec.encode(reply), [("Content-Type", "application/kerberos")]) except HTTPException as e: start_response(str(e), e.headers) return [e.message]
def __call__(self, env, start_response): try: # Validate the method method = env["REQUEST_METHOD"].upper() if method != "POST": raise HTTPException(405, "Method not allowed (%s)." % method) # Parse the request length = -1 try: length = int(env["CONTENT_LENGTH"]) except KeyError: pass except ValueError: pass if length < 0: raise HTTPException(411, "Length required.") if length > self.MAX_LENGTH: raise HTTPException(413, "Request entity too large.") try: pr = codec.decode(env["wsgi.input"].read(length)) except codec.ParsingError as e: raise HTTPException(400, e.message) # Find the remote proxy servers = self.__resolver.lookup( pr.realm, kpasswd=isinstance(pr, codec.KPASSWDProxyRequest) ) if not servers: raise HTTPException(503, "Can't find remote (%s)." % pr) # Contact the remote server reply = None wsocks = [] rsocks = [] for server in map(urlparse.urlparse, servers): # Enforce valid, supported URIs scheme = server.scheme.lower().split("+", 1) if scheme[0] not in ("kerberos", "kpasswd"): continue if len(scheme) > 1 and scheme[1] not in ("tcp", "udp"): continue # Do the DNS lookup try: port = server.port if port is None: port = scheme[0] addrs = socket.getaddrinfo(server.hostname, port) except socket.gaierror: continue # Sort addresses so that we get TCP first. # # Stick a None address on the end so we can get one # more attempt after all servers have been contacted. addrs = tuple(sorted(filter(self.__filter_addr, addrs))) for addr in addrs + (None,): if addr is not None: # Bypass unspecified socktypes if (len(scheme) > 1 and addr[1] != self.SOCKTYPES[scheme[1]]): continue # Create the socket sock = socket.socket(*addr[:3]) sock.setblocking(0) # Connect try: # In Python 2.x, non-blocking connect() throws # socket.error() with errno == EINPROGRESS. In # Python 3.x, it throws io.BlockingIOError(). sock.connect(addr[4]) except socket.error as e: if e.errno != 115: # errno != EINPROGRESS sock.close() continue except io.BlockingIOError: pass wsocks.append(sock) # Resend packets to UDP servers for sock in tuple(rsocks): if self.sock_type(sock) == socket.SOCK_DGRAM: wsocks.append(sock) rsocks.remove(sock) # Call select() timeout = time.time() + (15 if addr is None else 2) reply = self.__await_reply(pr, rsocks, wsocks, timeout) if reply is not None: break if reply is not None: break for sock in rsocks + wsocks: sock.close() if reply is None: raise HTTPException(503, "Remote unavailable (%s)." % pr) # Return the result to the client raise HTTPException(200, codec.encode(reply), [("Content-Type", "application/kerberos")]) except HTTPException as e: start_response(str(e), e.headers) return [e.message]