duosecurity/duo_api_csharp

JSON parsing issue

tecssil opened this issue · 5 comments

The api is not able to deserialize a response that contains a Token object, on the get users call.

Message: 
Duo.BadResponseException : Got error 'The JSON value could not be converted to System.String. Path: $.response[0].tokens[0] | LineNumber: 0 | BytePositionInLine: 3598.' with HTTP Status 200. Response : {"metadata": {"next_offset": 1, "total_objects": 531}, "response": [{"alias1": "john.doe@mail.com", "alias2": null, "alias3": null, "alias4": null, "aliases": {"alias1": "john.doe@mail.com"}, "created": 1562778837, "desktoptokens": [], "email": "john.doe@mail.com", "firstname": "John", "groups": [{"desc": "", "group_id": "123456789", "mobile_otp_enabled": false, "name": "Info (from AD sync \"INFO\")", "push_enabled": false, "sms_enabled": false, "status": "Active", "voice_enabled": false}, {"desc": "", "group_id": "123456789", "mobile_otp_enabled": false, "name": "DUO (from AD sync \"INFO\")", "push_enabled": false, "sms_enabled": false, "status": "Active", "voice_enabled": false}, {"desc": "", "group_id": "123456789", "mobile_otp_enabled": false, "name": "Dropbox (from AD sync \"INFO\")", "push_enabled": false, "sms_enabled": false, "status": "Active", "voice_enabled": false}, {"desc": "", "group_id": "123456789", "mobile_otp_enabled": false, "name": "Duo_Admin (from AD sync \"INFO\")", "push_enabled": false, "sms_enabled": false, "status": "Active", "voice_enabled": false}, {"desc": "", "group_id": "123456789", "mobile_otp_enabled": false, "name": "Duo (from AD sync \"INFO\")", "push_enabled": false, "sms_enabled": false, "status": "Active", "voice_enabled": false}, {"desc": "", "group_id": "123456789", "mobile_otp_enabled": false, "name": "MobiControl (from AD sync \"INFO\")", "push_enabled": false, "sms_enabled": false, "status": "Active", "voice_enabled": false}, {"desc": "", "group_id": "123456789", "mobile_otp_enabled": false, "name": "RServer (from AD sync \"INFO)\")", "push_enabled": false, "sms_enabled": false, "status": "Active", "voice_enabled": false}, {"desc": "", "group_id": "123456789", "mobile_otp_enabled": false, "name": "RServer_Devs (from AD sync \"INFO\")", "push_enabled": false, "sms_enabled": false, "status": "Active", "voice_enabled": false}, {"desc": "", "group_id": "123456789", "mobile_otp_enabled": false, "name": "TIS (from AD sync \"INFO\")", "push_enabled": false, "sms_enabled": false, "status": "Active", "voice_enabled": false}, {"desc": "", "group_id": "123456789", "mobile_otp_enabled": false, "name": "VPN (from AD sync \"INFO\")", "push_enabled": false, "sms_enabled": false, "status": "Active", "voice_enabled": false}, {"desc": "", "group_id": "123456789", "mobile_otp_enabled": false, "name": "VPN (from AD sync \"INFO\")", "push_enabled": false, "sms_enabled": false, "status": "Active", "voice_enabled": false}, {"desc": "", "group_id": "123456789", "mobile_otp_enabled": false, "name": "VPN (from AD sync \"INFO\")", "push_enabled": false, "sms_enabled": false, "status": "Active", "voice_enabled": false}], "is_enrolled": true, "last_directory_sync": 1681294065, "last_login": 1681262284, "lastname": "Doe", "notes": "", "phones": [{"activated": true, "capabilities": ["auto", "push", "sms", "phone", "mobile_otp"], "encrypted": "Encrypted", "extension": "", "fingerprint": "Disabled", "last_seen": "2023-04-12T01:17:56", "model": "Apple iPhone 13", "name": "", "number": "+123456789", "phone_id": "123456789", "platform": "Apple iOS", "postdelay": "", "predelay": "", "screenlock": "Locked", "sms_passcodes_sent": false, "tampered": "Not tampered", "type": "Mobile"}], "realname": "Doe, John", "status": "active", "tokens": [{"serial": "*****************", "token_id": "********************", "totp_step": null, "type": "d1"}], "u2ftokens": [], "user_id": "123456789", "username": "doej", "webauthncredentials": []}], "stat": "OK"}
---- System.Text.Json.JsonException : The JSON value could not be converted to System.String. Path: $.response[0].tokens[0] | LineNumber: 0 | BytePositionInLine: 3598.
-------- System.InvalidOperationException : Cannot get the value of a token type 'StartObject' as a string.

  Stack Trace: 
DuoApi.BaseJSONApiCall[T](String method, String path, Dictionary`2 parameters, Int32 timeout, DateTime date, PagingInfo& metaData) line 436
DuoApi.JSONPagingApiCall[T](String method, String path, Dictionary`2 parameters, Int32 offset, Int32 limit, Int32 timeout, DateTime date, PagingInfo& metaData) line 544
DuoApi.JSONPagingApiCall[T](String method, String path, Dictionary`2 parameters, Int32 offset, Int32 limit, PagingInfo& metaData) line 502
DuoApi.GetUsers(UInt16 limit, PagingInfo& pagingInfo, UInt16 offset) line 27
TestRealAPICall.GetUsers(UInt16 pagesize, UInt16 offset) line 50
----- Inner Stack Trace -----
ThrowHelper.ReThrowWithPath(ReadStack& state, Utf8JsonReader& reader, Exception ex)
JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 utf8Json, JsonTypeInfo jsonTypeInfo, Nullable`1 actualByteCount)
JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 json, JsonTypeInfo jsonTypeInfo)
JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options)
DuoApi.BaseJSONApiCall[T](String method, String path, Dictionary`2 parameters, Int32 timeout, DateTime date, PagingInfo& metaData) line 409
----- Inner Stack Trace -----
ThrowHelper.ThrowInvalidOperationException_ExpectedString(JsonTokenType tokenType)
Utf8JsonReader.GetString()
StringConverter.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
JsonCollectionConverter`2.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TCollection& value)
JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
JsonCollectionConverter`2.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TCollection& value)
JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)

Update:
The problem it's solve changing the User class parameter Token to a object[] instead of a string[]

@tecssil I'll take a look at this. As you can probably tell, this client doesn't get a lot of attention unfortunately. Just to make sure I'm looking at the right thing, can you confirm which API call you were using? It looks to me like it was https://duo.com/docs/adminapi#retrieve-users but I want to make sure.