You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

689 lines
32 KiB

5 months ago
5 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
5 months ago
3 months ago
5 months ago
3 months ago
5 months ago
  1. /* Copyright 2010-present MongoDB Inc.
  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. using System;
  16. using System.Collections.Generic;
  17. using FluentAssertions;
  18. using MongoDB.Bson;
  19. using MongoDB.Bson.Serialization.Attributes;
  20. using MongoDB.Driver.Encryption;
  21. using Xunit;
  22. namespace MongoDB.Driver.Tests.Encryption
  23. {
  24. public class CsfleSchemaBuilderTests
  25. {
  26. private const string _keyIdString = "6f4af470-00d1-401f-ac39-f45902a0c0c8";
  27. private static Guid _keyId = Guid.Parse(_keyIdString);
  28. [Fact]
  29. public void CsfleSchemaBuilder_works_as_expected()
  30. {
  31. const string collectionName = "medicalRecords.patients";
  32. var builder = CsfleSchemaBuilder.Create(schemaBuilder =>
  33. {
  34. schemaBuilder.Encrypt<Patient>(collectionName, builder =>
  35. {
  36. builder
  37. .EncryptMetadata(keyId: _keyId)
  38. .Property(p => p.MedicalRecords, BsonType.Array,
  39. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random)
  40. .Property("bloodType", BsonType.String,
  41. algorithm: EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random)
  42. .Property(p => p.Ssn, BsonType.Int32,
  43. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic)
  44. .Property(p => p.Insurance, innerBuilder =>
  45. {
  46. innerBuilder
  47. .Property(i => i.PolicyNumber, BsonType.Int32,
  48. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic);
  49. })
  50. .PatternProperty("_PIIString$", BsonType.String, EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic)
  51. .PatternProperty("_PIIArray$", BsonType.Array, EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random)
  52. .PatternProperty(p => p.Insurance, innerBuilder =>
  53. {
  54. innerBuilder
  55. .PatternProperty("_PIIString$", BsonType.String,
  56. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic)
  57. .PatternProperty("_PIINumber$", BsonType.Int32,
  58. algorithm: EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic);
  59. });
  60. } );
  61. });
  62. var expected = new Dictionary<string, string>
  63. {
  64. [collectionName] = """
  65. {
  66. "bsonType": "object",
  67. "encryptMetadata": {
  68. "keyId": [{ "$binary" : { "base64" : "b0r0cADRQB+sOfRZAqDAyA==", "subType" : "04" } }]
  69. },
  70. "properties": {
  71. "insurance": {
  72. "bsonType": "object",
  73. "properties": {
  74. "policyNumber": {
  75. "encrypt": {
  76. "bsonType": "int",
  77. "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
  78. }
  79. }
  80. }
  81. },
  82. "medicalRecords": {
  83. "encrypt": {
  84. "bsonType": "array",
  85. "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
  86. }
  87. },
  88. "bloodType": {
  89. "encrypt": {
  90. "bsonType": "string",
  91. "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
  92. }
  93. },
  94. "ssn": {
  95. "encrypt": {
  96. "bsonType": "int",
  97. "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
  98. }
  99. }
  100. },
  101. "patternProperties": {
  102. "_PIIString$": {
  103. "encrypt": {
  104. "bsonType": "string",
  105. "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic",
  106. },
  107. },
  108. "_PIIArray$": {
  109. "encrypt": {
  110. "bsonType": "array",
  111. "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random",
  112. },
  113. },
  114. "insurance": {
  115. "bsonType": "object",
  116. "patternProperties": {
  117. "_PIINumber$": {
  118. "encrypt": {
  119. "bsonType": "int",
  120. "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic",
  121. },
  122. },
  123. "_PIIString$": {
  124. "encrypt": {
  125. "bsonType": "string",
  126. "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic",
  127. },
  128. },
  129. },
  130. },
  131. },
  132. }
  133. """
  134. };
  135. AssertOutcomeCsfleSchemaBuilder(builder, expected);
  136. }
  137. [Fact]
  138. public void CsfleSchemaBuilder_with_multiple_types_works_as_expected()
  139. {
  140. const string patientCollectionName = "medicalRecords.patients";
  141. const string testClassCollectionName = "test.class";
  142. var builder = CsfleSchemaBuilder.Create(schemaBuilder =>
  143. {
  144. schemaBuilder.Encrypt<Patient>(patientCollectionName, builder =>
  145. {
  146. builder
  147. .EncryptMetadata(keyId: _keyId)
  148. .Property(p => p.MedicalRecords, BsonType.Array,
  149. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random);
  150. });
  151. schemaBuilder.Encrypt<TestClass>(testClassCollectionName, builder =>
  152. {
  153. builder.Property(t => t.TestString, BsonType.String);
  154. });
  155. });
  156. var expected = new Dictionary<string, string>
  157. {
  158. [patientCollectionName] = """
  159. {
  160. "bsonType": "object",
  161. "encryptMetadata": {
  162. "keyId": [{ "$binary" : { "base64" : "b0r0cADRQB+sOfRZAqDAyA==", "subType" : "04" } }]
  163. },
  164. "properties": {
  165. "medicalRecords": {
  166. "encrypt": {
  167. "bsonType": "array",
  168. "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
  169. }
  170. },
  171. },
  172. }
  173. """,
  174. [testClassCollectionName] = """
  175. {
  176. "bsonType": "object",
  177. "properties": {
  178. "TestString": {
  179. "encrypt": {
  180. "bsonType": "string",
  181. }
  182. },
  183. }
  184. }
  185. """
  186. };
  187. AssertOutcomeCsfleSchemaBuilder(builder, expected);
  188. }
  189. [Theory]
  190. [InlineData(
  191. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random,
  192. null,
  193. """ "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" """)]
  194. [InlineData(
  195. null,
  196. _keyIdString,
  197. """ "keyId": [{ "$binary" : { "base64" : "b0r0cADRQB+sOfRZAqDAyA==", "subType" : "04" } }] """)]
  198. public void EncryptedCollection_Metadata_works_as_expected(EncryptionAlgorithm? algorithm, string keyString, string expectedContent)
  199. {
  200. Guid? keyId = keyString is null ? null : Guid.Parse(keyString);
  201. var builder = new EncryptedCollectionBuilder<Patient>();
  202. builder.EncryptMetadata(keyId, algorithm);
  203. var expected = $$"""
  204. {
  205. "bsonType": "object",
  206. "encryptMetadata": {
  207. {{expectedContent}}
  208. }
  209. }
  210. """;
  211. AssertOutcomeCollectionBuilder(builder, expected);
  212. }
  213. [Theory]
  214. [InlineData(BsonType.Array,
  215. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random,
  216. null,
  217. """ "bsonType": "array", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" """)]
  218. [InlineData(BsonType.Array,
  219. null,
  220. _keyIdString,
  221. """ "bsonType": "array", "keyId": [{ "$binary" : { "base64" : "b0r0cADRQB+sOfRZAqDAyA==", "subType" : "04" } }] """)]
  222. [InlineData(BsonType.Array,
  223. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random,
  224. _keyIdString,
  225. """ "bsonType": "array", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", "keyId": [{ "$binary" : { "base64" : "b0r0cADRQB+sOfRZAqDAyA==", "subType" : "04" } }] """)]
  226. public void EncryptedCollection_PatternProperty_works_as_expected(BsonType bsonType, EncryptionAlgorithm? algorithm, string keyString, string expectedContent)
  227. {
  228. Guid? keyId = keyString is null ? null : Guid.Parse(keyString);
  229. var builder = new EncryptedCollectionBuilder<Patient>();
  230. builder.PatternProperty("randomRegex*", bsonType, algorithm, keyId);
  231. var expected = $$"""
  232. {
  233. "bsonType": "object",
  234. "patternProperties": {
  235. "randomRegex*": {
  236. "encrypt": {
  237. {{expectedContent}}
  238. }
  239. }
  240. }
  241. }
  242. """;
  243. AssertOutcomeCollectionBuilder(builder, expected);
  244. }
  245. [Theory]
  246. [InlineData(new[] {BsonType.Array, BsonType.String},
  247. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random,
  248. null,
  249. """ "bsonType": ["array", "string"], "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" """)]
  250. [InlineData(new[] {BsonType.Array, BsonType.String},
  251. null,
  252. _keyIdString,
  253. """ "bsonType": ["array", "string"], "keyId": [{ "$binary" : { "base64" : "b0r0cADRQB+sOfRZAqDAyA==", "subType" : "04" } }] """)]
  254. [InlineData(new[] {BsonType.Array, BsonType.String},
  255. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random,
  256. _keyIdString,
  257. """ "bsonType": ["array", "string"], "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", "keyId": [{ "$binary" : { "base64" : "b0r0cADRQB+sOfRZAqDAyA==", "subType" : "04" } }] """)]
  258. public void EncryptedCollection_PatternProperty_with_multiple_bson_types_works_as_expected(IEnumerable<BsonType> bsonTypes, EncryptionAlgorithm? algorithm, string keyString, string expectedContent)
  259. {
  260. Guid? keyId = keyString is null ? null : Guid.Parse(keyString);
  261. var builder = new EncryptedCollectionBuilder<Patient>();
  262. builder.PatternProperty("randomRegex*", bsonTypes, algorithm, keyId);
  263. var expected = $$"""
  264. {
  265. "bsonType": "object",
  266. "patternProperties": {
  267. "randomRegex*": {
  268. "encrypt": {
  269. {{expectedContent}}
  270. }
  271. }
  272. }
  273. }
  274. """;
  275. AssertOutcomeCollectionBuilder(builder, expected);
  276. }
  277. [Fact]
  278. public void EncryptedCollection_PatternProperty_nested_works_as_expected()
  279. {
  280. Guid? keyId = Guid.Parse(_keyIdString);
  281. var builder = new EncryptedCollectionBuilder<Patient>();
  282. builder.PatternProperty(p => p.Insurance, innerBuilder =>
  283. {
  284. innerBuilder
  285. .EncryptMetadata(keyId)
  286. .Property("policyNumber", BsonType.Int32,
  287. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic)
  288. .PatternProperty("randomRegex*", BsonType.String,
  289. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random);
  290. });
  291. var expected = """
  292. {
  293. "bsonType": "object",
  294. "patternProperties": {
  295. "insurance": {
  296. "bsonType": "object",
  297. "encryptMetadata": {
  298. "keyId": [{ "$binary" : { "base64" : "b0r0cADRQB+sOfRZAqDAyA==", "subType" : "04" } }]
  299. },
  300. "properties": {
  301. "policyNumber": {
  302. "encrypt": {
  303. "bsonType": "int",
  304. "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
  305. }
  306. }
  307. },
  308. "patternProperties": {
  309. "randomRegex*": {
  310. "encrypt": {
  311. "bsonType": "string",
  312. "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
  313. }
  314. }
  315. }
  316. }
  317. }
  318. }
  319. """;
  320. AssertOutcomeCollectionBuilder(builder, expected);
  321. }
  322. [Fact]
  323. public void EncryptedCollection_PatternProperty_nested_with_string_works_as_expected()
  324. {
  325. Guid? keyId = Guid.Parse(_keyIdString);
  326. var builder = new EncryptedCollectionBuilder<Patient>();
  327. builder.PatternProperty<Insurance>("insurance", innerBuilder =>
  328. {
  329. innerBuilder
  330. .EncryptMetadata(keyId)
  331. .Property("policyNumber", BsonType.Int32,
  332. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic)
  333. .PatternProperty("randomRegex*", BsonType.String,
  334. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random);
  335. });
  336. var expected = """
  337. {
  338. "bsonType": "object",
  339. "patternProperties": {
  340. "insurance": {
  341. "bsonType": "object",
  342. "encryptMetadata": {
  343. "keyId": [{ "$binary" : { "base64" : "b0r0cADRQB+sOfRZAqDAyA==", "subType" : "04" } }]
  344. },
  345. "properties": {
  346. "policyNumber": {
  347. "encrypt": {
  348. "bsonType": "int",
  349. "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
  350. }
  351. }
  352. },
  353. "patternProperties": {
  354. "randomRegex*": {
  355. "encrypt": {
  356. "bsonType": "string",
  357. "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
  358. }
  359. }
  360. }
  361. }
  362. }
  363. }
  364. """;
  365. AssertOutcomeCollectionBuilder(builder, expected);
  366. }
  367. [Theory]
  368. [InlineData(BsonType.Array,
  369. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random,
  370. null,
  371. """ "bsonType": "array", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" """)]
  372. [InlineData(BsonType.Array,
  373. null,
  374. _keyIdString,
  375. """ "bsonType": "array", "keyId": [{ "$binary" : { "base64" : "b0r0cADRQB+sOfRZAqDAyA==", "subType" : "04" } }] """)]
  376. [InlineData(BsonType.Array,
  377. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random,
  378. _keyIdString,
  379. """ "bsonType": "array", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", "keyId": [{ "$binary" : { "base64" : "b0r0cADRQB+sOfRZAqDAyA==", "subType" : "04" } }] """)]
  380. public void EncryptedCollection_Property_with_expression_works_as_expected(BsonType bsonType, EncryptionAlgorithm? algorithm, string keyString, string expectedContent)
  381. {
  382. Guid? keyId = keyString is null ? null : Guid.Parse(keyString);
  383. var builder = new EncryptedCollectionBuilder<Patient>();
  384. builder.Property(p => p.MedicalRecords, bsonType, algorithm, keyId);
  385. var expected = $$"""
  386. {
  387. "bsonType": "object",
  388. "properties": {
  389. "medicalRecords": {
  390. "encrypt": {
  391. {{expectedContent}}
  392. }
  393. }
  394. }
  395. }
  396. """;
  397. AssertOutcomeCollectionBuilder(builder, expected);
  398. }
  399. [Theory]
  400. [InlineData(new[] {BsonType.Array, BsonType.String},
  401. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random,
  402. null,
  403. """ "bsonType": ["array", "string"], "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" """)]
  404. [InlineData(new[] {BsonType.Array, BsonType.String},
  405. null,
  406. _keyIdString,
  407. """ "bsonType": ["array", "string"], "keyId": [{ "$binary" : { "base64" : "b0r0cADRQB+sOfRZAqDAyA==", "subType" : "04" } }] """)]
  408. [InlineData(new[] {BsonType.Array, BsonType.String},
  409. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random,
  410. _keyIdString,
  411. """ "bsonType": ["array", "string"], "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", "keyId": [{ "$binary" : { "base64" : "b0r0cADRQB+sOfRZAqDAyA==", "subType" : "04" } }] """)]
  412. public void EncryptedCollection_Property_with_multiple_bson_types_works_as_expected(IEnumerable<BsonType> bsonTypes, EncryptionAlgorithm? algorithm, string keyString, string expectedContent)
  413. {
  414. Guid? keyId = keyString is null ? null : Guid.Parse(keyString);
  415. var builder = new EncryptedCollectionBuilder<Patient>();
  416. builder.Property(p => p.MedicalRecords, bsonTypes, algorithm, keyId);
  417. var expected = $$"""
  418. {
  419. "bsonType": "object",
  420. "properties": {
  421. "medicalRecords": {
  422. "encrypt": {
  423. {{expectedContent}}
  424. }
  425. }
  426. }
  427. }
  428. """;
  429. AssertOutcomeCollectionBuilder(builder, expected);
  430. }
  431. [Theory]
  432. [InlineData(BsonType.Array,
  433. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random,
  434. null,
  435. """ "bsonType": "array", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" """)]
  436. [InlineData(BsonType.Array,
  437. null,
  438. _keyIdString,
  439. """ "bsonType": "array", "keyId": [{ "$binary" : { "base64" : "b0r0cADRQB+sOfRZAqDAyA==", "subType" : "04" } }] """)]
  440. [InlineData(BsonType.Array,
  441. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random,
  442. _keyIdString,
  443. """ "bsonType": "array", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", "keyId": [{ "$binary" : { "base64" : "b0r0cADRQB+sOfRZAqDAyA==", "subType" : "04" } }] """)]
  444. public void EncryptedCollection_Property_with_string_works_as_expected(BsonType bsonType, EncryptionAlgorithm? algorithm, string keyString, string expectedContent)
  445. {
  446. Guid? keyId = keyString is null ? null : Guid.Parse(keyString);
  447. var builder = new EncryptedCollectionBuilder<Patient>();
  448. builder.Property("medicalRecords", bsonType, algorithm, keyId);
  449. var expected = $$"""
  450. {
  451. "bsonType": "object",
  452. "properties": {
  453. "medicalRecords": {
  454. "encrypt": {
  455. {{expectedContent}}
  456. }
  457. }
  458. }
  459. }
  460. """;
  461. AssertOutcomeCollectionBuilder(builder, expected);
  462. }
  463. [Fact]
  464. public void EncryptedCollection_Property_nested_works_as_expected()
  465. {
  466. Guid? keyId = Guid.Parse(_keyIdString);
  467. var builder = new EncryptedCollectionBuilder<Patient>();
  468. builder.Property(p => p.Insurance, innerBuilder =>
  469. {
  470. innerBuilder
  471. .EncryptMetadata(keyId)
  472. .Property("policyNumber", BsonType.Int32,
  473. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic)
  474. .PatternProperty("randomRegex*", BsonType.String,
  475. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random);
  476. });
  477. var expected = """
  478. {
  479. "bsonType": "object",
  480. "properties": {
  481. "insurance": {
  482. "bsonType": "object",
  483. "encryptMetadata": {
  484. "keyId": [{ "$binary" : { "base64" : "b0r0cADRQB+sOfRZAqDAyA==", "subType" : "04" } }]
  485. },
  486. "properties": {
  487. "policyNumber": {
  488. "encrypt": {
  489. "bsonType": "int",
  490. "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
  491. }
  492. }
  493. },
  494. "patternProperties": {
  495. "randomRegex*": {
  496. "encrypt": {
  497. "bsonType": "string",
  498. "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
  499. }
  500. }
  501. }
  502. }
  503. }
  504. }
  505. """;
  506. AssertOutcomeCollectionBuilder(builder, expected);
  507. }
  508. [Fact]
  509. public void EncryptedCollection_Property_nested_with_string_works_as_expected()
  510. {
  511. Guid? keyId = Guid.Parse(_keyIdString);
  512. var builder = new EncryptedCollectionBuilder<Patient>();
  513. builder.Property<Insurance>("insurance", innerBuilder =>
  514. {
  515. innerBuilder
  516. .EncryptMetadata(keyId)
  517. .Property("policyNumber", BsonType.Int32,
  518. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic)
  519. .PatternProperty("randomRegex*", BsonType.String,
  520. EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random);
  521. });
  522. var expected = """
  523. {
  524. "bsonType": "object",
  525. "properties": {
  526. "insurance": {
  527. "bsonType": "object",
  528. "encryptMetadata": {
  529. "keyId": [{ "$binary" : { "base64" : "b0r0cADRQB+sOfRZAqDAyA==", "subType" : "04" } }]
  530. },
  531. "properties": {
  532. "policyNumber": {
  533. "encrypt": {
  534. "bsonType": "int",
  535. "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
  536. }
  537. }
  538. },
  539. "patternProperties": {
  540. "randomRegex*": {
  541. "encrypt": {
  542. "bsonType": "string",
  543. "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
  544. }
  545. }
  546. }
  547. }
  548. }
  549. }
  550. """;
  551. AssertOutcomeCollectionBuilder(builder, expected);
  552. }
  553. [Fact]
  554. public void EncryptedCollection_Property_with_empty_bson_types_throws()
  555. {
  556. var builder = new EncryptedCollectionBuilder<Patient>();
  557. var recordedException = Record.Exception(() => builder.Property("test", []));
  558. recordedException.Should().NotBeNull();
  559. recordedException.Should().BeOfType<ArgumentException>();
  560. }
  561. [Fact]
  562. public void EncryptedCollection_Metadata_with_empty_algorithm_and_key_throws()
  563. {
  564. var builder = new EncryptedCollectionBuilder<Patient>();
  565. var recordedException = Record.Exception(() => builder.EncryptMetadata(null, null));
  566. recordedException.Should().NotBeNull();
  567. recordedException.Should().BeOfType<ArgumentException>();
  568. }
  569. private void AssertOutcomeCsfleSchemaBuilder(CsfleSchemaBuilder builder, Dictionary<string, string> expectedSchema)
  570. {
  571. var builtSchema = builder.Build();
  572. expectedSchema.Should().HaveCount(builtSchema.Count);
  573. foreach (var collectionNamespace in expectedSchema.Keys)
  574. {
  575. var parsed = BsonDocument.Parse(expectedSchema[collectionNamespace]);
  576. builtSchema[collectionNamespace].Should().BeEquivalentTo(parsed);
  577. }
  578. }
  579. private void AssertOutcomeCollectionBuilder<T>(EncryptedCollectionBuilder<T> builder, string expected)
  580. {
  581. var builtSchema = builder.Build();
  582. var expectedSchema = BsonDocument.Parse(expected);
  583. builtSchema.Should().BeEquivalentTo(expectedSchema);
  584. }
  585. internal class TestClass
  586. {
  587. public ObjectId Id { get; set; }
  588. public string TestString { get; set; }
  589. }
  590. internal class Patient
  591. {
  592. [BsonId]
  593. public ObjectId Id { get; set; }
  594. [BsonElement("name")]
  595. public string Name { get; set; }
  596. [BsonElement("ssn")]
  597. public int Ssn { get; set; }
  598. [BsonElement("bloodType")]
  599. public string BloodType { get; set; }
  600. [BsonElement("medicalRecords")]
  601. public List<MedicalRecord> MedicalRecords { get; set; }
  602. [BsonElement("insurance")]
  603. public Insurance Insurance { get; set; }
  604. }
  605. internal class MedicalRecord
  606. {
  607. [BsonElement("weight")]
  608. public int Weight { get; set; }
  609. [BsonElement("bloodPressure")]
  610. public string BloodPressure { get; set; }
  611. }
  612. internal class Insurance
  613. {
  614. [BsonElement("provider")]
  615. public string Provider { get; set; }
  616. [BsonElement("policyNumber")]
  617. public int PolicyNumber { get; set; }
  618. }
  619. }
  620. }