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