Skip to content

Commit b00bfce

Browse files
authored
Updated the request header sent to the OIDC endpoint so it doesn't result in a redirect response when an invalid system access token is provided. (Azure#46135)
* Updated the request header sent to the OIDC endpoint in so it doesn't result in a redirect response when an invalid system access token is provided. * Fix typo in header name and update test name. * Update TSG wording to match error, and fix assert. * Change the test back to returning void. * Update wording in TSG to reset CI.
1 parent adcbf3f commit b00bfce

File tree

4 files changed

+33
-1
lines changed

4 files changed

+33
-1
lines changed

sdk/identity/Azure.Identity/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
### Bugs Fixed
1010

11+
- Fixed the request sent in `AzurePipelinesCredential` so it doesn't result in a redirect response when an invalid system access token is provided.
12+
1113
### Other Changes
1214

1315
## 1.13.0-beta.2 (2024-09-17)

sdk/identity/Azure.Identity/TROUBLESHOOTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ You may also log in another MSA account by selecting "Microsoft account":
386386
| --- | --- | --- |
387387
| AADSTS900023: Specified tenant identifier `<some tenant ID>` is neither a valid DNS name, nor a valid external domain. | The tenant ID passed to the credential is invalid. | Verify the tenant ID is valid. If the service connection was configured via a user-assigned managed identity, the tenant will be the one in which managed identity was registered. If the service connection is configured via a service principal, the tenant should be the one in which the Service Principal is registered. |
388388
| No service connection found with identifier `<GUID>` | The service connection ID provided is incorrect. | Verify the serviceConnectionId provided. This parameter refers to the `resourceId` of the Azure Service Connection. It can also be found in the query string of the respective Service Connection's configuration page in Azure DevOps. More information about service connections can be found [here](https://learn.microsoft.com/azure/devops/pipelines/library/service-endpoints?view=azure-devops&tabs=yaml) |
389-
| AzurePipelinesCredential: Authentication Failed. oidcToken field not detected in the response. Response = Object moved to here. Status Code: 302. | The system access token seems to be malformed when passing in as a parameter to the credential. | `System.AccessToken` is a required system variable in the Azure Pipelines task and should be provided in the pipeline task, [as mentioned in the docs](https://learn.microsoft.com/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#systemaccesstoken). Verify that the system access token value provided is the predefined variable in Azure Pipelines and isn't malformed. |
389+
| AzurePipelinesCredential: Authentication Failed. OIDC token not found in response. Status Code: 401 (Unauthorized). | The system access token seems to be malformed when passed in as a parameter to the credential. | `System.AccessToken` is a required system variable in the Azure Pipelines task and should be provided in the pipeline task, [as mentioned in the docs](https://learn.microsoft.com/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#systemaccesstoken). Verify that the system access token value provided is the predefined variable in Azure Pipelines and isn't malformed. |
390390
| AzurePipelinesCredential: Authentication Failed. oidcToken field not detected in the response. Response = {"$id":"1","innerException":null,"message":"`<ACTUAL ERROR MESSAGE>`","typeName":"Microsoft.VisualStudio.Services.WebApi.VssInvalidPreviewVersionException, Microsoft.VisualStudio.Services.WebApi","typeKey":"VssInvalidPreviewVersionException","errorCode":0} | When the OIDC token request fails, the OIDC token api throws an error. More details about the specific error are specified in the "message" field of the Response as shown above. | Mitigation will usually depend on the scenario based on what [error message](https://learn.microsoft.com/azure/devops/pipelines/release/troubleshoot-workload-identity?view=azure-devops#error-messages) is being thrown. Make sure you use the [recommended Azure Pipelines task](https://learn.microsoft.com/azure/devops/pipelines/release/troubleshoot-workload-identity?view=azure-devops#review-pipeline-tasks). |
391391
| CredentialUnavailableError: AzurePipelinesCredential is not available: Ensure that you're running this task in an Azure Pipeline so that following missing system variable(s) can be defined: SYSTEM_OIDCREQUESTURI is not set. | This code is not running inside of the Azure Pipelines Environment. You may be running this code locally or on some other environment. | This credential is only designed to run from inside the Azure Pipelines environment for the federated identity to work. |
392392
| AuthenticationRequiredError: unauthorized_client: 700016 - AADSTS700016: Application with identifier 'clientId' was not found in the directory 'Microsoft'. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant.| The `clientId` provided is invalid. | Verify the client ID argument is valid. If the service connection's federated identity was registered via a user-assigned managed identity, the client ID of the managed identity should be provided. If the service connection's federated identity is registered via a Service Principal, the Application (client) ID from your app registration should be provided. |

sdk/identity/Azure.Identity/src/Credentials/AzurePipelinesCredential.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ internal HttpMessage CreateOidcRequestMessage(AzurePipelinesCredentialOptions op
116116
message.Request.Uri.Reset(requestUri);
117117
message.Request.Headers.SetValue(HttpHeader.Names.Authorization, $"Bearer {systemToken}");
118118
message.Request.Headers.SetValue(HttpHeader.Names.ContentType, "application/json");
119+
// Prevents the service from responding with a redirect HTTP status code (useful for automation).
120+
message.Request.Headers.SetValue("X-TFS-FedAuthRedirect", "Suppress");
119121
message.Request.Method = RequestMethod.Post;
120122
return message;
121123
}

sdk/identity/Azure.Identity/tests/AzurePipelinesCredentialLiveTests.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,33 @@ public async Task AzurePipelineCredentialLiveTest_GetToken()
4444

4545
Assert.IsNotNull(token.Token);
4646
}
47+
48+
[Test]
49+
[LiveOnly]
50+
public void AzurePipelineCredentialLiveTest_GetToken_InvalidSystemAccessToken()
51+
{
52+
string systemAccessToken = "invalidSystemAccessToken";
53+
var tenantId = Environment.GetEnvironmentVariable("AZURE_SERVICE_CONNECTION_TENANT_ID");
54+
var clientId = Environment.GetEnvironmentVariable("AZURE_SERVICE_CONNECTION_CLIENT_ID");
55+
var serviceConnectionId = Environment.GetEnvironmentVariable("AZURE_SERVICE_CONNECTION_ID");
56+
57+
if (string.IsNullOrEmpty(tenantId) || string.IsNullOrEmpty(clientId) || string.IsNullOrEmpty(serviceConnectionId))
58+
{
59+
var envVars = Environment.GetEnvironmentVariables();
60+
StringBuilder sb = new StringBuilder();
61+
foreach (var key in envVars.Keys)
62+
{
63+
sb.AppendLine($"{key}: {envVars[key]}");
64+
}
65+
Console.WriteLine(sb);
66+
Assert.Fail($"{sb} SYSTEM_ACCESSTOKEN: {systemAccessToken}, AZURE_SERVICE_CONNECTION_TENANT_ID: {tenantId}, AZURE_SERVICE_CONNECTION_CLIENT_ID: {clientId}, AZURE_SERVICE_CONNECTION_ID: {serviceConnectionId}");
67+
Assert.Ignore("AzurePipelinesCredentialLiveTests disabled because required environment variables are not set");
68+
}
69+
70+
var cred = new AzurePipelinesCredential(tenantId, clientId, serviceConnectionId, systemAccessToken);
71+
72+
var ex = Assert.ThrowsAsync<AuthenticationFailedException>(async () => await cred.GetTokenAsync(new TokenRequestContext(new[] { "https://management.azure.com//.default" }), CancellationToken.None));
73+
Assert.That(ex.Message, Does.Contain("not authorized"));
74+
}
4775
}
4876
}

0 commit comments

Comments
 (0)