aws / aws-sdk-cpp

AWS SDK for C++
Apache License 2.0
1.97k stars 1.06k forks source link

Aws::Organizations::OrganizationsClient::DescribeOrganization API not working as expected #2631

Closed japsingh closed 1 year ago

japsingh commented 1 year ago

Describe the bug

This code results in error response:

        Aws::SDKOptions options;
        Aws::InitAPI(options);
        Aws::Client::ClientConfiguration config;

        auto credprovider = std::make_shared<Aws::Auth::InstanceProfileCredentialsProvider>();

        Aws::Organizations::OrganizationsClient cl(credprovider, config);
        auto out = cl.DescribeOrganization();
        if (!out.IsSuccess()) {
            std::cerr << "Error getting EC2 organization metadata: " << out.GetError().GetMessage();
            Aws::ShutdownAPI(options);
            return;
        }
        auto res = out.GetResult();
        auto org = res.GetOrganization();
        std::cout << "Organization-id(AWS): " << std::string(org.GetId().c_str());

        Aws::ShutdownAPI(options);

Expected Behavior

On an EC2 instance where the following AWS CLI command works well:

C:\Users\Administrator>aws organizations describe-organization
{
    "Organization": {
        "Id": "o-xxxxxxxxx",
        "Arn": "arn:aws:organizations::xxxxxxxxxx:organization/o-xxxxxxxxx",
        "FeatureSet": "ALL",
        "MasterAccountArn": "arn:aws:organizations::xxxxxxxxxx:account/o-xxxxxxxxxxx/xxxxxxxxxxxx",
        "MasterAccountId": "xxxxxxxxxxxx",
        "MasterAccountEmail": "xxxxxxxxxxxxxx",
        "AvailablePolicyTypes": [
            {
                "Type": "xxxxxxxxxxxxxxxxxx",
                "Status": "ENABLED"
            }
        ]
    }
}

Trying to run the C++ code mentioned in the bug description should successfully describe the organization.

Current Behavior

However, the code mentioned in the bug description doesn't work. It leads to following error:

Failed to parse error payload: <UnknownOperationException>
  <Message>The action or operation requested is invalid. Verify that the action is typed correctly.</Message>

Reproduction Steps

This code results in error

// ConsoleApplication1.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include <iostream>
#include <aws/core/Aws.h>
#include <aws/core/auth/AWSCredentialsProvider.h>
#include <aws/core/utils/Outcome.h>
#include <aws/core/http/HttpClientFactory.h>
#include <aws/core/http/HttpClient.h>
#include <aws/core/http/standard/StandardHttpRequest.h>
#include <aws/core/http/standard/StandardHttpResponse.h>
#include <aws/organizations/model/DescribeOrganizationResult.h>
#include <aws/organizations/model/DescribeOrganizationalUnitResult.h>
#include <aws/organizations/model/DescribeOrganizationalUnitRequest.h>
#include <aws/organizations/model/ListRootsRequest.h>
#include <aws/organizations/model/ListRootsResult.h>
#include <aws/organizations/OrganizationsClient.h>

int main()
{
    Aws::SDKOptions options;
    Aws::InitAPI(options);
    Aws::Client::ClientConfiguration config;

    auto credprovider = std::make_shared<Aws::Auth::InstanceProfileCredentialsProvider>();

    Aws::Organizations::OrganizationsClient cl(credprovider, config);
    auto out = cl.DescribeOrganization();
    if (!out.IsSuccess()) {
        std::cerr << "Error getting organization metadata: " << out.GetError().GetMessage();
        Aws::ShutdownAPI(options);
        return 0;
    }
    auto res = out.GetResult();
    auto org = res.GetOrganization();
    std::cout << "Organization-id(AWS): " << std::string(org.GetId().c_str());

    Aws::ShutdownAPI(options);

    return 0;
}

Possible Solution

As per my debugging, the error is due to a missing header. When I try to run following command via AWS CLI: aws organizations describe-organizations

and use Burrp suite to check which headers are added by AWS CLI, then diff with the headers added by the code I shared, then I observe the following header is missing when calling the CPP code to DescribeOrganization():

X-Amz-Target: AWSOrganizationsV20161128.DescribeOrganization

I tried adding the header by creating my own HTTP client by setting

Aws::SDKOptions options;
options.httpOptions.httpClientFactory_create_fn = ...

However, that doesn't work, because the headers are signed before sending in the HTTP request, and therefore the addition of header needs to happen in the SDK, before HTTP header signing takes place.

I see that for other requests like ListRootsRequest, header like this is added in the SDK code:

Aws::Http::HeaderValueCollection ListRootsRequest::GetRequestSpecificHeaders() const
{
  Aws::Http::HeaderValueCollection headers;
  headers.insert(Aws::Http::HeaderValuePair("X-Amz-Target", "AWSOrganizationsV20161128.ListRoots"));
  return headers;

}

But, there is no DescribeOrganizationRequest class which can do this job of adding X-Amz-Target header. I think the fix is to create DescribeOrganizationRequest class which adds the correct X-Amz-Target header.

Additional Information/Context

No response

AWS CPP SDK version used

1.11.132

Compiler and Version used

Visual Studio 2019

Operating System and version

Windows 2022 Server

yasminetalby commented 1 year ago

Hello @japsingh ,

Thank you very much for your detailed submission.

You are right, per the AWS Organizations documentation, the DescribeOrganization request does require the X-Amz-Target header.

If you look at the code for the DescribeOrganizationRequest:

Aws::Http::HeaderValueCollection DescribeOrganizationRequest::GetRequestSpecificHeaders() const
{
  Aws::Http::HeaderValueCollection headers;
  headers.insert(Aws::Http::HeaderValuePair("X-Amz-Target", "WorkMailService.DescribeOrganization"));
  return headers;
}

We do set X-Amz-Target header as part of our request process.

However, it seems that the request is requestless and doesn't have input specified (see). Because this is generated code from the service team, we need to investigate the issue further to provide a fix.

Thank you very much for bringing this up to our attention.

We will provide updates here.

Best regards,

Yasmine

japsingh commented 1 year ago

Hi @yasminetalby, thanks for looking into this and responding. The code you shared seems to be from a different SDK aws-cpp-sdk-workmail, while I am trying to use aws-cpp-sdk-organizations. Also, i have observed the X-Amz-Target headers for other Organizations requests are formatted like "AWSOrganizationsV20161128.xxxxxxxxxxxxxx", while the one you shared starts with "WorkMailService.xxxxxxxxxxxx".

I am not sure if both services are linked in any way, my suspect is that "WorkMailService organization" might be a different concept than "AWS organization". I believe a proper fix should be in aws-sdk-cpp-organizations lib instead.

mgrandis commented 1 year ago

@japsingh It may come from the Content-Type header which should be application/x-amz-json-1.1.

Had the same error with application/json, changed it to the Content-Type above and it worked (direct API query using Insomnia).

yasminetalby commented 1 year ago

Hello @japsingh ,

Thank you very much for your answer. You are right, this is an overlook on my end the DescribeOrganizationRequest sample I have linked is for aws-cpp-sdk-workmail. The issue is still the same: the request object currently doesn't have an input specified in the service generated code sample.

We are currently working on a fix for this issue.

I will keep you updated here! Thank you very much for your feedback and for bringing this up to our attention.

Best regards,

Yasmine

sbiscigl commented 1 year ago

fix has been merged and will be tagged as part of this days release, give a shout if you have any questions

github-actions[bot] commented 1 year ago

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.

japsingh commented 1 year ago

Thank you for fixing this so fast :)