mirror of
https://github.com/tvytlx/ai-agent-deep-dive.git
synced 2026-04-09 18:44:48 +08:00
Add extracted source directory and README navigation
This commit is contained in:
229
extracted-source/node_modules/@azure/identity/dist/esm/credentials/azurePowerShellCredential.js
generated
vendored
Normal file
229
extracted-source/node_modules/@azure/identity/dist/esm/credentials/azurePowerShellCredential.js
generated
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
import { checkTenantId, processMultiTenantRequest, resolveAdditionallyAllowedTenantIds, } from "../util/tenantIdUtils.js";
|
||||
import { credentialLogger, formatError, formatSuccess } from "../util/logging.js";
|
||||
import { ensureValidScopeForDevTimeCreds, getScopeResource } from "../util/scopeUtils.js";
|
||||
import { CredentialUnavailableError } from "../errors.js";
|
||||
import { processUtils } from "../util/processUtils.js";
|
||||
import { tracingClient } from "../util/tracing.js";
|
||||
const logger = credentialLogger("AzurePowerShellCredential");
|
||||
const isWindows = process.platform === "win32";
|
||||
/**
|
||||
* Returns a platform-appropriate command name by appending ".exe" on Windows.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function formatCommand(commandName) {
|
||||
if (isWindows) {
|
||||
return `${commandName}.exe`;
|
||||
}
|
||||
else {
|
||||
return commandName;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Receives a list of commands to run, executes them, then returns the outputs.
|
||||
* If anything fails, an error is thrown.
|
||||
* @internal
|
||||
*/
|
||||
async function runCommands(commands, timeout) {
|
||||
const results = [];
|
||||
for (const command of commands) {
|
||||
const [file, ...parameters] = command;
|
||||
const result = (await processUtils.execFile(file, parameters, {
|
||||
encoding: "utf8",
|
||||
timeout,
|
||||
}));
|
||||
results.push(result);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
/**
|
||||
* Known PowerShell errors
|
||||
* @internal
|
||||
*/
|
||||
export const powerShellErrors = {
|
||||
login: "Run Connect-AzAccount to login",
|
||||
installed: "The specified module 'Az.Accounts' with version '2.2.0' was not loaded because no valid module file was found in any module directory",
|
||||
};
|
||||
/**
|
||||
* Messages to use when throwing in this credential.
|
||||
* @internal
|
||||
*/
|
||||
export const powerShellPublicErrorMessages = {
|
||||
login: "Please run 'Connect-AzAccount' from PowerShell to authenticate before using this credential.",
|
||||
installed: `The 'Az.Account' module >= 2.2.0 is not installed. Install the Azure Az PowerShell module with: "Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force".`,
|
||||
troubleshoot: `To troubleshoot, visit https://aka.ms/azsdk/js/identity/powershellcredential/troubleshoot.`,
|
||||
};
|
||||
// PowerShell Azure User not logged in error check.
|
||||
const isLoginError = (err) => err.message.match(`(.*)${powerShellErrors.login}(.*)`);
|
||||
// Az Module not Installed in Azure PowerShell check.
|
||||
const isNotInstalledError = (err) => err.message.match(powerShellErrors.installed);
|
||||
/**
|
||||
* The PowerShell commands to be tried, in order.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export const commandStack = [formatCommand("pwsh")];
|
||||
if (isWindows) {
|
||||
commandStack.push(formatCommand("powershell"));
|
||||
}
|
||||
/**
|
||||
* This credential will use the currently logged-in user information from the
|
||||
* Azure PowerShell module. To do so, it will read the user access token and
|
||||
* expire time with Azure PowerShell command `Get-AzAccessToken -ResourceUrl {ResourceScope}`
|
||||
*/
|
||||
export class AzurePowerShellCredential {
|
||||
/**
|
||||
* Creates an instance of the {@link AzurePowerShellCredential}.
|
||||
*
|
||||
* To use this credential:
|
||||
* - Install the Azure Az PowerShell module with:
|
||||
* `Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force`.
|
||||
* - You have already logged in to Azure PowerShell using the command
|
||||
* `Connect-AzAccount` from the command line.
|
||||
*
|
||||
* @param options - Options, to optionally allow multi-tenant requests.
|
||||
*/
|
||||
constructor(options) {
|
||||
if (options === null || options === void 0 ? void 0 : options.tenantId) {
|
||||
checkTenantId(logger, options === null || options === void 0 ? void 0 : options.tenantId);
|
||||
this.tenantId = options === null || options === void 0 ? void 0 : options.tenantId;
|
||||
}
|
||||
this.additionallyAllowedTenantIds = resolveAdditionallyAllowedTenantIds(options === null || options === void 0 ? void 0 : options.additionallyAllowedTenants);
|
||||
this.timeout = options === null || options === void 0 ? void 0 : options.processTimeoutInMs;
|
||||
}
|
||||
/**
|
||||
* Gets the access token from Azure PowerShell
|
||||
* @param resource - The resource to use when getting the token
|
||||
*/
|
||||
async getAzurePowerShellAccessToken(resource, tenantId, timeout) {
|
||||
// Clone the stack to avoid mutating it while iterating
|
||||
for (const powerShellCommand of [...commandStack]) {
|
||||
try {
|
||||
await runCommands([[powerShellCommand, "/?"]], timeout);
|
||||
}
|
||||
catch (e) {
|
||||
// Remove this credential from the original stack so that we don't try it again.
|
||||
commandStack.shift();
|
||||
continue;
|
||||
}
|
||||
const results = await runCommands([
|
||||
[
|
||||
powerShellCommand,
|
||||
"-NoProfile",
|
||||
"-NonInteractive",
|
||||
"-Command",
|
||||
`
|
||||
$tenantId = "${tenantId !== null && tenantId !== void 0 ? tenantId : ""}"
|
||||
$m = Import-Module Az.Accounts -MinimumVersion 2.2.0 -PassThru
|
||||
$useSecureString = $m.Version -ge [version]'2.17.0'
|
||||
|
||||
$params = @{
|
||||
ResourceUrl = "${resource}"
|
||||
}
|
||||
|
||||
if ($tenantId.Length -gt 0) {
|
||||
$params["TenantId"] = $tenantId
|
||||
}
|
||||
|
||||
if ($useSecureString) {
|
||||
$params["AsSecureString"] = $true
|
||||
}
|
||||
|
||||
$token = Get-AzAccessToken @params
|
||||
|
||||
$result = New-Object -TypeName PSObject
|
||||
$result | Add-Member -MemberType NoteProperty -Name ExpiresOn -Value $token.ExpiresOn
|
||||
if ($useSecureString) {
|
||||
$result | Add-Member -MemberType NoteProperty -Name Token -Value (ConvertFrom-SecureString -AsPlainText $token.Token)
|
||||
} else {
|
||||
$result | Add-Member -MemberType NoteProperty -Name Token -Value $token.Token
|
||||
}
|
||||
|
||||
Write-Output (ConvertTo-Json $result)
|
||||
`,
|
||||
],
|
||||
]);
|
||||
const result = results[0];
|
||||
return parseJsonToken(result);
|
||||
}
|
||||
throw new Error(`Unable to execute PowerShell. Ensure that it is installed in your system`);
|
||||
}
|
||||
/**
|
||||
* Authenticates with Microsoft Entra ID and returns an access token if successful.
|
||||
* If the authentication cannot be performed through PowerShell, a {@link CredentialUnavailableError} will be thrown.
|
||||
*
|
||||
* @param scopes - The list of scopes for which the token will have access.
|
||||
* @param options - The options used to configure any requests this TokenCredential implementation might make.
|
||||
*/
|
||||
async getToken(scopes, options = {}) {
|
||||
return tracingClient.withSpan(`${this.constructor.name}.getToken`, options, async () => {
|
||||
const tenantId = processMultiTenantRequest(this.tenantId, options, this.additionallyAllowedTenantIds);
|
||||
const scope = typeof scopes === "string" ? scopes : scopes[0];
|
||||
if (tenantId) {
|
||||
checkTenantId(logger, tenantId);
|
||||
}
|
||||
try {
|
||||
ensureValidScopeForDevTimeCreds(scope, logger);
|
||||
logger.getToken.info(`Using the scope ${scope}`);
|
||||
const resource = getScopeResource(scope);
|
||||
const response = await this.getAzurePowerShellAccessToken(resource, tenantId, this.timeout);
|
||||
logger.getToken.info(formatSuccess(scopes));
|
||||
return {
|
||||
token: response.Token,
|
||||
expiresOnTimestamp: new Date(response.ExpiresOn).getTime(),
|
||||
tokenType: "Bearer",
|
||||
};
|
||||
}
|
||||
catch (err) {
|
||||
if (isNotInstalledError(err)) {
|
||||
const error = new CredentialUnavailableError(powerShellPublicErrorMessages.installed);
|
||||
logger.getToken.info(formatError(scope, error));
|
||||
throw error;
|
||||
}
|
||||
else if (isLoginError(err)) {
|
||||
const error = new CredentialUnavailableError(powerShellPublicErrorMessages.login);
|
||||
logger.getToken.info(formatError(scope, error));
|
||||
throw error;
|
||||
}
|
||||
const error = new CredentialUnavailableError(`${err}. ${powerShellPublicErrorMessages.troubleshoot}`);
|
||||
logger.getToken.info(formatError(scope, error));
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export async function parseJsonToken(result) {
|
||||
const jsonRegex = /{[^{}]*}/g;
|
||||
const matches = result.match(jsonRegex);
|
||||
let resultWithoutToken = result;
|
||||
if (matches) {
|
||||
try {
|
||||
for (const item of matches) {
|
||||
try {
|
||||
const jsonContent = JSON.parse(item);
|
||||
if (jsonContent === null || jsonContent === void 0 ? void 0 : jsonContent.Token) {
|
||||
resultWithoutToken = resultWithoutToken.replace(item, "");
|
||||
if (resultWithoutToken) {
|
||||
logger.getToken.warning(resultWithoutToken);
|
||||
}
|
||||
return jsonContent;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error(`Unable to parse the output of PowerShell. Received output: ${result}`);
|
||||
}
|
||||
}
|
||||
throw new Error(`No access token found in the output. Received output: ${result}`);
|
||||
}
|
||||
//# sourceMappingURL=azurePowerShellCredential.js.map
|
||||
Reference in New Issue
Block a user