def match_filter( proxy_mode: ProxyMode, phase: Phase, flow: HTTPFlow, fltr: RuleEntry, ) -> bool: if fltr.phase != phase.value: # TODO: Should we emit filter audit logs when phases do not match? return False evaluated = [] for rule in fltr.expression_snapshot['rules']: expression = rule['expression'] expected_value = expression['values'][0].lower() extracted_value = extract_value(flow, expression['field']).lower() evaluated.append(extracted_value is not None and expected_value == extracted_value) condition = fltr.expression_snapshot['condition'] matched = all(evaluated) if condition == 'AND' else any(evaluated) audit_logs.emit( audit_logs.records.FilterEvaluationLogRecord( flow_id=flow.id, matched=matched, phase=phase, proxy_mode=proxy_mode, route_id=fltr.route_id, filter_id=fltr.id, )) return matched
def match_route( proxy_mode: ProxyMode, phase: Phase, flow: HTTPFlow, ) -> Tuple[Optional[Route], List[RuleEntry]]: request = flow.request is_outbound = proxy_mode == ProxyMode.FORWARD routes = route_manager.get_all_by_type(is_outbound) for route in routes: if is_outbound and not match_host(request.host, route.host_endpoint): continue match_filters = partial(match_filter, proxy_mode, phase, flow) filters = list(filter(match_filters, route.rule_entries_list)) matched = bool(filters) audit_logs.emit( audit_logs.records.RouteEvaluationLogRecord( flow_id=flow.id, matched=matched, phase=phase, proxy_mode=proxy_mode, route_id=route.id, )) if matched: return route, filters return None, []
def match_route( proxy_mode: ProxyMode, phase: Phase, flow: HTTPFlow, ) -> Tuple[Optional[Route], List[RuleEntry]]: request = flow.request route_type = RouteType.INBOUND if proxy_mode == ProxyMode.REVERSE else RouteType.OUTBOUND routes = route_manager.get_all_by_type(route_type) request_host = request.host.replace('/', '').replace('.', '\\.') if proxy_mode == ProxyMode.FORWARD: routes = [ route for route in routes if route.host_endpoint == request_host ] for route in routes: match_filters = partial(match_filter, proxy_mode, phase, flow) filters = list(filter(match_filters, route.rule_entries_list)) matched = bool(filters) audit_logs.emit( audit_logs.records.RouteEvaluationLogRecord( flow_id=flow.id, matched=matched, phase=phase, proxy_mode=proxy_mode, route_id=route.id, )) if matched: return route, filters return None, []
def test_pubsub(): records = [] record = AuditLogTestRecord( flow_id='flow-id', proxy_mode=ProxyMode.REVERSE, ) subscribe(lambda record: records.append(record)) emit(record) assert records == [record]
def request(self, flow: HTTPFlow): try: audit_logs.emit( audit_logs.records.VaultRequestAuditLogRecord( flow_id=flow.id, proxy_mode=ctx.get_proxy_context().mode, method=flow.request.method, uri=flow.request.url, )) flow.request_raw = flow.request.copy() self._process(flow, Phase.REQUEST) except (RedactFailed, RevealFailed) as exc: logger.error(exc) except Exception as exc: logger.exception(exc)
def match_filter( proxy_mode: ProxyMode, phase: Phase, flow: HTTPFlow, fltr: RuleEntry, ) -> bool: if fltr.phase != phase: # TODO: Should we emit filter audit logs when phases do not match? return False expr = CompositeExpression.build(fltr.expression_snapshot) matched = expr.evaluate(flow) audit_logs.emit(audit_logs.records.FilterEvaluationLogRecord( flow_id=flow.id, matched=matched, phase=phase, proxy_mode=proxy_mode, route_id=fltr.route_id, filter_id=fltr.id, )) return matched
def response(self, flow: HTTPFlow): try: proxy_context = ctx.get_proxy_context() for sock, label in [ (flow.server_conn.wfile, audit_logs.records.TrafficLabel.TO_SERVER), (flow.server_conn.rfile, audit_logs.records.TrafficLabel.FROM_SERVER), ]: if sock and sock.is_logging(): # TODO: (SAT-98) trigger TO_SERVER-event at the right time. audit_logs.emit( audit_logs.records.VaultTrafficLogRecord( flow_id=flow.id, proxy_mode=proxy_context.mode, bytes=len(sock.get_log()), label=label, )) sock.stop_log() audit_logs.emit( audit_logs.records.UpstreamResponseLogRecord( flow_id=flow.id, proxy_mode=proxy_context.mode, upstream=flow.request.host, status_code=flow.response.status_code, )) flow.response_raw = flow.response.copy() self._process(flow, Phase.RESPONSE) except (RedactFailed, RevealFailed) as exc: logger.error(exc) except Exception as exc: logger.exception(exc)