【问题标题】:C# OAuth batch multipart content response, how to get all the contents not as string objectsC# OAuth批量多部分内容响应,如何获取所有内容而不是字符串对象
【发布时间】:2017-01-20 09:19:44
【问题描述】:

我收到属于 OAuth 批处理请求的多部分内容响应:

// batchRequest is a HttpRequestMessage, http is an HttpClient
HttpResponseMessage response = await http.SendAsync(batchRequest);

如果我将其内容作为全文阅读:

string fullResponse = await response.Content.ReadAsStringAsync();

这是它包含的内容:

--batchresponse_e42a30ca-0f3a-4c17-8672-22abc469cd16
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 200 OK
DataServiceVersion: 3.0;
Content-Type: application/json;odata=minimalmetadata;streaming=true;charset=utf-8

{\"odata.metadata\":\"https://graph.windows.net/XXX.onmicrosoft.com/$metadata#directoryObjects/@Element\",\"odata.type\":\"Microsoft.DirectoryServices.User\",\"objectType\":\"User\",\"objectId\":\"5f6851c3-99cc-4a89-936d-4bb44fa78a34\",\"deletionTimestamp\":null,\"accountEnabled\":true,\"signInNames\":[],\"assignedLicenses\":[],\"assignedPlans\":[],\"city\":null,\"companyName\":null,\"country\":null,\"creationType\":null,\"department\":\"NRF\",\"dirSyncEnabled\":null,\"displayName\":\"dummy1 Test\",\"facsimileTelephoneNumber\":null,\"givenName\":\"dummy1\",\"immutableId\":null,\"isCompromised\":null,\"jobTitle\":\"test\",\"lastDirSyncTime\":null,\"mail\":null,\"mailNickname\":\"dummy1test\",\"mobile\":null,\"onPremisesSecurityIdentifier\":null,\"otherMails\":[],\"passwordPolicies\":null,\"passwordProfile\":{\"password\":null,\"forceChangePasswordNextLogin\":true,\"enforceChangePasswordPolicy\":false},\"physicalDeliveryOfficeName\":null,\"postalCode\":null,\"preferredLanguage\":null,\"provisionedPlans\":[],\"provisioningErrors\":[],\"proxyAddresses\":[],\"refreshTokensValidFromDateTime\":\"2016-12-02T08:37:24Z\",\"showInAddressList\":null,\"sipProxyAddress\":null,\"state\":\"California\",\"streetAddress\":null,\"surname\":\"Test\",\"telephoneNumber\":\"666\",\"thumbnailPhoto@odata.mediaEditLink\":\"directoryObjects/5f6851c3-99cc-4a89-936d-4bb44fa78a34/Microsoft.DirectoryServices.User/thumbnailPhoto\",\"usageLocation\":null,\"userPrincipalName\":\"dummy1test@XXX.onmicrosoft.com\",\"userType\":\"Member\"}
--batchresponse_e42a30ca-0f3a-4c17-8672-22abc469cd16
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 200 OK
DataServiceVersion: 3.0;
Content-Type: application/json;odata=minimalmetadata;streaming=true;charset=utf-8

{\"odata.metadata\":\"https://graph.windows.net/XXX.onmicrosoft.com/$metadata#directoryObjects/@Element\",\"odata.type\":\"Microsoft.DirectoryServices.User\",\"objectType\":\"User\",\"objectId\":\"dd35d761-e6ed-44e7-919f-f3b1e54eb7be\",\"deletionTimestamp\":null,\"accountEnabled\":true,\"signInNames\":[],\"assignedLicenses\":[],\"assignedPlans\":[],\"city\":null,\"companyName\":null,\"country\":null,\"creationType\":null,\"department\":null,\"dirSyncEnabled\":null,\"displayName\":\"Max Admin\",\"facsimileTelephoneNumber\":null,\"givenName\":null,\"immutableId\":null,\"isCompromised\":null,\"jobTitle\":null,\"lastDirSyncTime\":null,\"mail\":null,\"mailNickname\":\"maxadmin\",\"mobile\":null,\"onPremisesSecurityIdentifier\":null,\"otherMails\":[],\"passwordPolicies\":null,\"passwordProfile\":null,\"physicalDeliveryOfficeName\":null,\"postalCode\":null,\"preferredLanguage\":null,\"provisionedPlans\":[],\"provisioningErrors\":[],\"proxyAddresses\":[],\"refreshTokensValidFromDateTime\":\"2016-12-05T15:11:51Z\",\"showInAddressList\":null,\"sipProxyAddress\":null,\"state\":null,\"streetAddress\":null,\"surname\":null,\"telephoneNumber\":null,\"thumbnailPhoto@odata.mediaEditLink\":\"directoryObjects/dd35d761-e6ed-44e7-919f-f3b1e54eb7be/Microsoft.DirectoryServices.User/thumbnailPhoto\",\"usageLocation\":null,\"userPrincipalName\":\"maxadmin@XXX.onmicrosoft.com\",\"userType\":\"Member\"}
--batchresponse_e42a30ca-0f3a-4c17-8672-22abc469cd16--

我需要将所有这些内容作为对象获取(如经典的HttpResponseMessage,而不是简单的字符串),以便获取HTTP返回码、JSON内容等作为属性并能够对其进行处理。

我知道如何分别读取所有这些内容,但我不知道如何将它们作为对象获取,我只成功获取了字符串内容:

var multipartContent = await response.Content.ReadAsMultipartAsync();
foreach (HttpContent currentContent in multipartContent.Contents) {
     var testString = currentContent.ReadAsStringAsync();
     // How to get this content as an exploitable object?
}

在我的示例中,testString 包含:

HTTP/1.1 200 OK
DataServiceVersion: 3.0;
Content-Type: application/json;odata=minimalmetadata;streaming=true;charset=utf-8

{\"odata.metadata\":\"https://graph.windows.net/XXX.onmicrosoft.com/$metadata#directoryObjects/@Element\",\"odata.type\":\"Microsoft.DirectoryServices.User\",\"objectType\":\"User\",\"objectId\":\"5f6851c3-99cc-4a89-936d-4bb44fa78a34\",\"deletionTimestamp\":null,\"accountEnabled\":true,\"signInNames\":[],\"assignedLicenses\":[],\"assignedPlans\":[],\"city\":null,\"companyName\":null,\"country\":null,\"creationType\":null,\"department\":\"NRF\",\"dirSyncEnabled\":null,\"displayName\":\"dummy1 Test\",\"facsimileTelephoneNumber\":null,\"givenName\":\"dummy1\",\"immutableId\":null,\"isCompromised\":null,\"jobTitle\":\"test\",\"lastDirSyncTime\":null,\"mail\":null,\"mailNickname\":\"dummy1test\",\"mobile\":null,\"onPremisesSecurityIdentifier\":null,\"otherMails\":[],\"passwordPolicies\":null,\"passwordProfile\":{\"password\":null,\"forceChangePasswordNextLogin\":true,\"enforceChangePasswordPolicy\":false},\"physicalDeliveryOfficeName\":null,\"postalCode\":null,\"preferredLanguage\":null,\"provisionedPlans\":[],\"provisioningErrors\":[],\"proxyAddresses\":[],\"refreshTokensValidFromDateTime\":\"2016-12-02T08:37:24Z\",\"showInAddressList\":null,\"sipProxyAddress\":null,\"state\":\"California\",\"streetAddress\":null,\"surname\":\"Test\",\"telephoneNumber\":\"666\",\"thumbnailPhoto@odata.mediaEditLink\":\"directoryObjects/5f6851c3-99cc-4a89-936d-4bb44fa78a34/Microsoft.DirectoryServices.User/thumbnailPhoto\",\"usageLocation\":null,\"userPrincipalName\":\"dummy1test@XXX.onmicrosoft.com\",\"userType\":\"Member\"}

我无法想象手动解析这个字符串......所以如果有人有线索或可以向我解释阅读内容的好方法,那就太好了。

谢谢, 最大

【问题讨论】:

    标签: c# oauth httpresponsemessage


    【解决方案1】:

    这是一种可以做到的方法。关键是在响应中添加一个新的内容类型“msgtype”标头:

    var multipartContent = await response.Content.ReadAsMultipartAsync();
    var multipartRespMsgs = new List<HttpResponseMessage>();
    foreach (HttpContent currentContent in multipartContent.Contents) {
        // Two cases:
        // 1. a "single" response
        if (currentContent.Headers.ContentType.MediaType.Equals("application/http", StringComparison.OrdinalIgnoreCase)) {
            if (!currentContent.Headers.ContentType.Parameters.Any(parameter => parameter.Name.Equals("msgtype", StringComparison.OrdinalIgnoreCase) && parameter.Value.Equals("response", StringComparison.OrdinalIgnoreCase))) {
                currentContent.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("msgtype", "response"));
            }
            multipartRespMsgs.Add(await currentContent.ReadAsHttpResponseMessageAsync());
            // The single object in multipartRespMsgs contains a classic exploitable HttpResponseMessage (with IsSuccessStatusCode, Content.ReadAsStringAsync().Result, etc.)
        }
        // 2. a changeset response, which is an embedded multipart content
        else {
            var subMultipartContent = await currentContent.ReadAsMultipartAsync();
            foreach (HttpContent currentSubContent in subMultipartContent.Contents) {
                currentSubContent.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("msgtype", "response"));
                multipartRespMsgs.Add(await currentSubContent.ReadAsHttpResponseMessageAsync());
                // Same here, the objects in multipartRespMsgs contain classic exploitable HttpResponseMessages
            }
        }
    }
    

    Thanks to darl0026

    【讨论】:

    • 添加“msgtype”参数对我有用并节省了我的一天。谢了!
    • 如果我没看错,您的代码中有一个小错误:案例 1. 只有在 msgtype 参数不存在时才会触发。如果 Headers.ContentType 已经包含“application/http; msgtype=response”,那么您会遇到案例 2,这是错误的。相反,您应该只检查“application/http”以识别案例 1,然后使用第二个内部 if/then 来决定是否必须添加“msgtype=response”。
    • @Jpsy 你是对的,谢谢!因为这段代码刚刚被用于 PoC(后面是……什么都没有),显然它还没有经过足够的测试
    • @MaxXapi:我冒昧地更正了您的代码。我添加了一个内部 if 子句,它仅在缺少 msgtype=response 时才添加它。我还更改了变量以将传入的 HttpResponseMessages 存储为 List 类型,因此它可以在 2. 情况下保存多个响应。此代码在生产中进行了测试。 (希望我在适应你的变量名时没有引入错别字。:D)
    • @Jpsy 很高兴您已更正它!自从我在这里发帖以来,我没有研究这个主题,它在我的脑海中并不新鲜,所以我没有足够的时间回到这个主题并纠正错误并做一些改进。正确/更好的代码会更有帮助,谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-02
    • 2021-09-03
    • 1970-01-01
    • 2021-12-02
    • 2011-07-30
    • 2018-08-08
    • 2021-09-14
    相关资源
    最近更新 更多