Skip to content

Commit

Permalink
Client credentials now work #74
Browse files Browse the repository at this point in the history
Crazy fast winget package search
  • Loading branch information
svrooij committed May 28, 2024
1 parent 83819fc commit 549169e
Show file tree
Hide file tree
Showing 10 changed files with 747 additions and 28 deletions.
46 changes: 34 additions & 12 deletions src/Svrooij.WinTuner.CmdLets/Commands/BaseIntuneCmdlet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ namespace Svrooij.WinTuner.CmdLets.Commands;
public abstract class BaseIntuneCmdlet : DependencyCmdlet<Startup>
{
private const string DefaultClientId = "d5a8a406-3b1d-4069-91cc-d76acdd812fe";
private const string DefaultClientCredentialScope = "https://graph.microsoft.com/.default";

/// <summary>
///
Expand All @@ -25,7 +26,7 @@ public abstract class BaseIntuneCmdlet : DependencyCmdlet<Startup>
ValueFromPipeline = false,
ValueFromPipelineByPropertyName = false,
HelpMessage = "Use a managed identity to connect to Intune")]
public bool UseManagedIdentity { get; set; }
public bool UseManagedIdentity { get; set; } = Environment.GetEnvironmentVariable("AZURE_USE_MANAGED_IDENTITY")?.Equals("true", StringComparison.OrdinalIgnoreCase) == true;

/// <summary>
///
Expand All @@ -36,7 +37,7 @@ public abstract class BaseIntuneCmdlet : DependencyCmdlet<Startup>
ValueFromPipeline = false,
ValueFromPipelineByPropertyName = false,
HelpMessage = "Use default Azure Credentials from Azure.Identity to connect to Intune")]
public bool UseDefaultAzureCredential { get; set; }
public bool UseDefaultAzureCredential { get; set; } = Environment.GetEnvironmentVariable("AZURE_USE_DEFAULT_CREDENTIALS")?.Equals("true", StringComparison.OrdinalIgnoreCase) == true;

/// <summary>
///
Expand All @@ -47,7 +48,7 @@ public abstract class BaseIntuneCmdlet : DependencyCmdlet<Startup>
ValueFromPipeline = false,
ValueFromPipelineByPropertyName = false,
HelpMessage = "Use a token from another source to connect to Intune")]
public string? Token { get; set; }
public string? Token { get; set; } = Environment.GetEnvironmentVariable("AZURE_TOKEN");

/// <summary>
///
Expand Down Expand Up @@ -105,6 +106,17 @@ public abstract class BaseIntuneCmdlet : DependencyCmdlet<Startup>
HelpMessage = "Specify the client secret, mandatory for Client Credentials flow. Loaded from `AZURE_CLIENT_SECRET`")]
public string? ClientSecret { get; set; } = Environment.GetEnvironmentVariable("AZURE_CLIENT_SECRET");

/// <summary>
///
/// </summary>
[Parameter(
Mandatory = false,
Position = 40,
ValueFromPipeline = false,
ValueFromPipelineByPropertyName = false,
HelpMessage = "Specify the scopes to request, default is `DeviceManagementConfiguration.ReadWrite.All`, `DeviceManagementApps.ReadWrite.All`")]
public string[]? Scopes { get; set; } = Environment.GetEnvironmentVariable("AZURE_SCOPES")?.Split(' ');

/// <summary>
///
/// </summary>
Expand All @@ -119,6 +131,7 @@ internal void ValidateAuthenticationParameters()

if (UseManagedIdentity || UseDefaultAzureCredential)
{
Scopes ??= new[] { DefaultClientCredentialScope };
return;
}

Expand All @@ -127,6 +140,12 @@ internal void ValidateAuthenticationParameters()
return;
}

if (!string.IsNullOrEmpty(ClientId) && !string.IsNullOrEmpty(ClientSecret) && !string.IsNullOrEmpty(TenantId))
{
Scopes ??= new[] { DefaultClientCredentialScope };
return;
}

throw new ArgumentException($"Use `{nameof(Token)}`, `{nameof(UseManagedIdentity)}`, `{nameof(UseDefaultAzureCredential)}` or `{nameof(Username)}` to select the graph connection type", nameof(ParameterSetName));
}

Expand All @@ -137,7 +156,7 @@ internal IAuthenticationProvider CreateAuthenticationProvider(string[]? scopes =
return new WingetIntune.Internal.Msal.StaticAuthenticationProvider(Token);
}

var scope = (scopes ?? DefaultScopes)[0];
var scope = (Scopes ?? scopes ?? DefaultScopes)[0];

