• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <grpc/support/port_platform.h>
16 
17 #include "src/core/lib/security/authorization/matchers.h"
18 
19 #include "absl/memory/memory.h"
20 #include "absl/strings/str_cat.h"
21 #include "absl/strings/str_format.h"
22 #include "absl/strings/str_join.h"
23 #include "absl/strings/str_split.h"
24 
25 namespace grpc_core {
26 
27 //
28 // StringMatcher
29 //
30 
Create(Type type,const std::string & matcher,bool case_sensitive)31 absl::StatusOr<StringMatcher> StringMatcher::Create(Type type,
32                                                     const std::string& matcher,
33                                                     bool case_sensitive) {
34   if (type == Type::SAFE_REGEX) {
35     RE2::Options options;
36     options.set_case_sensitive(case_sensitive);
37     auto regex_matcher = absl::make_unique<RE2>(matcher, options);
38     if (!regex_matcher->ok()) {
39       return absl::InvalidArgumentError(
40           "Invalid regex string specified in matcher.");
41     }
42     return StringMatcher(std::move(regex_matcher), case_sensitive);
43   } else {
44     return StringMatcher(type, matcher, case_sensitive);
45   }
46 }
47 
StringMatcher(Type type,const std::string & matcher,bool case_sensitive)48 StringMatcher::StringMatcher(Type type, const std::string& matcher,
49                              bool case_sensitive)
50     : type_(type), string_matcher_(matcher), case_sensitive_(case_sensitive) {}
51 
StringMatcher(std::unique_ptr<RE2> regex_matcher,bool case_sensitive)52 StringMatcher::StringMatcher(std::unique_ptr<RE2> regex_matcher,
53                              bool case_sensitive)
54     : type_(Type::SAFE_REGEX),
55       regex_matcher_(std::move(regex_matcher)),
56       case_sensitive_(case_sensitive) {}
57 
StringMatcher(const StringMatcher & other)58 StringMatcher::StringMatcher(const StringMatcher& other)
59     : type_(other.type_), case_sensitive_(other.case_sensitive_) {
60   if (type_ == Type::SAFE_REGEX) {
61     RE2::Options options;
62     options.set_case_sensitive(other.case_sensitive_);
63     regex_matcher_ =
64         absl::make_unique<RE2>(other.regex_matcher_->pattern(), options);
65   } else {
66     string_matcher_ = other.string_matcher_;
67   }
68 }
69 
operator =(const StringMatcher & other)70 StringMatcher& StringMatcher::operator=(const StringMatcher& other) {
71   type_ = other.type_;
72   if (type_ == Type::SAFE_REGEX) {
73     RE2::Options options;
74     options.set_case_sensitive(other.case_sensitive_);
75     regex_matcher_ =
76         absl::make_unique<RE2>(other.regex_matcher_->pattern(), options);
77   } else {
78     string_matcher_ = other.string_matcher_;
79   }
80   case_sensitive_ = other.case_sensitive_;
81   return *this;
82 }
83 
StringMatcher(StringMatcher && other)84 StringMatcher::StringMatcher(StringMatcher&& other) noexcept
85     : type_(other.type_), case_sensitive_(other.case_sensitive_) {
86   if (type_ == Type::SAFE_REGEX) {
87     regex_matcher_ = std::move(other.regex_matcher_);
88   } else {
89     string_matcher_ = std::move(other.string_matcher_);
90   }
91 }
92 
operator =(StringMatcher && other)93 StringMatcher& StringMatcher::operator=(StringMatcher&& other) noexcept {
94   type_ = other.type_;
95   if (type_ == Type::SAFE_REGEX) {
96     regex_matcher_ = std::move(other.regex_matcher_);
97   } else {
98     string_matcher_ = std::move(other.string_matcher_);
99   }
100   case_sensitive_ = other.case_sensitive_;
101   return *this;
102 }
103 
operator ==(const StringMatcher & other) const104 bool StringMatcher::operator==(const StringMatcher& other) const {
105   if (type_ != other.type_ || case_sensitive_ != other.case_sensitive_) {
106     return false;
107   }
108   if (type_ == Type::SAFE_REGEX) {
109     return regex_matcher_->pattern() == other.regex_matcher_->pattern();
110   } else {
111     return string_matcher_ == other.string_matcher_;
112   }
113 }
114 
Match(absl::string_view value) const115 bool StringMatcher::Match(absl::string_view value) const {
116   switch (type_) {
117     case Type::EXACT:
118       return case_sensitive_ ? value == string_matcher_
119                              : absl::EqualsIgnoreCase(value, string_matcher_);
120     case StringMatcher::Type::PREFIX:
121       return case_sensitive_
122                  ? absl::StartsWith(value, string_matcher_)
123                  : absl::StartsWithIgnoreCase(value, string_matcher_);
124     case StringMatcher::Type::SUFFIX:
125       return case_sensitive_ ? absl::EndsWith(value, string_matcher_)
126                              : absl::EndsWithIgnoreCase(value, string_matcher_);
127     case StringMatcher::Type::CONTAINS:
128       return case_sensitive_
129                  ? absl::StrContains(value, string_matcher_)
130                  : absl::StrContains(absl::AsciiStrToLower(value),
131                                      absl::AsciiStrToLower(string_matcher_));
132     case StringMatcher::Type::SAFE_REGEX:
133       return RE2::FullMatch(std::string(value), *regex_matcher_);
134     default:
135       return false;
136   }
137 }
138 
ToString() const139 std::string StringMatcher::ToString() const {
140   switch (type_) {
141     case Type::EXACT:
142       return absl::StrFormat("StringMatcher{exact=%s%s}", string_matcher_,
143                              case_sensitive_ ? "" : ", case_sensitive=false");
144     case Type::PREFIX:
145       return absl::StrFormat("StringMatcher{prefix=%s%s}", string_matcher_,
146                              case_sensitive_ ? "" : ", case_sensitive=false");
147     case Type::SUFFIX:
148       return absl::StrFormat("StringMatcher{suffix=%s%s}", string_matcher_,
149                              case_sensitive_ ? "" : ", case_sensitive=false");
150     case Type::CONTAINS:
151       return absl::StrFormat("StringMatcher{contains=%s%s}", string_matcher_,
152                              case_sensitive_ ? "" : ", case_sensitive=false");
153     case Type::SAFE_REGEX:
154       return absl::StrFormat("StringMatcher{safe_regex=%s%s}",
155                              regex_matcher_->pattern(),
156                              case_sensitive_ ? "" : ", case_sensitive=false");
157     default:
158       return "";
159   }
160 }
161 
162 //
163 // HeaderMatcher
164 //
165 
Create(const std::string & name,Type type,const std::string & matcher,int64_t range_start,int64_t range_end,bool present_match,bool invert_match)166 absl::StatusOr<HeaderMatcher> HeaderMatcher::Create(
167     const std::string& name, Type type, const std::string& matcher,
168     int64_t range_start, int64_t range_end, bool present_match,
169     bool invert_match) {
170   if (static_cast<int>(type) < 5) {
171     // Only for EXACT, PREFIX, SUFFIX, SAFE_REGEX and CONTAINS.
172     absl::StatusOr<StringMatcher> string_matcher =
173         StringMatcher::Create(static_cast<StringMatcher::Type>(type), matcher,
174                               /*case_sensitive=*/true);
175     if (!string_matcher.ok()) {
176       return string_matcher.status();
177     }
178     return HeaderMatcher(name, type, std::move(string_matcher.value()),
179                          invert_match);
180   } else if (type == Type::RANGE) {
181     if (range_start > range_end) {
182       return absl::InvalidArgumentError(
183           "Invalid range specifier specified: end cannot be smaller than "
184           "start.");
185     }
186     return HeaderMatcher(name, range_start, range_end, invert_match);
187   } else {
188     return HeaderMatcher(name, present_match, invert_match);
189   }
190 }
191 
HeaderMatcher(const std::string & name,Type type,StringMatcher string_matcher,bool invert_match)192 HeaderMatcher::HeaderMatcher(const std::string& name, Type type,
193                              StringMatcher string_matcher, bool invert_match)
194     : name_(name),
195       type_(type),
196       matcher_(std::move(string_matcher)),
197       invert_match_(invert_match) {}
198 
HeaderMatcher(const std::string & name,int64_t range_start,int64_t range_end,bool invert_match)199 HeaderMatcher::HeaderMatcher(const std::string& name, int64_t range_start,
200                              int64_t range_end, bool invert_match)
201     : name_(name),
202       type_(Type::RANGE),
203       range_start_(range_start),
204       range_end_(range_end),
205       invert_match_(invert_match) {}
206 
HeaderMatcher(const std::string & name,bool present_match,bool invert_match)207 HeaderMatcher::HeaderMatcher(const std::string& name, bool present_match,
208                              bool invert_match)
209     : name_(name),
210       type_(Type::PRESENT),
211       present_match_(present_match),
212       invert_match_(invert_match) {}
213 
HeaderMatcher(const HeaderMatcher & other)214 HeaderMatcher::HeaderMatcher(const HeaderMatcher& other)
215     : name_(other.name_),
216       type_(other.type_),
217       invert_match_(other.invert_match_) {
218   switch (type_) {
219     case Type::RANGE:
220       range_start_ = other.range_start_;
221       range_end_ = other.range_end_;
222       break;
223     case Type::PRESENT:
224       present_match_ = other.present_match_;
225       break;
226     default:
227       matcher_ = other.matcher_;
228   }
229 }
230 
operator =(const HeaderMatcher & other)231 HeaderMatcher& HeaderMatcher::operator=(const HeaderMatcher& other) {
232   name_ = other.name_;
233   type_ = other.type_;
234   invert_match_ = other.invert_match_;
235   switch (type_) {
236     case Type::RANGE:
237       range_start_ = other.range_start_;
238       range_end_ = other.range_end_;
239       break;
240     case Type::PRESENT:
241       present_match_ = other.present_match_;
242       break;
243     default:
244       matcher_ = other.matcher_;
245   }
246   return *this;
247 }
248 
HeaderMatcher(HeaderMatcher && other)249 HeaderMatcher::HeaderMatcher(HeaderMatcher&& other) noexcept
250     : name_(std::move(other.name_)),
251       type_(other.type_),
252       invert_match_(other.invert_match_) {
253   switch (type_) {
254     case Type::RANGE:
255       range_start_ = other.range_start_;
256       range_end_ = other.range_end_;
257       break;
258     case Type::PRESENT:
259       present_match_ = other.present_match_;
260       break;
261     default:
262       matcher_ = std::move(other.matcher_);
263   }
264 }
265 
operator =(HeaderMatcher && other)266 HeaderMatcher& HeaderMatcher::operator=(HeaderMatcher&& other) noexcept {
267   name_ = std::move(other.name_);
268   type_ = other.type_;
269   invert_match_ = other.invert_match_;
270   switch (type_) {
271     case Type::RANGE:
272       range_start_ = other.range_start_;
273       range_end_ = other.range_end_;
274       break;
275     case Type::PRESENT:
276       present_match_ = other.present_match_;
277       break;
278     default:
279       matcher_ = std::move(other.matcher_);
280   }
281   return *this;
282 }
283 
operator ==(const HeaderMatcher & other) const284 bool HeaderMatcher::operator==(const HeaderMatcher& other) const {
285   if (name_ != other.name_) return false;
286   if (type_ != other.type_) return false;
287   if (invert_match_ != other.invert_match_) return false;
288   switch (type_) {
289     case Type::RANGE:
290       return range_start_ == other.range_start_ &&
291              range_end_ == other.range_end_;
292     case Type::PRESENT:
293       return present_match_ == other.present_match_;
294     default:
295       return matcher_ == other.matcher_;
296   }
297 }
298 
Match(const absl::optional<absl::string_view> & value) const299 bool HeaderMatcher::Match(
300     const absl::optional<absl::string_view>& value) const {
301   bool match;
302   if (type_ == Type::PRESENT) {
303     match = value.has_value() == present_match_;
304   } else if (!value.has_value()) {
305     // All other types fail to match if field is not present.
306     match = false;
307   } else if (type_ == Type::RANGE) {
308     int64_t int_value;
309     match = absl::SimpleAtoi(value.value(), &int_value) &&
310             int_value >= range_start_ && int_value < range_end_;
311   } else {
312     match = matcher_.Match(value.value());
313   }
314   return match != invert_match_;
315 }
316 
ToString() const317 std::string HeaderMatcher::ToString() const {
318   switch (type_) {
319     case Type::RANGE:
320       return absl::StrFormat("HeaderMatcher{%s %srange=[%d, %d]}", name_,
321                              invert_match_ ? "not " : "", range_start_,
322                              range_end_);
323     case Type::PRESENT:
324       return absl::StrFormat("HeaderMatcher{%s %spresent=%s}", name_,
325                              invert_match_ ? "not " : "",
326                              present_match_ ? "true" : "false");
327     case Type::EXACT:
328     case Type::PREFIX:
329     case Type::SUFFIX:
330     case Type::SAFE_REGEX:
331     case Type::CONTAINS:
332       return absl::StrFormat("HeaderMatcher{%s %s%s}", name_,
333                              invert_match_ ? "not " : "", matcher_.ToString());
334     default:
335       return "";
336   }
337 }
338 
339 }  // namespace grpc_core
340