Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[identity] add support for AZURE_CLIENT_SEND_CERTIFICATE_CHAIN env var #30570

Merged
merged 2 commits into from
Jul 30, 2024
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/identity/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

### Features Added

- Added support in `EnvironmentCredential` and `DefaultAzureCredential` for `AZURE_CLIENT_SEND_CERTIFICATE_CHAIN` environment variable to configure subject name / issuer authentication. [#30570](https://github.com/Azure/azure-sdk-for-js/pull/30570)

### Breaking Changes

### Bugs Fixed
Expand Down
16 changes: 15 additions & 1 deletion sdk/identity/identity/src/credentials/environmentCredential.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const AllSupportedEnvironmentVariables = [
"AZURE_USERNAME",
"AZURE_PASSWORD",
"AZURE_ADDITIONALLY_ALLOWED_TENANTS",
"AZURE_CLIENT_SEND_CERTIFICATE_CHAIN",
];

function getAdditionallyAllowedTenants(): string[] {
Expand All @@ -38,6 +39,17 @@ function getAdditionallyAllowedTenants(): string[] {
const credentialName = "EnvironmentCredential";
const logger = credentialLogger(credentialName);

export function getSendCertificateChain(): boolean {
const sendCertificateChain = (
process.env.AZURE_CLIENT_SEND_CERTIFICATE_CHAIN ?? ""
).toLowerCase();
const result = sendCertificateChain === "true" || sendCertificateChain === "1";
logger.verbose(
`AZURE_CLIENT_SEND_CERTIFICATE_CHAIN: ${process.env.AZURE_CLIENT_SEND_CERTIFICATE_CHAIN}; sendCertificateChain: ${result}`,
);
return result;
}

/**
* Enables authentication to Microsoft Entra ID using a client secret or certificate, or as a user
* with a username and password.
Expand All @@ -61,6 +73,7 @@ export class EnvironmentCredential implements TokenCredential {
* - `AZURE_CLIENT_SECRET`: A client secret that was generated for the App Registration.
* - `AZURE_CLIENT_CERTIFICATE_PATH`: The path to a PEM certificate to use during the authentication, instead of the client secret.
* - `AZURE_CLIENT_CERTIFICATE_PASSWORD`: (optional) password for the certificate file.
* - `AZURE_CLIENT_SEND_CERTIFICATE_CHAIN`: (optional) indicates that the certificate chain should be set in x5c header to support subject name / issuer based authentication.
*
* Alternatively, users can provide environment variables for username and password authentication:
* - `AZURE_USERNAME`: Username to authenticate with.
Expand All @@ -82,7 +95,8 @@ export class EnvironmentCredential implements TokenCredential {
clientSecret = process.env.AZURE_CLIENT_SECRET;

const additionallyAllowedTenantIds = getAdditionallyAllowedTenants();
const newOptions = { ...options, additionallyAllowedTenantIds };
const sendCertificateChain = getSendCertificateChain();
const newOptions = { ...options, additionallyAllowedTenantIds, sendCertificateChain };

if (tenantId) {
checkTenantId(logger, tenantId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import Sinon from "sinon";
import { assert } from "@azure-tools/test-utils";
import { getSendCertificateChain } from "../../../src/credentials/environmentCredential";

describe("EnvironmentCredential (internal)", function () {
afterEach(function () {
Sinon.restore();
});

describe("#getSendCertificateChain", () => {
it("should parse 'true' correctly", async () => {
Sinon.stub(process, "env").value({
AZURE_CLIENT_SEND_CERTIFICATE_CHAIN: "true",
});

const sendCertificateChain = getSendCertificateChain();
assert.isTrue(sendCertificateChain);
});

it("should parse '1' correctly", async () => {
Sinon.stub(process, "env").value({
AZURE_CLIENT_SEND_CERTIFICATE_CHAIN: "1",
});

const sendCertificateChain = getSendCertificateChain();
assert.isTrue(sendCertificateChain);
});

it("is case insensitive", async () => {
Sinon.stub(process, "env").value({
AZURE_CLIENT_SEND_CERTIFICATE_CHAIN: "TrUe",
});

const sendCertificateChain = getSendCertificateChain();
assert.isTrue(sendCertificateChain);
});

it("should parse undefined correctly", async () => {
Sinon.stub(process, "env").value({});

const sendCertificateChain = getSendCertificateChain();
assert.isFalse(sendCertificateChain);
});

it("should default other values to false", async () => {
Sinon.stub(process, "env").value({
AZURE_CLIENT_SEND_CERTIFICATE_CHAIN: "foobar",
});

const sendCertificateChain = getSendCertificateChain();
assert.isFalse(sendCertificateChain);
});
});
});