Skip to content

Commit 52b6abe

Browse files
authored
Fix #3837 Fixed Document.cs serialization issue that caused WebAuthn operations to fail when response contained Dictionary structures (#3867)
1 parent 891fed4 commit 52b6abe

File tree

3 files changed

+150
-1
lines changed

3 files changed

+150
-1
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"core": {
3+
"changeLogMessages": [
4+
"Fixed Document.cs serialization issue that caused WebAuthn operations to fail when response contained Dictionary structures [issue 3837](https://github.com/aws/aws-sdk-net/issues/3837)"
5+
],
6+
"type": "patch",
7+
"updateMinimum": true
8+
}
9+
}

sdk/src/Core/Amazon.Runtime/Documents/Document.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,13 @@ public override bool Equals(object obj)
286286
#region Collection Initializers
287287
IEnumerator<Document> IEnumerable<Document>.GetEnumerator()
288288
{
289-
return AsList().GetEnumerator();
289+
if (Type == DocumentType.List)
290+
return AsList().GetEnumerator();
291+
292+
if (Type == DocumentType.Dictionary)
293+
return AsDictionary().Values.GetEnumerator();
294+
295+
return new[] { this }.AsEnumerable().GetEnumerator();
290296
}
291297

292298
IEnumerator IEnumerable.GetEnumerator()

sdk/test/UnitTests/Custom/Runtime/Documents/DocumentTests.cs

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,140 @@ private void AssertIsDocumentType(Document doc, DocumentType t)
266266
Assert.IsTrue(doc.IsString());
267267
else
268268
Assert.IsFalse(doc.IsString());
269+
}
270+
/// <summary>
271+
/// Tests that enumerating a Dictionary type Document works correctly
272+
/// This tests the fix for WebAuthn serialization errors
273+
/// </summary>
274+
[TestMethod]
275+
[TestCategory("UnitTest")]
276+
[TestCategory("Runtime")]
277+
public void EnumerateDictionaryDocument()
278+
{
279+
// Create a dictionary document
280+
var doc = new Document
281+
{
282+
{"key1", "value1"},
283+
{"key2", 42},
284+
{"key3", true}
285+
};
286+
287+
// Ensure we can enumerate the document as IEnumerable<Document>
288+
var values = new List<Document>();
289+
foreach (var item in (IEnumerable<Document>)doc)
290+
{
291+
values.Add(item);
292+
}
293+
294+
// Should enumerate dictionary values
295+
Assert.AreEqual(3, values.Count);
296+
Assert.IsTrue(values.Any(v => v.IsString() && v.AsString() == "value1"));
297+
Assert.IsTrue(values.Any(v => v.IsInt() && v.AsInt() == 42));
298+
Assert.IsTrue(values.Any(v => v.IsBool() && v.AsBool() == true));
299+
}
300+
301+
/// <summary>
302+
/// Tests that enumerating a List type Document still works correctly
303+
/// </summary>
304+
[TestMethod]
305+
[TestCategory("UnitTest")]
306+
[TestCategory("Runtime")]
307+
public void EnumerateListDocument()
308+
{
309+
// Create a list document
310+
var doc = new Document("value1", 42, true);
311+
312+
// Ensure we can enumerate the document
313+
var values = new List<Document>();
314+
foreach (var item in (IEnumerable<Document>)doc)
315+
{
316+
values.Add(item);
317+
}
318+
319+
// Should enumerate list items in order
320+
Assert.AreEqual(3, values.Count);
321+
Assert.IsTrue(values[0].IsString() && values[0].AsString() == "value1");
322+
Assert.IsTrue(values[1].IsInt() && values[1].AsInt() == 42);
323+
Assert.IsTrue(values[2].IsBool() && values[2].AsBool() == true);
324+
}
325+
326+
/// <summary>
327+
/// Tests that enumerating non-collection type Documents returns the document itself
328+
/// </summary>
329+
[TestMethod]
330+
[TestCategory("UnitTest")]
331+
[TestCategory("Runtime")]
332+
public void EnumerateNonCollectionDocument()
333+
{
334+
// Test with various non-collection types
335+
var stringDoc = new Document("test");
336+
var intDoc = new Document(42);
337+
var boolDoc = new Document(true);
338+
var nullDoc = new Document();
339+
340+
// Each should enumerate to a single item - itself
341+
var stringValues = ((IEnumerable<Document>)stringDoc).ToList();
342+
Assert.AreEqual(1, stringValues.Count);
343+
Assert.AreEqual(stringDoc, stringValues[0]);
344+
345+
var intValues = ((IEnumerable<Document>)intDoc).ToList();
346+
Assert.AreEqual(1, intValues.Count);
347+
Assert.AreEqual(intDoc, intValues[0]);
348+
349+
var boolValues = ((IEnumerable<Document>)boolDoc).ToList();
350+
Assert.AreEqual(1, boolValues.Count);
351+
Assert.AreEqual(boolDoc, boolValues[0]);
352+
353+
var nullValues = ((IEnumerable<Document>)nullDoc).ToList();
354+
Assert.AreEqual(1, nullValues.Count);
355+
Assert.AreEqual(nullDoc, nullValues[0]);
356+
}
357+
358+
/// <summary>
359+
/// Tests that LINQ operations work correctly on Dictionary documents
360+
/// This specifically tests the WebAuthn scenario
361+
/// </summary>
362+
[TestMethod]
363+
[TestCategory("UnitTest")]
364+
[TestCategory("Runtime")]
365+
public void LinqOperationsOnDictionaryDocument()
366+
{
367+
// Create a complex dictionary document similar to WebAuthn responses
368+
var doc = new Document
369+
{
370+
{"credentialId", "abc123"},
371+
{"publicKey", "key-data"},
372+
{"signCount", 5},
373+
{"userVerified", true},
374+
{"attestationObject", new Document
375+
{
376+
{"fmt", "packed"},
377+
{"authData", "auth-data-bytes"}
378+
}
379+
}
380+
};
381+
382+
// Cast to IEnumerable<Document> to use LINQ operations
383+
var enumerable = (IEnumerable<Document>)doc;
384+
385+
// Test that we can use LINQ operations
386+
var count = enumerable.Count();
387+
Assert.AreEqual(5, count);
388+
389+
// Test FirstOrDefault
390+
var first = enumerable.FirstOrDefault();
391+
Assert.IsNotNull(first);
392+
393+
// Test Any
394+
Assert.IsTrue(enumerable.Any());
395+
396+
// Test Where (filtering)
397+
var stringValues = enumerable.Where(d => d.IsString()).ToList();
398+
Assert.IsTrue(stringValues.Count >= 2); // At least credentialId and publicKey
399+
400+
// Test Select (projection)
401+
var types = enumerable.Select(d => d.Type).ToList();
402+
Assert.AreEqual(5, types.Count);
269403
}
270404
}
271405
}

0 commit comments

Comments
 (0)