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] Use environment variable for password for PEM #22782

Merged
merged 5 commits into from
Aug 2, 2022
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
1 change: 1 addition & 0 deletions sdk/identity/identity/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
src/**/*.js
!assets/fake-cert.pem
!assets/fake-cert-password.pem
58 changes: 58 additions & 0 deletions sdk/identity/identity/assets/fake-cert-password.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
Bag Attributes
localKeyID: F3 93 1A AD 84 1C D7 2E F3 20 08 C7 7D A9 ED B0 3D 29 4E F7
subject=/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd
issuer=/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd
-----BEGIN CERTIFICATE-----
MIIDbTCCAlWgAwIBAgIUHBH8mppwjLI2dFOQ7haLnd6iRjQwDQYJKoZIhvcNAQEL
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yMDAxMDMxODE2MzlaGA8yMTk5
MDYwODE4MTYzOVowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBANMXamdgXR+0B2b6zt2nURcYcwC0YrqjvTH/ofF3
MjUzZ1uKziPNxxAYrUY0O0zIcZWo9Aqfi10vS5oNya/aDrKoWxVRCsLltAV9dbLJ
65zF7wbVE7ZnZ7Nknop+ytd1t1VNTlpbxgWdT6z/WTn4ydqH7Hlh0Ucu2Q3QGQL3
G9He0kOMog4Y0myxP2xNGjLoig2kh60KEwtxbudOxVN4rLpqhT/1n/L5s+7rznKc
cB4MRqPJMdycIYhTD2mfp/E9hDWRcVJY+9GlqzyxXFTsDsO1SzGgpMEjdO5mtc6N
A0dd8fZQLt1BHLFJlpsuk5Fk40y7HtT3kYKUcD55Xd0pd6ECAwEAAaNTMFEwHQYD
VR0OBBYEFKG65qd+cChhFLB8y4po+vL3HwxuMB8GA1UdIwQYMBaAFKG65qd+cChh
FLB8y4po+vL3HwxuMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
AAlEqWO8tGKprQrqfdZDsMyKyne+WYYA7RqRxYzKJ5j1zsPa4f7RKhLYzx6TqWK3
keBc6aw9aeNYNqTBeDLGHRHRRwdHwwU5HdqowhE0sEQzOIJvs2JK5L+LcoSkTViy
PzidZ0qoAHRluuFw8Ag9sahcQfao6rqJOFY/16KEjDthATGo/4mHRsuAM+xza+2m
GbqJH/iO/q0lsPb3culm8aoJNxULTHrU5YWhuGvRypSYrfdL7RBkzW4VEt5LcRK6
KcfmfHMrjPl/XxSSvrBmly7nYNH80DGSMRP/lnrQ8OS+hSiDy1KBaCcNhja5Dyzn
K0dXlMGmWrnDMs8m+4cUoIM=
-----END CERTIFICATE-----
Bag Attributes
mpodwysocki marked this conversation as resolved.
Show resolved Hide resolved
localKeyID: F3 93 1A AD 84 1C D7 2E F3 20 08 C7 7D A9 ED B0 3D 29 4E F7
Key Attributes: <No Attributes>
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIFMcFVFpHnS0CAggA
MBQGCCqGSIb3DQMHBAi+r+wNWXgmYASCBMiZWRwBAkRI+CPrAf5OQ6v8SiEW3L4v
zLze/kzHFM+9u2fK7svyLYspNAUrnOKGl/LXupdGxa6kvJba4rPNGGjpwLoHx/Hr
f3UOXlwLNs3KD+cSrL2/XBLciW6qLESZ6BIsOy8siTjeaOY0lyTkzI3uKZ2sqA3F
RlS81uKK5B7iksBNIhYx32MN0FgRRsaAie3CTXnbf9yB2fQO/042n50UbOXnHTkl
NpnKqgGlp4Ilog6aGnyRUBHrxHgkdpEUACTgSnEgDX3rs2xcaprCns0Pr+8KJLAF
qrmFBcxYKct1pFx/PtKO65uVmTjLHWsZL5qkTAn70V2Hc728dijMcMdPcycQ5Kvi
1PLajlkO+WgGS0Q2u9FsJ5ojikc4CiHuC46Y3H/MprhCwXnrA65yNUbiY66iDN5n
sXCK9DGL3STk3Dfcyan102aXErTJYSbAddK0cPOnkJTcoONxFZP2uxoJsrWeSH9n
xp08FJvW6oqBS3RBWlMugtQ4dRs3bbsg1YrGodunOgK0ZxAT9/Kn8rg/KUM5Yiz6
K20DXw8Qbzj0tq7nggyd9yVSjR0oSZ9uFzhehzT3TzhjBtBCcFD/M3sJoZVmCMDg
XslIPDxJlAlkZ14rmFrSRUBUcXHhmAMq85taocSVejw7ntA1mTa3G6Os2tW0ObfJ
1uoRUCM/bK7jR25BVlpI9cxJe32e6IGTQvEoqY051GYn/LkwWcTEdaYOLg7JsqUP
yMvLn+qjSbPaG7e/yKASP9EOs1Bi4pb6OcXIv9YVmujhbNJRSNRc8aW85nJ3M56x
v9r8WBV6IooyOH9UslNqt7DYzgCxvNWgp1E6WGrlWJMyfmgEjQCLYhmQJZU+lWCg
LOwEfcZgnCItNjI/JCv+bB9WkJqbsLvDT9ae7oVIwMlXNyuacKMbCuWsrG4C4JqN
xzjCSangAN+0AouqLUGIL+k8NUGLkrt5yBsnUxvltSwmneVos/SW5CzAuP95PvsN
FV8LTi0T7YB8YssklP/u+j6tdtERt7EaQ/F+bUBlRctcypc5wB6kpfjc/7HaG8Mf
7dZ2IcwhnkQIcqQ7bAOwUQgwnQs2yLsTJ0fXLTVMPtdwCYJy+7o33dU/qGxajXDO
o+gHQr3Vvk5wrHIbdTwUci6oZclQt2xFCDqql2l41g4t530rm2aiDDnG0eaKyWQ3
TrxF1j8LHcewzzFcQ+nGtcomfP7QAW2/km+w+Cnro4TjC3GbB3h6UH1CUCLlEMKv
rEK2lDWngJJzhsfExbUWYIYLOZpyhcvFEZMCOjOBFPVmRGdak8f9M/X5lo0wYIRi
DALFmc7/e+aiKbYE5n2B+uzP1Cvw+8eUr1wbSFjgK35qZYVGY9kKcA4pnMwVVtnM
dBrJt7QZMfdjmlc49lsfw/hC38xKm+Kbqz2+yg4Ra0WCQTwsWxDMTaZt5DZgImw1
R+jbdZQP45cPNdUFKLGdjyvmQpmcYnKIJndcGvOqGWVPdGKy4oekewT7frvHUT4M
6MjJdve8pIZV/ClwWM6Q5WMj9D2ChK5aDGztEp/Qc2K0cYSzZ28prd89mDehfTZj
XNmM4HVlOKU7AJGKt3Cf6AYtiSYnjUCNqjSY1ZQyG982Z5xr6FCUN4GZUXHoIUtA
dTU=
-----END ENCRYPTED PRIVATE KEY-----

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions sdk/identity/identity/review/identity.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,12 @@ export type ClientCertificateCredentialPEMConfiguration = ClientCertificatePEMCe
// @public
export interface ClientCertificatePEMCertificate {
certificate: string;
certificatePassword?: string;
}

