Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions sdk/identity/azure-identity/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

### Other Changes

- [[#5141]](https://github.com/Azure/azure-sdk-for-cpp/issues/5141) Added error response details to the Identity exceptions thrown when the authority host returns error response.

## 1.6.0 (2023-11-10)

### Features Added
Expand Down
22 changes: 12 additions & 10 deletions sdk/identity/azure-identity/src/token_credential_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,13 @@ std::string TokenCredentialImpl::FormatScopes(

if (scopesIter != scopesEnd)
{
auto const scope = *scopesIter;
scopesStr += OptionalUrlEncode(scope, urlEncode);
}

for (++scopesIter; scopesIter != scopesEnd; ++scopesIter)
{
auto const Separator = std::string(" "); // Element separator never gets URL-encoded
scopesStr += OptionalUrlEncode(*scopesIter, urlEncode);

auto const scope = *scopesIter;
scopesStr += Separator + OptionalUrlEncode(scope, urlEncode);
constexpr auto Separator = " "; // Element separator never gets URL-encoded
for (++scopesIter; scopesIter != scopesEnd; ++scopesIter)
{
scopesStr += Separator + OptionalUrlEncode(*scopesIter, urlEncode);
}
}
}

Expand Down Expand Up @@ -117,11 +114,16 @@ AccessToken TokenCredentialImpl::GetToken(
request = shouldRetry(statusCode, *response);
if (request == nullptr)
{
auto const bodyStream = response->ExtractBodyStream();
auto const bodyVec = bodyStream ? bodyStream->ReadToEnd(context) : response->GetBody();
auto const responseBody
= std::string(reinterpret_cast<char const*>(bodyVec.data()), bodyVec.size());

throw std::runtime_error(
std::string("error response: ")
+ std::to_string(
static_cast<std::underlying_type<decltype(statusCode)>::type>(statusCode))
+ " " + response->GetReasonPhrase());
+ " " + response->GetReasonPhrase() + "\n\n" + responseBody);
}

response.reset();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,49 @@ TEST(TokenCredentialImpl, MaxValues)
std::exception);
}

TEST(TokenCredentialImpl, AuthErrorResponse)
{
std::string const errorJson
= "{\"error\":\"invalid_request\","
"\"error_description\":\"AADSTS90014: "
"The required field 'scope' is missing from the credential. "
"Ensure that you have all the necessary parameters for the login request. "
"Trace ID: 01234567-89ab-cdef-0123-456789abcdef "
"Correlation ID: fedcba98-7654-3210-0123-456789abcdef "
"Timestamp: 2023-11-30 00:51:37Z\","
"\"error_codes\":[90014],"
"\"timestamp\":\"2023-11-30 00:51:37Z\","
"\"trace_id\":\"01234567-89ab-cdef-0123-456789abcdef\","
"\"correlation_id\":\"fedcba98-7654-3210-0123-456789abcdef\","
"\"error_uri\":\"https://login.microsoftonline.com/error?code=90014\"}";

try
{
using Azure::Core::Http::HttpStatusCode;
std::vector<std::string> const testScopes;
CredentialTestHelper::TokenRequestSimulationServerResponse testResponse;
testResponse.StatusCode = HttpStatusCode::BadRequest;
testResponse.Body = errorJson;

static_cast<void>(CredentialTestHelper::SimulateTokenRequest(
[](auto transport) {
TokenCredentialOptions options;
options.Transport.Transport = transport;

return std::make_unique<TokenCredentialImplTester>(
HttpMethod::Delete, Url("https://outlook.com/"), options);
},
{testScopes},
{testResponse}));

EXPECT_TRUE(!"TokenCredentialImpl should throw given the response above.");
}
catch (AuthenticationException const& ex)
{
EXPECT_EQ(ex.what(), "GetToken(): error response: 400 Test\n\n" + errorJson);
}
}

TEST(TokenCredentialImpl, Diagnosability)
{
using Azure::Core::Diagnostics::Logger;
Expand Down