Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/source/extensions/filters/common/rbac/matchers.h
Line
Count
Source
1
#pragma once
2
3
#include <memory>
4
5
#include "envoy/config/core/v3/address.pb.h"
6
#include "envoy/config/rbac/v3/rbac.pb.h"
7
#include "envoy/config/route/v3/route_components.pb.h"
8
#include "envoy/http/header_map.h"
9
#include "envoy/network/connection.h"
10
#include "envoy/type/matcher/v3/path.pb.h"
11
#include "envoy/type/matcher/v3/string.pb.h"
12
13
#include "source/common/common/matchers.h"
14
#include "source/common/http/header_utility.h"
15
#include "source/common/network/cidr_range.h"
16
#include "source/extensions/filters/common/expr/evaluator.h"
17
18
namespace Envoy {
19
namespace Extensions {
20
namespace Filters {
21
namespace Common {
22
namespace RBAC {
23
24
class Matcher;
25
using MatcherConstSharedPtr = std::shared_ptr<const Matcher>;
26
27
/**
28
 *  Matchers describe the rules for matching either a permission action or principal.
29
 */
30
class Matcher {
31
public:
32
40.9k
  virtual ~Matcher() = default;
33
34
  /**
35
   * Returns whether or not the permission/principal matches the rules of the matcher.
36
   *
37
   * @param connection the downstream connection used to match against.
38
   * @param headers    the request headers used to match against. An empty map should be used if
39
   *                   there are none headers available.
40
   * @param info       the additional information about the action/principal.
41
   */
42
  virtual bool matches(const Network::Connection& connection,
43
                       const Envoy::Http::RequestHeaderMap& headers,
44
                       const StreamInfo::StreamInfo& info) const PURE;
45
46
  /**
47
   * Creates a shared instance of a matcher based off the rules defined in the Permission config
48
   * proto message.
49
   */
50
  static MatcherConstSharedPtr create(const envoy::config::rbac::v3::Permission& permission,
51
                                      ProtobufMessage::ValidationVisitor& validation_visitor);
52
53
  /**
54
   * Creates a shared instance of a matcher based off the rules defined in the Principal config
55
   * proto message.
56
   */
57
  static MatcherConstSharedPtr create(const envoy::config::rbac::v3::Principal& principal);
58
};
59
60
/**
61
 * Always matches, returning true for any input.
62
 */
63
class AlwaysMatcher : public Matcher {
64
public:
65
  bool matches(const Network::Connection&, const Envoy::Http::RequestHeaderMap&,
66
23.0k
               const StreamInfo::StreamInfo&) const override {
67
23.0k
    return true;
68
23.0k
  }
69
};
70
71
/**
72
 * A composite matcher where all sub-matchers must match for this to return true. Evaluation
73
 * short-circuits on the first non-match.
74
 */
75
class AndMatcher : public Matcher {
76
public:
77
  AndMatcher(const envoy::config::rbac::v3::Permission::Set& rules,
78
             ProtobufMessage::ValidationVisitor& validation_visitor);
79
  AndMatcher(const envoy::config::rbac::v3::Principal::Set& ids);
80
81
  bool matches(const Network::Connection& connection, const Envoy::Http::RequestHeaderMap& headers,
82
               const StreamInfo::StreamInfo&) const override;
83
84
private:
85
  std::vector<MatcherConstSharedPtr> matchers_;
86
};
87
88
/**
89
 * A composite matcher where only one sub-matcher must match for this to return true. Evaluation
90
 * short-circuits on the first match.
91
 */
92
class OrMatcher : public Matcher {
93
public:
94
  OrMatcher(const envoy::config::rbac::v3::Permission::Set& set,
95
            ProtobufMessage::ValidationVisitor& validation_visitor)
96
867
      : OrMatcher(set.rules(), validation_visitor) {}
97
1.78k
  OrMatcher(const envoy::config::rbac::v3::Principal::Set& set) : OrMatcher(set.ids()) {}
98
  OrMatcher(const Protobuf::RepeatedPtrField<envoy::config::rbac::v3::Permission>& rules,
99
            ProtobufMessage::ValidationVisitor& validation_visitor);
100
  OrMatcher(const Protobuf::RepeatedPtrField<envoy::config::rbac::v3::Principal>& ids);
101
102
  bool matches(const Network::Connection& connection, const Envoy::Http::RequestHeaderMap& headers,
103
               const StreamInfo::StreamInfo&) const override;
104
105
private:
106
  std::vector<MatcherConstSharedPtr> matchers_;
107
};
108
109
class NotMatcher : public Matcher {
110
public:
111
  NotMatcher(const envoy::config::rbac::v3::Permission& permission,
112
             ProtobufMessage::ValidationVisitor& validation_visitor)
113
851
      : matcher_(Matcher::create(permission, validation_visitor)) {}
114
  NotMatcher(const envoy::config::rbac::v3::Principal& principal)
115
1.59k
      : matcher_(Matcher::create(principal)) {}
116
117
  bool matches(const Network::Connection& connection, const Envoy::Http::RequestHeaderMap& headers,
118
               const StreamInfo::StreamInfo&) const override;
119
120
private:
121
  MatcherConstSharedPtr matcher_;
122
};
123
124
/**
125
 * Perform a match against any HTTP header (or pseudo-header, such as `:path` or `:authority`). Will
126
 * always fail to match on any non-HTTP connection.
127
 */
128
class HeaderMatcher : public Matcher {
129
public:
130
68
  HeaderMatcher(const envoy::config::route::v3::HeaderMatcher& matcher) : header_(matcher) {}
131
132
  bool matches(const Network::Connection& connection, const Envoy::Http::RequestHeaderMap& headers,
133
               const StreamInfo::StreamInfo&) const override;
134
135
private:
136
  const Envoy::Http::HeaderUtility::HeaderData header_;
137
};
138
139
/**
140
 * Perform a match against an IP CIDR range. This rule can be applied to connection remote,
141
 * downstream local address, downstream direct remote address or downstream remote address.
142
 */
143
class IPMatcher : public Matcher {
144
public:
145
  enum Type { ConnectionRemote = 0, DownstreamLocal, DownstreamDirectRemote, DownstreamRemote };
146
147
  IPMatcher(const envoy::config::core::v3::CidrRange& range, Type type)
148
1.29k
      : range_(Network::Address::CidrRange::create(range)), type_(type) {}
149
150
  bool matches(const Network::Connection& connection, const Envoy::Http::RequestHeaderMap& headers,
151
               const StreamInfo::StreamInfo& info) const override;
152
153
private:
154
  const Network::Address::CidrRange range_;
155
  const Type type_;
156
};
157
158
/**
159
 * Matches the port number of the destination (local) address.
160
 */
161
class PortMatcher : public Matcher {
162
public:
163
5.51k
  PortMatcher(const uint32_t port) : port_(port) {}
164
165
  bool matches(const Network::Connection&, const Envoy::Http::RequestHeaderMap&,
166
               const StreamInfo::StreamInfo& info) const override;
167
168
private:
169
  const uint32_t port_;
170
};
171
172
class PortRangeMatcher : public Matcher {
173
public:
174
  PortRangeMatcher(const ::envoy::type::v3::Int32Range& range);
175
176
  bool matches(const Network::Connection&, const Envoy::Http::RequestHeaderMap&,
177
               const StreamInfo::StreamInfo& info) const override;
178
179
private:
180
  const uint32_t start_;
181
  const uint32_t end_;
182
};
183
184
/**
185
 * Matches the principal name as described in the peer certificate. Uses the URI SAN first. If that
186
 * field is not present, uses the subject instead.
187
 */
188
class AuthenticatedMatcher : public Matcher {
189
public:
190
  AuthenticatedMatcher(const envoy::config::rbac::v3::Principal::Authenticated& auth)
191
      : matcher_(auth.has_principal_name()
192
                     ? absl::make_optional<
193
                           Matchers::StringMatcherImpl<envoy::type::matcher::v3::StringMatcher>>(
194
                           auth.principal_name())
195
4.16k
                     : absl::nullopt) {}
196
197
  bool matches(const Network::Connection& connection, const Envoy::Http::RequestHeaderMap& headers,
198
               const StreamInfo::StreamInfo&) const override;
199
200
private:
201
  const absl::optional<Matchers::StringMatcherImpl<envoy::type::matcher::v3::StringMatcher>>
202
      matcher_;
203
};
204
205
/**
206
 * Matches a Policy which is a collection of permission and principal matchers. If any action
207
 * matches a permission, the principals are then checked for a match.
208
 * The condition is a conjunction clause.
209
 */
210
class PolicyMatcher : public Matcher, NonCopyable {
211
public:
212
  PolicyMatcher(const envoy::config::rbac::v3::Policy& policy, Expr::Builder* builder,
213
                ProtobufMessage::ValidationVisitor& validation_visitor)
214
      : permissions_(policy.permissions(), validation_visitor), principals_(policy.principals()),
215
4.72k
        condition_(policy.condition()) {
216
4.72k
    if (policy.has_condition()) {
217
4.19k
      expr_ = Expr::createExpression(*builder, condition_);
218
4.19k
    }
219
4.72k
  }
220
221
  bool matches(const Network::Connection& connection, const Envoy::Http::RequestHeaderMap& headers,
222
               const StreamInfo::StreamInfo&) const override;
223
224
private:
225
  const OrMatcher permissions_;
226
  const OrMatcher principals_;
227
  const google::api::expr::v1alpha1::Expr condition_;
228
  Expr::ExpressionPtr expr_;
229
};
230
231
class MetadataMatcher : public Matcher {
232
public:
233
415
  MetadataMatcher(const Envoy::Matchers::MetadataMatcher& matcher) : matcher_(matcher) {}
234
235
  bool matches(const Network::Connection& connection, const Envoy::Http::RequestHeaderMap& headers,
236
               const StreamInfo::StreamInfo& info) const override;
237
238
private:
239
  const Envoy::Matchers::MetadataMatcher matcher_;
240
};
241
242
class FilterStateMatcher : public Matcher {
243
public:
244
  FilterStateMatcher(const envoy::type::matcher::v3::FilterStateMatcher& matcher)
245
17
      : matcher_(matcher) {}
246
247
  bool matches(const Network::Connection&, const Envoy::Http::RequestHeaderMap&,
248
               const StreamInfo::StreamInfo& info) const override;
249
250
private:
251
  const Envoy::Matchers::FilterStateMatcher matcher_;
252
};
253
254
/**
255
 * Perform a match against the request server from the client's connection
256
 * request. This is typically TLS SNI.
257
 */
258
class RequestedServerNameMatcher
259
    : public Matcher,
260
      Envoy::Matchers::StringMatcherImpl<envoy::type::matcher::v3::StringMatcher> {
261
public:
262
  RequestedServerNameMatcher(const envoy::type::matcher::v3::StringMatcher& requested_server_name)
263
      : Envoy::Matchers::StringMatcherImpl<envoy::type::matcher::v3::StringMatcher>(
264
889
            requested_server_name) {}
265
266
  bool matches(const Network::Connection& connection, const Envoy::Http::RequestHeaderMap& headers,
267
               const StreamInfo::StreamInfo&) const override;
268
};
269
270
/**
271
 * Perform a match against the path header on the HTTP request. The query and fragment string are
272
 * removed from the path header before matching.
273
 */
274
class PathMatcher : public Matcher {
275
public:
276
  PathMatcher(const envoy::type::matcher::v3::PathMatcher& path_matcher)
277
255
      : path_matcher_(path_matcher) {}
278
279
  bool matches(const Network::Connection& connection, const Envoy::Http::RequestHeaderMap& headers,
280
               const StreamInfo::StreamInfo&) const override;
281
282
private:
283
  const Matchers::PathMatcher path_matcher_;
284
};
285
286
} // namespace RBAC
287
} // namespace Common
288
} // namespace Filters
289
} // namespace Extensions
290
} // namespace Envoy