diff --git a/Common/Utils/AuthUtils.cs b/Common/Utils/AuthUtils.cs index 9c135b3..584a4ef 100644 --- a/Common/Utils/AuthUtils.cs +++ b/Common/Utils/AuthUtils.cs @@ -9,6 +9,8 @@ namespace Microsoft.Intune.PowerShellGraphSDK using Microsoft.IdentityModel.Clients.ActiveDirectory; using Newtonsoft.Json; using Newtonsoft.Json.Linq; + using System.Security.Cryptography; + using System.Security.Cryptography.X509Certificates; internal static partial class AuthUtils { @@ -49,6 +51,53 @@ internal static partial class AuthUtils /// internal static bool UseMsiAuth => !string.IsNullOrWhiteSpace(ManagedServiceIdentityEndpoint) && LatestAdalAuthResult == null; + /// + /// Authenticates with the currently set environment parameters and the provided client certificate identified by thumbprint. + /// + /// The client secret + /// The authentication result. + internal static SdkAuthResult AuthWithCertificateThumbprint(string certificateThumbprint) + { + // Get the environment parameters + EnvironmentParameters environmentParameters = AuthUtils.CurrentEnvironmentParameters; + + // Create auth context that we will use to connect to the AAD endpoint + AuthenticationContext authContext = new AuthenticationContext(environmentParameters.AuthUrl); + + // Get certificate with specified Thumbprint from "My" store + X509Certificate2 xCertificate = null; + + using (X509Store xStore = new X509Store(StoreName.My, StoreLocation.CurrentUser)) + { + xStore.Open(OpenFlags.ReadOnly); + // Get unexpired certificates with the specified name. + X509Certificate2Collection unexpiredCerts = xStore.Certificates + .Find(X509FindType.FindByTimeValid, DateTime.Now, false) + .Find(X509FindType.FindByThumbprint, certificateThumbprint, false); + if (unexpiredCerts == null) + throw new Exception($"{certificateThumbprint} certificate was not found or has expired."); + // Only return current cert. + xCertificate = unexpiredCerts + .OfType() + .OrderByDescending(c => c.NotBefore) + .FirstOrDefault(); + } + + // Build clientAssertionCertificate for the request + ClientAssertionCertificate clientAssertionCertificate = new ClientAssertionCertificate(CurrentEnvironmentParameters.AppId, xCertificate); + + // Acquire token for Microsoft Graph via certificate credentials from AAD + AuthenticationResult authenticationResult = authContext.AcquireTokenAsync(CurrentEnvironmentParameters.GraphBaseAddress, clientAssertionCertificate).GetAwaiter().GetResult(); + + // Convert the auth result into our own type + SdkAuthResult authResult = authenticationResult.ToSdkAuthResult(); + + // Save the auth result + AuthUtils.LatestAdalAuthResult = authResult; + + return authResult; + } + /// /// Authenticates with the currently set environment parameters and the provided client secret. /// diff --git a/PowerShellCmdlets/Utils/UtilCmdlets.cs b/PowerShellCmdlets/Utils/UtilCmdlets.cs index 1778875..116cf50 100644 --- a/PowerShellCmdlets/Utils/UtilCmdlets.cs +++ b/PowerShellCmdlets/Utils/UtilCmdlets.cs @@ -33,6 +33,11 @@ public class Connect : PSCmdlet /// private const string ParameterSetAdminConsent = "AdminConsent"; + /// + /// Parameter set for triggering the app-only authentication with a client certificate. + /// + private const string ParameterSetCertificateThumbprint = "CertificateThumbprint"; + /// /// Parameter set for triggering app-only authentication. /// @@ -87,6 +92,14 @@ public class Connect : PSCmdlet [Parameter(ParameterSetName = ParameterSetAppOnly)] public string ClientSecret { get; set; } + /// + /// + /// If the certificate thumbprint is set, app-only authentication will be performed using the client ID specified by the AppId environment parameter. + /// + /// + [Parameter(ParameterSetName = ParameterSetCertificateThumbprint)] + public string CertificateThumbprint { get; set; } + /// /// /// If the AdminConsent flag is set, admin consent can be granted for the currently selected AppId @@ -125,6 +138,12 @@ protected override void ProcessRecord() // App-only auth authResult = AuthUtils.AuthWithClientCredentials(this.ClientSecret); } + else if (this.ParameterSetName == ParameterSetCertificateThumbprint) + { + authResult = AuthUtils.AuthWithCertificateThumbprint(this.CertificateThumbprint); + + } + else { // User auth diff --git a/PowerShellGraphSDK.csproj b/PowerShellGraphSDK.csproj index 8c88de7..5e6fdb6 100644 --- a/PowerShellGraphSDK.csproj +++ b/PowerShellGraphSDK.csproj @@ -41,9 +41,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers @@ -90,7 +90,7 @@ - +