Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/source/extensions/filters/common/ext_authz/ext_authz_grpc_impl.cc
Line
Count
Source (jump to first uncovered line)
1
#include "source/extensions/filters/common/ext_authz/ext_authz_grpc_impl.h"
2
3
#include "envoy/config/core/v3/base.pb.h"
4
#include "envoy/service/auth/v3/external_auth.pb.h"
5
6
#include "source/common/common/assert.h"
7
#include "source/common/grpc/async_client_impl.h"
8
#include "source/common/http/headers.h"
9
#include "source/common/http/utility.h"
10
#include "source/common/network/utility.h"
11
#include "source/common/protobuf/protobuf.h"
12
13
namespace Envoy {
14
namespace Extensions {
15
namespace Filters {
16
namespace Common {
17
namespace ExtAuthz {
18
19
GrpcClientImpl::GrpcClientImpl(const Grpc::RawAsyncClientSharedPtr& async_client,
20
                               const absl::optional<std::chrono::milliseconds>& timeout)
21
    : async_client_(async_client), timeout_(timeout),
22
      service_method_(*Protobuf::DescriptorPool::generated_pool()->FindMethodByName(
23
5
          "envoy.service.auth.v3.Authorization.Check")) {}
24
25
5
GrpcClientImpl::~GrpcClientImpl() { ASSERT(!callbacks_); }
26
27
3
void GrpcClientImpl::cancel() {
28
3
  ASSERT(callbacks_ != nullptr);
29
3
  request_->cancel();
30
3
  callbacks_ = nullptr;
31
3
}
32
33
void GrpcClientImpl::check(RequestCallbacks& callbacks,
34
                           const envoy::service::auth::v3::CheckRequest& request,
35
3
                           Tracing::Span& parent_span, const StreamInfo::StreamInfo& stream_info) {
36
3
  ASSERT(callbacks_ == nullptr);
37
3
  callbacks_ = &callbacks;
38
3
  Http::AsyncClient::RequestOptions options;
39
3
  options.setTimeout(timeout_);
40
3
  options.setParentContext(Http::AsyncClient::ParentContext{&stream_info});
41
42
3
  ENVOY_LOG(trace, "Sending CheckRequest: {}", request.DebugString());
43
3
  request_ = async_client_->send(service_method_, request, *this, parent_span, options);
44
3
}
45
46
void GrpcClientImpl::onSuccess(std::unique_ptr<envoy::service::auth::v3::CheckResponse>&& response,
47
0
                               Tracing::Span& span) {
48
0
  ENVOY_LOG(trace, "Received CheckResponse: {}", response->DebugString());
49
0
  ResponsePtr authz_response = std::make_unique<Response>(Response{});
50
0
  if (response->status().code() == Grpc::Status::WellKnownGrpcStatus::Ok) {
51
0
    span.setTag(TracingConstants::get().TraceStatus, TracingConstants::get().TraceOk);
52
0
    authz_response->status = CheckStatus::OK;
53
0
    if (response->has_ok_response()) {
54
0
      toAuthzResponseHeader(authz_response, response->ok_response().headers());
55
0
      if (response->ok_response().headers_to_remove_size() > 0) {
56
0
        for (const auto& header : response->ok_response().headers_to_remove()) {
57
0
          authz_response->headers_to_remove.push_back(Http::LowerCaseString(header));
58
0
        }
59
0
      }
60
0
      if (response->ok_response().query_parameters_to_set_size() > 0) {
61
0
        for (const auto& query_parameter : response->ok_response().query_parameters_to_set()) {
62
0
          authz_response->query_parameters_to_set.push_back(
63
0
              std::pair(query_parameter.key(), query_parameter.value()));
64
0
        }
65
0
      }
66
0
      if (response->ok_response().query_parameters_to_remove_size() > 0) {
67
0
        for (const auto& key : response->ok_response().query_parameters_to_remove()) {
68
0
          authz_response->query_parameters_to_remove.push_back(key);
69
0
        }
70
0
      }
71
      // These two vectors hold header overrides of encoded response headers.
72
0
      if (response->ok_response().response_headers_to_add_size() > 0) {
73
0
        for (const auto& header : response->ok_response().response_headers_to_add()) {
74
0
          if (header.append().value()) {
75
0
            authz_response->response_headers_to_add.emplace_back(
76
0
                Http::LowerCaseString(header.header().key()), header.header().value());
77
0
          } else {
78
0
            authz_response->response_headers_to_set.emplace_back(
79
0
                Http::LowerCaseString(header.header().key()), header.header().value());
80
0
          }
81
0
        }
82
0
      }
83
0
    }
84
0
  } else {
85
0
    span.setTag(TracingConstants::get().TraceStatus, TracingConstants::get().TraceUnauthz);
86
0
    authz_response->status = CheckStatus::Denied;
87
88
    // The default HTTP status code for denied response is 403 Forbidden.
89
0
    authz_response->status_code = Http::Code::Forbidden;
90
0
    if (response->has_denied_response()) {
91
0
      toAuthzResponseHeader(authz_response, response->denied_response().headers());
92
93
0
      const uint32_t status_code = response->denied_response().status().code();
94
0
      if (status_code > 0) {
95
0
        authz_response->status_code = static_cast<Http::Code>(status_code);
96
0
      }
97
0
      authz_response->body = response->denied_response().body();
98
0
    }
99
0
  }
100
101
  // OkHttpResponse.dynamic_metadata is deprecated. Until OkHttpResponse.dynamic_metadata is
102
  // removed, it overrides dynamic_metadata field of the outer check response.
103
0
  if (response->has_ok_response() && response->ok_response().has_dynamic_metadata()) {
104
0
    authz_response->dynamic_metadata = response->ok_response().dynamic_metadata();
105
0
  } else {
106
0
    authz_response->dynamic_metadata = response->dynamic_metadata();
107
0
  }
108
109
0
  callbacks_->onComplete(std::move(authz_response));
110
0
  callbacks_ = nullptr;
111
0
}
112
113
void GrpcClientImpl::onFailure(Grpc::Status::GrpcStatus status, const std::string&,
114
0
                               Tracing::Span&) {
115
0
  ENVOY_LOG(trace, "CheckRequest call failed with status: {}",
116
0
            Grpc::Utility::grpcStatusToString(status));
117
0
  ASSERT(status != Grpc::Status::WellKnownGrpcStatus::Ok);
118
0
  Response response{};
119
0
  response.status = CheckStatus::Error;
120
0
  response.status_code = Http::Code::Forbidden;
121
0
  callbacks_->onComplete(std::make_unique<Response>(response));
122
0
  callbacks_ = nullptr;
123
0
}
124
125
void GrpcClientImpl::toAuthzResponseHeader(
126
    ResponsePtr& response,
127
0
    const Protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValueOption>& headers) {
128
0
  for (const auto& header : headers) {
129
0
    if (header.append().value()) {
130
0
      response->headers_to_append.emplace_back(Http::LowerCaseString(header.header().key()),
131
0
                                               header.header().value());
132
0
    } else {
133
0
      response->headers_to_set.emplace_back(Http::LowerCaseString(header.header().key()),
134
0
                                            header.header().value());
135
0
    }
136
0
  }
137
0
}
138
139
} // namespace ExtAuthz
140
} // namespace Common
141
} // namespace Filters
142
} // namespace Extensions
143
} // namespace Envoy