if (UseManagedIdentity || UseDefaultAzureCredential)
{
Expand All @@ -148,16 +167,19 @@ internal IAuthenticationProvider CreateAuthenticationProvider(string[]? scopes =
return new Microsoft.Graph.Authentication.AzureIdentityAuthenticationProvider(credentials, null, null, scope);
}

if (!string.IsNullOrEmpty(ClientId) && !string.IsNullOrEmpty(ClientSecret) && !string.IsNullOrEmpty(TenantId))
if (!string.IsNullOrEmpty(ClientId) && !string.IsNullOrEmpty(TenantId))
{
return new Microsoft.Graph.Authentication.AzureIdentityAuthenticationProvider(new Azure.Identity.ClientSecretCredential(TenantId, ClientId, ClientSecret, new Azure.Identity.ClientSecretCredentialOptions
{
TokenCachePersistenceOptions = new Azure.Identity.TokenCachePersistenceOptions
if (!string.IsNullOrEmpty(ClientSecret)) {

Check failure on line 172 in src/Svrooij.WinTuner.CmdLets/Commands/BaseIntuneCmdlet.cs

View workflow job for this annotation

GitHub Actions / 🛠️ Build and Test C#

Fix whitespace formatting. Replace 1 characters with '\r\n\s\s\s\s\s\s\s\s\s\s\s\s'. [/home/runner/work/WingetIntune/WingetIntune/src/Svrooij.WinTuner.CmdLets/Svrooij.WinTuner.CmdLets.csproj]
return new Microsoft.Graph.Authentication.AzureIdentityAuthenticationProvider(new Azure.Identity.ClientSecretCredential(TenantId, ClientId, ClientSecret, new Azure.Identity.ClientSecretCredentialOptions
{
Name = "WinTuner-PowerShell-CC",
UnsafeAllowUnencryptedStorage = true,
}
}), scopes: new[] { scope });
TokenCachePersistenceOptions = new Azure.Identity.TokenCachePersistenceOptions
{
Name = "WinTuner-PowerShell-CC",
UnsafeAllowUnencryptedStorage = true,
}
}), scopes: scope);
}

Check failure on line 182 in src/Svrooij.WinTuner.CmdLets/Commands/BaseIntuneCmdlet.cs

View workflow job for this annotation

GitHub Actions / 🛠️ Build and Test C#

Fix whitespace formatting. Replace 22 characters with '\r\n\s\s\s\s\s\s\s\s'. [/home/runner/work/WingetIntune/WingetIntune/src/Svrooij.WinTuner.CmdLets/Svrooij.WinTuner.CmdLets.csproj]
}

// Alternative interactive authentication in case the broker is not working as expected.
Expand Down
46 changes: 46 additions & 0 deletions src/Svrooij.WinTuner.CmdLets/Commands/SearchWtWinGetPackage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using Svrooij.PowerShell.DependencyInjection;
using System;
using System.Management.Automation;
using System.Threading;
using System.Threading.Tasks;

namespace Svrooij.WinTuner.CmdLets.Commands;

/// <summary>
/// <para type="synopsis">Search for packages in winget</para>
/// <para type="description">Search for WinGet packages, but faster</para>
/// </summary>
/// <example>
/// <para type="description">Search for 'fire', did I tell you it's fast?</para>
/// <code>Search-WtWinGetPackage fire</code>
/// </example>
[Cmdlet(VerbsCommon.Search, "WtWinGetPackage", HelpUri = "https://wintuner.app/docs/wintuner-powershell/Search-WtWingetPackage")]
[OutputType(typeof(Winget.CommunityRepository.Models.WingetEntry[]))]
public class SearchWtWinGetPackage : DependencyCmdlet<Startup>
{
/// <summary>
///
/// </summary>
[Parameter(
Mandatory = true,
Position = 0,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
HelpMessage = "Part of the package ID, 2 characters minimum")]
public string? PackageId { get; set; }

[ServiceDependency]
private Winget.CommunityRepository.WingetRepository wingetRepository;

/// <inheritdoc />
public override async Task ProcessRecordAsync(CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(PackageId) || PackageId.Length <= 1)
{
throw new ArgumentException("PackageId is required");
}
var packages = await wingetRepository.SearchPackage(PackageId ?? throw new ArgumentNullException(nameof(PackageId)), cancellationToken);

Check failure on line 43 in src/Svrooij.WinTuner.CmdLets/Commands/SearchWtWinGetPackage.cs

View workflow job for this annotation

GitHub Actions / 🛠️ Build and Test C#

Fix whitespace formatting. Replace 18 characters with '\r\n\s\s\s\s\s\s\s\s'. [/home/runner/work/WingetIntune/WingetIntune/src/Svrooij.WinTuner.CmdLets/Svrooij.WinTuner.CmdLets.csproj]
WriteObject(packages);
}
}
Loading

0 comments on commit 549169e

Please sign in to comment.