// @public
export interface ClientCertificatePEMCertificatePath {
certificatePassword?: string;
certificatePath: string;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ export interface ClientCertificatePEMCertificate {
* The PEM-encoded public/private key certificate on the filesystem.
*/
certificate: string;

/**
* The password for the certificate file.
*/
certificatePassword?: string;
}
/**
* Required configuration options for the {@link ClientCertificateCredential}, with the path to a PEM certificate.
Expand All @@ -29,6 +34,11 @@ export interface ClientCertificatePEMCertificatePath {
* The path to the PEM-encoded public/private key certificate on the filesystem.
*/
certificatePath: string;

/**
* The password for the certificate file.
*/
certificatePassword?: string;
}
/**
* Required configuration options for the {@link ClientCertificateCredential}, with either the string contents of a PEM certificate, or the path to a PEM certificate.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const AllSupportedEnvironmentVariables = [
"AZURE_CLIENT_ID",
"AZURE_CLIENT_SECRET",
"AZURE_CLIENT_CERTIFICATE_PATH",
"AZURE_CLIENT_CERTIFICATE_PASSWORD",
"AZURE_USERNAME",
"AZURE_PASSWORD",
];
Expand Down Expand Up @@ -56,6 +57,7 @@ export class EnvironmentCredential implements TokenCredential {
* Environment variables used for client credential authentication:
* - `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.
*
* Alternatively, users can provide environment variables for username and password authentication:
* - `AZURE_USERNAME`: Username to authenticate with.
Expand Down Expand Up @@ -89,14 +91,15 @@ export class EnvironmentCredential implements TokenCredential {
}

const certificatePath = process.env.AZURE_CLIENT_CERTIFICATE_PATH;
const certificatePassword = process.env.AZURE_CLIENT_CERTIFICATE_PASSWORD;
if (tenantId && clientId && certificatePath) {
logger.info(
`Invoking ClientCertificateCredential with tenant ID: ${tenantId}, clientId: ${clientId} and certificatePath: ${certificatePath}`
);
this._credential = new ClientCertificateCredential(
tenantId,
clientId,
{ certificatePath },
{ certificatePath, certificatePassword },
options
);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT license.

import { readFile } from "fs";
import { createHash } from "crypto";
import { createHash, createPrivateKey } from "crypto";
import { promisify } from "util";
import { AccessToken } from "@azure/core-auth";

Expand Down Expand Up @@ -121,9 +121,28 @@ export class MsalClientCertificate extends MsalNode {
async init(options?: CredentialFlowGetTokenOptions): Promise<void> {
try {
const parts = await parseCertificate(this.configuration, this.sendCertificateChain);

let privateKey: string | undefined;
if (this.configuration.certificatePassword !== undefined) {
const privateKeyObject = createPrivateKey({
key: parts.certificateContents,
passphrase: this.configuration.certificatePassword,
format: "pem",
});

privateKey = privateKeyObject
.export({
format: "pem",
type: "pkcs8",
})
.toString();
} else {
privateKey = parts.certificateContents;
}

this.msalConfig.auth.clientCertificate = {
thumbprint: parts.thumbprint,
privateKey: parts.certificateContents,
privateKey: privateKey,
x5c: parts.x5c,
};
} catch (error: any) {
Expand Down
Loading