filter_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "device/fido/filter.h"
  5. #include "testing/gtest/include/gtest/gtest.h"
  6. namespace device {
  7. namespace fido_filter {
  8. namespace {
  9. TEST(FidoFilter, Basic) {
  10. static const uint8_t kCredIDBytes[] = {1, 2, 3, 4};
  11. const auto cred_id = std::pair<IDType, base::span<const uint8_t>>(
  12. IDType::CREDENTIAL_ID, kCredIDBytes);
  13. const auto empty_cred_id = std::pair<IDType, base::span<const uint8_t>>(
  14. IDType::CREDENTIAL_ID, base::span<const uint8_t>());
  15. static const struct {
  16. const char* filter;
  17. Operation op;
  18. base::StringPiece rp_id;
  19. absl::optional<base::StringPiece> device;
  20. absl::optional<std::pair<IDType, base::span<const uint8_t>>> id;
  21. Action expected;
  22. } kTests[] = {
  23. {
  24. "",
  25. Operation::MAKE_CREDENTIAL,
  26. "example.com",
  27. absl::nullopt,
  28. absl::nullopt,
  29. Action::ALLOW,
  30. },
  31. {
  32. R"({"filters": []})",
  33. Operation::MAKE_CREDENTIAL,
  34. "example.com",
  35. absl::nullopt,
  36. absl::nullopt,
  37. Action::ALLOW,
  38. },
  39. {
  40. R"({"filters": [{
  41. "operation": "mc",
  42. "rp_id": "*",
  43. "action": "block",
  44. }]})",
  45. Operation::MAKE_CREDENTIAL,
  46. "example.com",
  47. absl::nullopt,
  48. absl::nullopt,
  49. Action::BLOCK,
  50. },
  51. {
  52. R"({"filters": [{
  53. "operation": "m*",
  54. "rp_id": "*",
  55. "action": "block",
  56. }]})",
  57. Operation::MAKE_CREDENTIAL,
  58. "example.com",
  59. absl::nullopt,
  60. absl::nullopt,
  61. Action::BLOCK,
  62. },
  63. {
  64. R"({"filters": [{
  65. "operation": "*",
  66. "rp_id": "*",
  67. "action": "block",
  68. }]})",
  69. Operation::MAKE_CREDENTIAL,
  70. "example.com",
  71. absl::nullopt,
  72. absl::nullopt,
  73. Action::BLOCK,
  74. },
  75. {
  76. R"({"filters": [{
  77. "operation": "mc",
  78. "rp_id": "*",
  79. "action": "no-attestation",
  80. }]})",
  81. Operation::MAKE_CREDENTIAL,
  82. "example.com",
  83. absl::nullopt,
  84. absl::nullopt,
  85. Action::NO_ATTESTATION,
  86. },
  87. {
  88. R"({"filters": [{
  89. "rp_id": "example.com",
  90. "action": "block",
  91. }]})",
  92. Operation::MAKE_CREDENTIAL,
  93. "example.com",
  94. absl::nullopt,
  95. absl::nullopt,
  96. Action::BLOCK,
  97. },
  98. {
  99. R"({"filters": [{
  100. "rp_id": "foo.com",
  101. "action": "block",
  102. }]})",
  103. Operation::MAKE_CREDENTIAL,
  104. "example.com",
  105. absl::nullopt,
  106. absl::nullopt,
  107. Action::ALLOW,
  108. },
  109. {
  110. R"({"filters": [{
  111. "device": "usb-1234:4321",
  112. "action": "block",
  113. }]})",
  114. Operation::MAKE_CREDENTIAL,
  115. "example.com",
  116. "usb-1234:4321",
  117. absl::nullopt,
  118. Action::BLOCK,
  119. },
  120. {
  121. R"({"filters": [{
  122. "device": "usb-1234:4321",
  123. "action": "block",
  124. }]})",
  125. Operation::MAKE_CREDENTIAL,
  126. "example.com",
  127. "usb-0000:4321",
  128. absl::nullopt,
  129. Action::ALLOW,
  130. },
  131. {
  132. R"({"filters": [{
  133. "device": "usb-*",
  134. "action": "block",
  135. }]})",
  136. Operation::MAKE_CREDENTIAL,
  137. "example.com",
  138. "usb-0000:4321",
  139. absl::nullopt,
  140. Action::BLOCK,
  141. },
  142. {
  143. R"({"filters": [{
  144. "device": "usb-*",
  145. "action": "block",
  146. }]})",
  147. Operation::MAKE_CREDENTIAL,
  148. "example.com",
  149. "usb-0000:4321",
  150. absl::nullopt,
  151. Action::BLOCK,
  152. },
  153. {
  154. R"({"filters": [{
  155. "id_type": "cred",
  156. "rp_id": "*",
  157. "action": "block",
  158. }]})",
  159. Operation::MAKE_CREDENTIAL,
  160. "example.com",
  161. absl::nullopt,
  162. cred_id,
  163. Action::BLOCK,
  164. },
  165. {
  166. R"({"filters": [{
  167. "id_type": "user",
  168. "rp_id": "*",
  169. "action": "block",
  170. }]})",
  171. Operation::MAKE_CREDENTIAL,
  172. "example.com",
  173. absl::nullopt,
  174. cred_id,
  175. Action::ALLOW,
  176. },
  177. {
  178. R"({"filters": [{
  179. "id_type": "cred",
  180. "id": "01*",
  181. "rp_id": "*",
  182. "action": "block",
  183. }]})",
  184. Operation::MAKE_CREDENTIAL,
  185. "example.com",
  186. absl::nullopt,
  187. cred_id,
  188. Action::BLOCK,
  189. },
  190. {
  191. R"({"filters": [{
  192. "id_type": "cred",
  193. "id": "01020304",
  194. "rp_id": "*",
  195. "action": "block",
  196. }]})",
  197. Operation::MAKE_CREDENTIAL,
  198. "example.com",
  199. absl::nullopt,
  200. cred_id,
  201. Action::BLOCK,
  202. },
  203. {
  204. R"({"filters": [{
  205. "id_type": "cred",
  206. "id_min_size": 4,
  207. "rp_id": "*",
  208. "action": "block",
  209. }]})",
  210. Operation::MAKE_CREDENTIAL,
  211. "example.com",
  212. absl::nullopt,
  213. cred_id,
  214. Action::BLOCK,
  215. },
  216. {
  217. R"({"filters": [{
  218. "id_type": "cred",
  219. "id_min_size": 8,
  220. "rp_id": "*",
  221. "action": "block",
  222. }]})",
  223. Operation::MAKE_CREDENTIAL,
  224. "example.com",
  225. absl::nullopt,
  226. cred_id,
  227. Action::ALLOW,
  228. },
  229. {
  230. R"({"filters": [{
  231. "id_type": "cred",
  232. "id_min_size": 4,
  233. "id_max_size": 4,
  234. "rp_id": "*",
  235. "action": "block",
  236. }]})",
  237. Operation::MAKE_CREDENTIAL,
  238. "example.com",
  239. absl::nullopt,
  240. cred_id,
  241. Action::BLOCK,
  242. },
  243. // id fields can be empty, to match an empty ID.
  244. {
  245. R"({"filters": [{
  246. "operation": "mc",
  247. "rp_id": "*",
  248. "id_type": "cred",
  249. "id": "",
  250. "action": "block",
  251. }]})",
  252. Operation::MAKE_CREDENTIAL,
  253. "example.com",
  254. absl::nullopt,
  255. empty_cred_id,
  256. Action::BLOCK,
  257. },
  258. // rp_id can be a list of strings, any of which may match.
  259. {
  260. R"({"filters": [{
  261. "operation": "mc",
  262. "rp_id": ["a.com", "b.com"],
  263. "action": "block",
  264. }]})",
  265. Operation::MAKE_CREDENTIAL,
  266. "a.com",
  267. absl::nullopt,
  268. absl::nullopt,
  269. Action::BLOCK,
  270. },
  271. {
  272. R"({"filters": [{
  273. "operation": "mc",
  274. "rp_id": ["a.com", "b.com"],
  275. "action": "block",
  276. }]})",
  277. Operation::MAKE_CREDENTIAL,
  278. "b.com",
  279. absl::nullopt,
  280. absl::nullopt,
  281. Action::BLOCK,
  282. },
  283. {
  284. R"({"filters": [{
  285. "operation": "mc",
  286. "rp_id": ["a.com", "b.com"],
  287. "action": "block",
  288. }]})",
  289. Operation::MAKE_CREDENTIAL,
  290. "c.com",
  291. absl::nullopt,
  292. absl::nullopt,
  293. Action::ALLOW,
  294. },
  295. // id can be a list of strings, any of which may match.
  296. {
  297. R"({"filters": [{
  298. "operation": "mc",
  299. "rp_id": "*",
  300. "id_type": "cred",
  301. "id": ["01", "01020304", "05060708", ""],
  302. "action": "block",
  303. }]})",
  304. Operation::MAKE_CREDENTIAL,
  305. "a.com",
  306. absl::nullopt,
  307. cred_id,
  308. Action::BLOCK,
  309. },
  310. // The two following cases test that a more specific filter can permit
  311. // something blocked by a later, more general, filter.
  312. {
  313. R"({"filters": [{
  314. "rp_id": "*",
  315. "device": "usb-1234:1234",
  316. "action": "allow",
  317. },{
  318. "rp_id": "*",
  319. "device": "usb-1234:*",
  320. "action": "block",
  321. }]})",
  322. Operation::MAKE_CREDENTIAL,
  323. "example.com",
  324. "usb-1234:5678",
  325. absl::nullopt,
  326. Action::BLOCK,
  327. },
  328. {
  329. R"({"filters": [{
  330. "rp_id": "*",
  331. "device": "usb-1234:1234",
  332. "action": "allow",
  333. },{
  334. "rp_id": "*",
  335. "device": "usb-1234:*",
  336. "action": "block",
  337. }]})",
  338. Operation::MAKE_CREDENTIAL,
  339. "example.com",
  340. "usb-1234:1234",
  341. absl::nullopt,
  342. Action::ALLOW,
  343. },
  344. };
  345. int test_num = 0;
  346. for (const auto& test : kTests) {
  347. SCOPED_TRACE(test_num);
  348. SCOPED_TRACE(test.filter);
  349. test_num++;
  350. ScopedFilterForTesting filter(test.filter);
  351. const Action result = Evaluate(test.op, test.rp_id, test.device, test.id);
  352. EXPECT_EQ(result, test.expected);
  353. }
  354. }
  355. TEST(FidoFilter, InvalidFilters) {
  356. static const char* kTests[] = {
  357. // Value has the wrong type.
  358. R"({"filters": [{
  359. "operation": 8,
  360. "rp_id": "foo.com",
  361. "action": "block"
  362. }]})",
  363. // Missing action.
  364. R"({"filters": [{
  365. "id_type": "cred",
  366. "id_min_size": 8
  367. }]})",
  368. // Unknown action.
  369. R"({"filters": [{
  370. "id_type": "cred",
  371. "id_min_size": 8,
  372. "action": "foo"
  373. }]})",
  374. // Missing ID types
  375. R"({"filters": [{
  376. "id_min_size": 8,
  377. "action": "block"
  378. }]})",
  379. R"({"filters": [{
  380. "id_max_size": 8,
  381. "action": "block"
  382. }]})",
  383. R"({"filters": [{
  384. "id": "112233",
  385. "action": "block"
  386. }]})",
  387. // Can't match everything.
  388. R"({"filters": [{
  389. "operation": "mc",
  390. "action": "block"
  391. }]})",
  392. // Can't match everything.
  393. R"({"filters": [{
  394. "operation": "ga",
  395. "action": "block"
  396. }]})",
  397. // Unknown keys are an error
  398. R"({"filters": [{
  399. "operation": "ga",
  400. "rp_id": "foo.com",
  401. "action": "block",
  402. "unknown": "bar"
  403. }]})",
  404. // No string values except IDs can be empty.
  405. R"({"filters": [{
  406. "operation": "ga",
  407. "rp_id": "",
  408. "action": "block",
  409. }]})",
  410. R"({"filters": [{
  411. "operation": "ga",
  412. "rp_id": ["nonempty", ""],
  413. "action": "block",
  414. }]})",
  415. R"({"filters": [{
  416. "operation": "ga",
  417. "rp_id": [],
  418. "action": "block",
  419. }]})",
  420. R"({"filters": [{
  421. "operation": "ga",
  422. "rp_id": "*",
  423. "id": [],
  424. "action": "block",
  425. }]})",
  426. };
  427. int test_num = 0;
  428. for (const auto* test : kTests) {
  429. SCOPED_TRACE(test_num);
  430. SCOPED_TRACE(test);
  431. test_num++;
  432. EXPECT_FALSE(ParseForTesting(test));
  433. }
  434. }
  435. TEST(FidoFilter, InvalidJSON) {
  436. // Testing that nothing crashes, etc.
  437. ScopedFilterForTesting filter(
  438. "nonsense", ScopedFilterForTesting::PermitInvalidJSON::kYes);
  439. ASSERT_EQ(Evaluate(Operation::GET_ASSERTION, "example.com", absl::nullopt,
  440. absl::nullopt),
  441. Action::ALLOW);
  442. ASSERT_EQ(Evaluate(Operation::MAKE_CREDENTIAL, "example.com", absl::nullopt,
  443. absl::nullopt),
  444. Action::ALLOW);
  445. }
  446. } // namespace
  447. } // namespace fido_filter
  448. } // namespace device