-
Notifications
You must be signed in to change notification settings - Fork 94
/
Copy pathAzureKeyVaultCommand.cs
108 lines (90 loc) · 5.25 KB
/
AzureKeyVaultCommand.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE.txt file in the project root for more information.
using System.CommandLine;
using System.CommandLine.Invocation;
using System.CommandLine.IO;
using Azure.Core;
using Azure.Identity;
using Sign.Core;
using Sign.SignatureProviders.KeyVault;
namespace Sign.Cli
{
internal sealed class AzureKeyVaultCommand : Command
{
private readonly CodeCommand _codeCommand;
internal Option<string> CertificateOption { get; } = new(["-kvc", "--azure-key-vault-certificate"], AzureKeyVaultResources.CertificateOptionDescription);
internal Option<string?> ClientIdOption { get; } = new(["-kvi", "--azure-key-vault-client-id"], AzureKeyVaultResources.ClientIdOptionDescription);
internal Option<string?> ClientSecretOption { get; } = new(["-kvs", "--azure-key-vault-client-secret"], AzureKeyVaultResources.ClientSecretOptionDescription);
internal Option<bool> ManagedIdentityOption { get; } = new(["-kvm", "--azure-key-vault-managed-identity"], getDefaultValue: () => false, AzureKeyVaultResources.ManagedIdentityOptionDescription);
internal Option<string?> TenantIdOption { get; } = new(["-kvt", "--azure-key-vault-tenant-id"], AzureKeyVaultResources.TenantIdOptionDescription);
internal Option<Uri> UrlOption { get; } = new(["-kvu", "--azure-key-vault-url"], AzureKeyVaultResources.UrlOptionDescription);
internal Argument<string?> FileArgument { get; } = new("file(s)", Resources.FilesArgumentDescription);
internal AzureKeyVaultCommand(CodeCommand codeCommand, IServiceProviderFactory serviceProviderFactory)
: base("azure-key-vault", AzureKeyVaultResources.CommandDescription)
{
ArgumentNullException.ThrowIfNull(codeCommand, nameof(codeCommand));
ArgumentNullException.ThrowIfNull(serviceProviderFactory, nameof(serviceProviderFactory));
_codeCommand = codeCommand;
CertificateOption.IsRequired = true;
UrlOption.IsRequired = true;
ManagedIdentityOption.SetDefaultValue(false);
AddOption(UrlOption);
AddOption(TenantIdOption);
AddOption(ClientIdOption);
AddOption(ClientSecretOption);
AddOption(CertificateOption);
AddOption(ManagedIdentityOption);
AddArgument(FileArgument);
this.SetHandler(async (InvocationContext context) =>
{
string? fileArgument = context.ParseResult.GetValueForArgument(FileArgument);
if (string.IsNullOrEmpty(fileArgument))
{
context.Console.Error.WriteLine(Resources.MissingFileValue);
context.ExitCode = ExitCode.InvalidOptions;
return;
}
// this check exists as a courtesy to users who may have been signing .clickonce files via the old workaround.
// at some point we should remove this check, probably once we hit v1.0
if (fileArgument.EndsWith(".clickonce", StringComparison.OrdinalIgnoreCase))
{
context.Console.Error.WriteLine(AzureKeyVaultResources.ClickOnceExtensionNotSupported);
context.ExitCode = ExitCode.InvalidOptions;
return;
}
// Some of the options are required and that is why we can safely use
// the null-forgiving operator (!) to simplify the code.
Uri url = context.ParseResult.GetValueForOption(UrlOption)!;
string? tenantId = context.ParseResult.GetValueForOption(TenantIdOption);
string? clientId = context.ParseResult.GetValueForOption(ClientIdOption);
string? secret = context.ParseResult.GetValueForOption(ClientSecretOption);
string certificateId = context.ParseResult.GetValueForOption(CertificateOption)!;
bool useManagedIdentity = context.ParseResult.GetValueForOption(ManagedIdentityOption);
TokenCredential? credential = null;
if (useManagedIdentity)
{
credential = new DefaultAzureCredential();
}
else
{
if (string.IsNullOrEmpty(tenantId) ||
string.IsNullOrEmpty(clientId) ||
string.IsNullOrEmpty(secret))
{
context.Console.Error.WriteFormattedLine(
AzureKeyVaultResources.InvalidClientSecretCredential,
TenantIdOption,
ClientIdOption,
ClientSecretOption);
context.ExitCode = ExitCode.NoInputsFound;
return;
}
credential = new ClientSecretCredential(tenantId, clientId, secret);
}
KeyVaultServiceProvider keyVaultServiceProvider = new(credential, url, certificateId);
await _codeCommand.HandleAsync(context, serviceProviderFactory, keyVaultServiceProvider, fileArgument);
});
}
}
}