]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2012 Inktank | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | ||
15 | #include <iostream> | |
16 | ||
17 | #include "include/stringify.h" | |
18 | #include "mon/MonCap.h" | |
19 | ||
20 | #include "gtest/gtest.h" | |
21 | ||
20effc67 TL |
22 | using namespace std; |
23 | ||
7c673cae FG |
24 | const char *parse_good[] = { |
25 | ||
26 | // MonCapMatch | |
27 | "allow *", | |
28 | "allow r", | |
29 | "allow rwx", | |
30 | "allow r", | |
31 | " allow rwx", | |
32 | "allow rwx ", | |
33 | " allow rwx ", | |
34 | " allow\t rwx ", | |
35 | "\tallow\nrwx\t", | |
36 | "allow service=foo x", | |
37 | "allow service=\"froo\" x", | |
38 | "allow profile osd", | |
39 | "allow profile osd-bootstrap", | |
40 | "allow profile \"mds-bootstrap\", allow *", | |
41 | "allow command \"a b c\"", | |
42 | "allow command abc", | |
43 | "allow command abc with arg=foo", | |
44 | "allow command abc with arg=foo arg2=bar", | |
45 | "allow command abc with arg=foo arg2=bar", | |
46 | "allow command abc with arg=foo arg2 prefix bar arg3 prefix baz", | |
47 | "allow command abc with arg=foo arg2 prefix \"bar bingo\" arg3 prefix baz", | |
c07f9fc5 FG |
48 | "allow command abc with arg regex \"^[0-9a-z.]*$\"", |
49 | "allow command abc with arg regex \"\(invaluid regex\"", | |
7c673cae FG |
50 | "allow service foo x", |
51 | "allow service foo x; allow service bar x", | |
52 | "allow service foo w ;allow service bar x", | |
53 | "allow service foo w , allow service bar x", | |
54 | "allow service foo r , allow service bar x", | |
55 | "allow service foo_foo r, allow service bar r", | |
56 | "allow service foo-foo r, allow service bar r", | |
57 | "allow service \" foo \" w, allow service bar r", | |
58 | "allow command abc with arg=foo arg2=bar, allow service foo r", | |
59 | "allow command abc.def with arg=foo arg2=bar, allow service foo r", | |
60 | "allow command \"foo bar\" with arg=\"baz\"", | |
61 | "allow command \"foo bar\" with arg=\"baz.xx\"", | |
c07f9fc5 FG |
62 | "profile osd", |
63 | "profile \"mds-bootstrap\", profile foo", | |
11fdf7f2 TL |
64 | "allow * network 1.2.3.4/24", |
65 | "allow * network ::1/128", | |
66 | "allow * network [aa:bb::1]/128", | |
67 | "allow service=foo x network 1.2.3.4/16", | |
68 | "allow command abc network 1.2.3.4/8", | |
69 | "profile osd network 1.2.3.4/32", | |
70 | "allow profile mon network 1.2.3.4/32", | |
7c673cae FG |
71 | 0 |
72 | }; | |
73 | ||
74 | TEST(MonCap, ParseGood) { | |
75 | for (int i=0; parse_good[i]; ++i) { | |
76 | string str = parse_good[i]; | |
77 | MonCap cap; | |
78 | std::cout << "Testing good input: '" << str << "'" << std::endl; | |
79 | ASSERT_TRUE(cap.parse(str, &cout)); | |
80 | std::cout << " -> " << cap << std::endl; | |
81 | } | |
82 | } | |
83 | ||
84 | // these should stringify to the input value | |
85 | const char *parse_identity[] = { | |
86 | "allow *", | |
87 | "allow r", | |
88 | "allow rwx", | |
89 | "allow service foo x", | |
90 | "allow profile osd", | |
91 | "allow profile osd-bootstrap", | |
92 | "allow profile mds-bootstrap, allow *", | |
93 | "allow profile \"foo bar\", allow *", | |
94 | "allow command abc", | |
95 | "allow command \"a b c\"", | |
96 | "allow command abc with arg=foo", | |
97 | "allow command abc with arg=foo arg2=bar", | |
98 | "allow command abc with arg=foo arg2=bar", | |
99 | "allow command abc with arg=foo arg2 prefix bar arg3 prefix baz", | |
100 | "allow command abc with arg=foo arg2 prefix \"bar bingo\" arg3 prefix baz", | |
101 | "allow service foo x", | |
102 | "allow service foo x, allow service bar x", | |
103 | "allow service foo w, allow service bar x", | |
104 | "allow service foo r, allow service bar x", | |
105 | "allow service foo_foo r, allow service bar r", | |
106 | "allow service foo-foo r, allow service bar r", | |
107 | "allow service \" foo \" w, allow service bar r", | |
108 | "allow command abc with arg=foo arg2=bar, allow service foo r", | |
109 | 0 | |
110 | }; | |
111 | ||
112 | TEST(MonCap, ParseIdentity) | |
113 | { | |
114 | for (int i=0; parse_identity[i]; ++i) { | |
115 | string str = parse_identity[i]; | |
116 | MonCap cap; | |
117 | std::cout << "Testing good input: '" << str << "'" << std::endl; | |
118 | ASSERT_TRUE(cap.parse(str, &cout)); | |
119 | string out = stringify(cap); | |
120 | ASSERT_EQ(out, str); | |
121 | } | |
122 | } | |
123 | ||
124 | const char *parse_bad[] = { | |
125 | "allow r foo", | |
126 | "allow*", | |
127 | "foo allow *", | |
128 | "allow profile foo rwx", | |
129 | "allow profile", | |
130 | "allow profile foo bar rwx", | |
131 | "allow service bar", | |
132 | "allow command baz x", | |
133 | "allow r w", | |
134 | "ALLOW r", | |
135 | "allow rwx,", | |
136 | "allow rwx x", | |
137 | "allow r pool foo r", | |
138 | "allow wwx pool taco", | |
139 | "allow wwx pool taco^funny&chars", | |
140 | "allow rwx pool 'weird name''", | |
141 | "allow rwx object_prefix \"beforepool\" pool weird", | |
142 | "allow rwx auid 123 pool asdf", | |
143 | "allow command foo a prefix b", | |
144 | "allow command foo with a prefixb", | |
145 | "allow command foo with a = prefix b", | |
146 | "allow command foo with a prefix b c", | |
147 | 0 | |
148 | }; | |
149 | ||
150 | TEST(MonCap, ParseBad) { | |
151 | for (int i=0; parse_bad[i]; ++i) { | |
152 | string str = parse_bad[i]; | |
153 | MonCap cap; | |
154 | std::cout << "Testing bad input: '" << str << "'" << std::endl; | |
155 | ASSERT_FALSE(cap.parse(str, &cout)); | |
156 | } | |
157 | } | |
158 | ||
159 | TEST(MonCap, AllowAll) { | |
160 | MonCap cap; | |
161 | ASSERT_FALSE(cap.is_allow_all()); | |
162 | ||
163 | ASSERT_TRUE(cap.parse("allow r", NULL)); | |
164 | ASSERT_FALSE(cap.is_allow_all()); | |
165 | cap.grants.clear(); | |
166 | ||
167 | ASSERT_TRUE(cap.parse("allow w", NULL)); | |
168 | ASSERT_FALSE(cap.is_allow_all()); | |
169 | cap.grants.clear(); | |
170 | ||
171 | ASSERT_TRUE(cap.parse("allow x", NULL)); | |
172 | ASSERT_FALSE(cap.is_allow_all()); | |
173 | cap.grants.clear(); | |
174 | ||
175 | ASSERT_TRUE(cap.parse("allow rwx", NULL)); | |
176 | ASSERT_FALSE(cap.is_allow_all()); | |
177 | cap.grants.clear(); | |
178 | ||
179 | ASSERT_TRUE(cap.parse("allow rw", NULL)); | |
180 | ASSERT_FALSE(cap.is_allow_all()); | |
181 | cap.grants.clear(); | |
182 | ||
183 | ASSERT_TRUE(cap.parse("allow rx", NULL)); | |
184 | ASSERT_FALSE(cap.is_allow_all()); | |
185 | cap.grants.clear(); | |
186 | ||
187 | ASSERT_TRUE(cap.parse("allow wx", NULL)); | |
188 | ASSERT_FALSE(cap.is_allow_all()); | |
189 | cap.grants.clear(); | |
190 | ||
191 | ASSERT_TRUE(cap.parse("allow *", NULL)); | |
192 | ASSERT_TRUE(cap.is_allow_all()); | |
92f5a8d4 TL |
193 | ASSERT_TRUE(cap.is_capable(NULL, {}, "foo", "asdf", {}, true, true, true, |
194 | {})); | |
7c673cae FG |
195 | |
196 | MonCap cap2; | |
197 | ASSERT_FALSE(cap2.is_allow_all()); | |
198 | cap2.set_allow_all(); | |
199 | ASSERT_TRUE(cap2.is_allow_all()); | |
200 | } | |
201 | ||
11fdf7f2 TL |
202 | TEST(MonCap, Network) { |
203 | MonCap cap; | |
204 | bool r = cap.parse("allow * network 192.168.0.0/16, allow * network 10.0.0.0/8", NULL); | |
205 | ASSERT_TRUE(r); | |
206 | ||
207 | entity_addr_t a, b, c; | |
208 | a.parse("10.1.2.3"); | |
209 | b.parse("192.168.2.3"); | |
210 | c.parse("192.167.2.3"); | |
211 | ||
92f5a8d4 | 212 | ASSERT_TRUE(cap.is_capable(NULL, {}, "foo", "asdf", {}, true, true, true, |
11fdf7f2 | 213 | a)); |
92f5a8d4 | 214 | ASSERT_TRUE(cap.is_capable(NULL, {}, "foo", "asdf", {}, true, true, true, |
11fdf7f2 | 215 | b)); |
92f5a8d4 | 216 | ASSERT_FALSE(cap.is_capable(NULL, {}, "foo", "asdf", {}, true, true, true, |
11fdf7f2 TL |
217 | c)); |
218 | } | |
219 | ||
7c673cae FG |
220 | TEST(MonCap, ProfileOSD) { |
221 | MonCap cap; | |
222 | bool r = cap.parse("allow profile osd", NULL); | |
223 | ASSERT_TRUE(r); | |
224 | ||
225 | EntityName name; | |
226 | name.from_str("osd.123"); | |
227 | map<string,string> ca; | |
228 | ||
92f5a8d4 TL |
229 | ASSERT_TRUE(cap.is_capable(NULL, name, "osd", "", ca, true, false, false, |
230 | {})); | |
231 | ASSERT_TRUE(cap.is_capable(NULL, name, "osd", "", ca, true, true, false, {})); | |
232 | ASSERT_TRUE(cap.is_capable(NULL, name, "osd", "", ca, true, true, true, {})); | |
233 | ASSERT_TRUE(cap.is_capable(NULL, name, "osd", "", ca, true, true, true, {})); | |
234 | ASSERT_TRUE(cap.is_capable(NULL, name, "mon", "", ca, true, false, false, | |
235 | {})); | |
236 | ||
237 | ASSERT_FALSE(cap.is_capable(NULL, name, "mds", "", ca, true, true, true, {})); | |
238 | ASSERT_FALSE(cap.is_capable(NULL, name, "mon", "", ca, true, true, true, {})); | |
7c673cae FG |
239 | |
240 | ca.clear(); | |
92f5a8d4 TL |
241 | ASSERT_FALSE(cap.is_capable(NULL, name, "", "config-key get", ca, true, true, |
242 | true, {})); | |
7c673cae | 243 | ca["key"] = "daemon-private/osd.123"; |
92f5a8d4 TL |
244 | ASSERT_FALSE(cap.is_capable(NULL, name, "", "config-key get", ca, true, true, |
245 | true, {})); | |
7c673cae | 246 | ca["key"] = "daemon-private/osd.12/asdf"; |
92f5a8d4 TL |
247 | ASSERT_FALSE(cap.is_capable(NULL, name, "", "config-key get", ca, true, true, |
248 | true, {})); | |
7c673cae | 249 | ca["key"] = "daemon-private/osd.123/"; |
92f5a8d4 TL |
250 | ASSERT_TRUE(cap.is_capable(NULL, name, "", "config-key get", ca, true, true, |
251 | true, {})); | |
252 | ASSERT_TRUE(cap.is_capable(NULL, name, "", "config-key get", ca, true, true, | |
253 | true, {})); | |
254 | ASSERT_TRUE(cap.is_capable(NULL, name, "", "config-key get", ca, true, true, | |
255 | true, {})); | |
7c673cae | 256 | ca["key"] = "daemon-private/osd.123/foo"; |
92f5a8d4 TL |
257 | ASSERT_TRUE(cap.is_capable(NULL, name, "", "config-key get", ca, true, true, |
258 | true, {})); | |
259 | ASSERT_TRUE(cap.is_capable(NULL, name, "", "config-key put", ca, true, true, | |
260 | true, {})); | |
261 | ASSERT_TRUE(cap.is_capable(NULL, name, "", "config-key set", ca, true, true, | |
262 | true, {})); | |
263 | ASSERT_TRUE(cap.is_capable(NULL, name, "", "config-key exists", ca, true, | |
264 | true, true, {})); | |
265 | ASSERT_TRUE(cap.is_capable(NULL, name, "", "config-key delete", ca, true, | |
266 | true, true, {})); | |
7c673cae FG |
267 | } |
268 | ||
c07f9fc5 FG |
269 | TEST(MonCap, CommandRegEx) { |
270 | MonCap cap; | |
271 | ASSERT_FALSE(cap.is_allow_all()); | |
92f5a8d4 TL |
272 | ASSERT_TRUE(cap.parse("allow command abc with arg regex \"^[0-9a-z.]*$\"", |
273 | NULL)); | |
c07f9fc5 FG |
274 | |
275 | EntityName name; | |
276 | name.from_str("osd.123"); | |
92f5a8d4 TL |
277 | ASSERT_TRUE(cap.is_capable(nullptr, name, "", "abc", {{"arg", "12345abcde"}}, |
278 | true, true, true, {})); | |
279 | ASSERT_FALSE(cap.is_capable(nullptr, name, "", "abc", {{"arg", "~!@#$"}}, | |
280 | true, true, true, {})); | |
c07f9fc5 FG |
281 | |
282 | ASSERT_TRUE(cap.parse("allow command abc with arg regex \"[*\"", NULL)); | |
92f5a8d4 TL |
283 | ASSERT_FALSE(cap.is_capable(nullptr, name, "", "abc", {{"arg", ""}}, true, |
284 | true, true, {})); | |
c07f9fc5 | 285 | } |
d2e6a577 FG |
286 | |
287 | TEST(MonCap, ProfileBootstrapRBD) { | |
288 | MonCap cap; | |
289 | ASSERT_FALSE(cap.is_allow_all()); | |
290 | ASSERT_TRUE(cap.parse("profile bootstrap-rbd", NULL)); | |
291 | ||
292 | EntityName name; | |
293 | name.from_str("mon.a"); | |
92f5a8d4 | 294 | ASSERT_TRUE(cap.is_capable(nullptr, name, "", |
d2e6a577 FG |
295 | "auth get-or-create", { |
296 | {"entity", "client.rbd"}, | |
297 | {"caps_mon", "profile rbd"}, | |
298 | {"caps_osd", "profile rbd pool=foo, profile rbd-read-only"}, | |
11fdf7f2 | 299 | }, true, true, true, |
92f5a8d4 TL |
300 | {})); |
301 | ASSERT_FALSE(cap.is_capable(nullptr, name, "", | |
d2e6a577 FG |
302 | "auth get-or-create", { |
303 | {"entity", "client.rbd"}, | |
304 | {"caps_mon", "allow *"}, | |
305 | {"caps_osd", "profile rbd"}, | |
11fdf7f2 | 306 | }, true, true, true, |
92f5a8d4 TL |
307 | {})); |
308 | ASSERT_FALSE(cap.is_capable(nullptr, name, "", | |
11fdf7f2 TL |
309 | "auth get-or-create", { |
310 | {"entity", "client.rbd"}, | |
311 | {"caps_mon", "profile rbd"}, | |
312 | {"caps_osd", "profile rbd pool=foo, allow *, profile rbd-read-only"}, | |
313 | }, true, true, true, | |
92f5a8d4 | 314 | {})); |
11fdf7f2 TL |
315 | } |
316 | ||
317 | TEST(MonCap, ProfileBootstrapRBDMirror) { | |
318 | MonCap cap; | |
319 | ASSERT_FALSE(cap.is_allow_all()); | |
320 | ASSERT_TRUE(cap.parse("profile bootstrap-rbd-mirror", NULL)); | |
321 | ||
322 | EntityName name; | |
323 | name.from_str("mon.a"); | |
92f5a8d4 | 324 | ASSERT_TRUE(cap.is_capable(nullptr, name, "", |
11fdf7f2 TL |
325 | "auth get-or-create", { |
326 | {"entity", "client.rbd"}, | |
327 | {"caps_mon", "profile rbd-mirror"}, | |
328 | {"caps_osd", "profile rbd pool=foo, profile rbd-read-only"}, | |
329 | }, true, true, true, | |
92f5a8d4 TL |
330 | {})); |
331 | ASSERT_FALSE(cap.is_capable(nullptr, name, "", | |
d2e6a577 FG |
332 | "auth get-or-create", { |
333 | {"entity", "client.rbd"}, | |
334 | {"caps_mon", "profile rbd"}, | |
11fdf7f2 TL |
335 | {"caps_osd", "profile rbd pool=foo, profile rbd-read-only"}, |
336 | }, true, true, true, | |
92f5a8d4 TL |
337 | {})); |
338 | ASSERT_FALSE(cap.is_capable(nullptr, name, "", | |
11fdf7f2 TL |
339 | "auth get-or-create", { |
340 | {"entity", "client.rbd"}, | |
341 | {"caps_mon", "allow *"}, | |
342 | {"caps_osd", "profile rbd"}, | |
343 | }, true, true, true, | |
92f5a8d4 TL |
344 | {})); |
345 | ASSERT_FALSE(cap.is_capable(nullptr, name, "", | |
11fdf7f2 TL |
346 | "auth get-or-create", { |
347 | {"entity", "client.rbd"}, | |
348 | {"caps_mon", "profile rbd-mirror"}, | |
d2e6a577 | 349 | {"caps_osd", "profile rbd pool=foo, allow *, profile rbd-read-only"}, |
11fdf7f2 | 350 | }, true, true, true, |
92f5a8d4 | 351 | {})); |
11fdf7f2 TL |
352 | } |
353 | ||
354 | TEST(MonCap, ProfileRBD) { | |
355 | MonCap cap; | |
356 | ASSERT_FALSE(cap.is_allow_all()); | |
357 | ASSERT_TRUE(cap.parse("profile rbd", NULL)); | |
358 | ||
359 | EntityName name; | |
360 | name.from_str("mon.a"); | |
92f5a8d4 | 361 | ASSERT_FALSE(cap.is_capable(nullptr, name, "config-key", |
11fdf7f2 TL |
362 | "config-key get", { |
363 | {"key", "rbd/mirror/peer/1/1234"}, | |
92f5a8d4 | 364 | }, true, false, false, {})); |
11fdf7f2 TL |
365 | } |
366 | ||
367 | TEST(MonCap, ProfileRBDMirror) { | |
368 | MonCap cap; | |
369 | ASSERT_FALSE(cap.is_allow_all()); | |
370 | ASSERT_TRUE(cap.parse("profile rbd-mirror", NULL)); | |
371 | ||
372 | EntityName name; | |
373 | name.from_str("mon.a"); | |
92f5a8d4 | 374 | ASSERT_TRUE(cap.is_capable(nullptr, name, "config-key", |
11fdf7f2 TL |
375 | "config-key get", { |
376 | {"key", "rbd/mirror/peer/1/1234"}, | |
92f5a8d4 | 377 | }, true, false, false, {})); |
d2e6a577 | 378 | } |