Skip to content

Commit f9c800e

Browse files
authored
Merge pull request #540 from microsoftgraph/features/CertThumbprintValidation
Cert Thumbprint Validation & Parameter Classification
2 parents 8a83f3d + e3807d8 commit f9c800e

File tree

3 files changed

+37
-9
lines changed

3 files changed

+37
-9
lines changed

src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,34 +53,43 @@ public class ConnectMgGraph : PSCmdlet, IModuleAssemblyInitializer, IModuleAssem
5353
HelpMessage = "The thumbprint of your certificate. The Certificate will be retrieved from the current user's certificate store.")]
5454
public string CertificateThumbprint { get; set; }
5555

56+
[Parameter(Mandatory = false,
57+
ParameterSetName = Constants.AppParameterSet,
58+
HelpMessage = "An X.509 certificate supplied during invocation.")]
59+
public X509Certificate2 Certificate { get; set; }
60+
5661
[Parameter(ParameterSetName = Constants.AccessTokenParameterSet,
5762
Position = 1,
5863
HelpMessage = "Specifies a bearer token for Microsoft Graph service. Access tokens do timeout and you'll have to handle their refresh.")]
5964
public string AccessToken { get; set; }
6065

61-
[Parameter(Position = 4,
66+
[Parameter(ParameterSetName = Constants.AppParameterSet)]
67+
[Parameter(ParameterSetName = Constants.UserParameterSet,
68+
Position = 4,
6269
HelpMessage = "The id of the tenant to connect to.")]
6370
public string TenantId { get; set; }
6471

65-
[Parameter(Position = 5,
72+
[Parameter(ParameterSetName = Constants.AppParameterSet)]
73+
[Parameter(ParameterSetName = Constants.UserParameterSet,
74+
Position = 5,
6675
HelpMessage = "Forces the command to get a new access token silently.")]
6776
public SwitchParameter ForceRefresh { get; set; }
6877

69-
[Parameter(Mandatory = false,
78+
[Parameter(ParameterSetName = Constants.AppParameterSet)]
79+
[Parameter(ParameterSetName = Constants.UserParameterSet,
80+
Mandatory = false,
7081
HelpMessage = "Determines the scope of authentication context. This accepts `Process` for the current process, or `CurrentUser` for all sessions started by user.")]
7182
public ContextScope ContextScope { get; set; }
7283

73-
[Parameter(Mandatory = false,
84+
[Parameter(ParameterSetName = Constants.AppParameterSet)]
85+
[Parameter(ParameterSetName = Constants.AccessTokenParameterSet)]
86+
[Parameter(ParameterSetName = Constants.UserParameterSet,
87+
Mandatory = false,
7488
HelpMessage = "The name of the national cloud environment to connect to. By default global cloud is used.")]
7589
[ValidateNotNullOrEmpty]
7690
[Alias("EnvironmentName", "NationalCloud")]
7791
public string Environment { get; set; }
7892

79-
[Parameter(Mandatory = false,
80-
ParameterSetName = Constants.AppParameterSet,
81-
HelpMessage = "An x509 Certificate supplied during invocation")]
82-
public X509Certificate2 Certificate { get; set; }
83-
8493
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
8594

8695
private IGraphEnvironment environment;
@@ -312,6 +321,13 @@ private void ValidateParameters()
312321
this.ThrowParameterError($"{nameof(CertificateThumbprint)} or {nameof(CertificateName)} or {nameof(Certificate)}");
313322
}
314323

324+
// A thumbprint will always have 40 characters since thumbprints are dynamically calculated as a SHA-1 hash of a certificate's binary data. A SHA-1 hash has a length of 40 hexadecimal numbers (160-bit = 20-byte).
325+
// See https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.x509certificates.x509certificate2.thumbprint?view=net-5.0#remarks.
326+
if (!string.IsNullOrEmpty(CertificateThumbprint) && CertificateThumbprint.Length != 40)
327+
{
328+
this.ThrowError(string.Format(ErrorConstants.Message.InvalidCertificateThumbprint, nameof(CertificateThumbprint)), ErrorCategory.InvalidArgument);
329+
}
330+
315331
// Tenant Id
316332
if (string.IsNullOrEmpty(TenantId))
317333
{

src/Authentication/Authentication/ErrorConstants.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ internal static class Message
4949
internal const string InvalidEnvironment = "Unable to find environment with name '{0}'. Use Get-MgEnvironment to list available environments.";
5050
internal const string CannotAccessFile = "Could not {0} file at '{1}'. Please ensure you have access to this file and try again in a few minutes..";
5151
internal const string CannotModifyBuiltInEnvironment = "Cannot {0} built-in environment {1}.";
52+
internal const string InvalidCertificateThumbprint = "'{0}' must have a length of 40. Ensure you have the right certificate thumbprint then try again.";
5253
}
5354
}
5455
}

src/Authentication/Authentication/test/Connect-MgGraph.Tests.ps1

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ BeforeAll {
22
$ModuleName = "Microsoft.Graph.Authentication"
33
$ModulePath = Join-Path $PSScriptRoot "..\$ModuleName.psd1"
44
Import-Module $ModulePath -Force
5+
$RandomClientId = (New-Guid).Guid
56
}
67
Describe 'Connect-MgGraph In Delegated Mode' {
78
It 'ShouldThrowExceptionWhenInvalidTenantIdIsSpecified' {
@@ -11,4 +12,14 @@ Describe 'Connect-MgGraph In Delegated Mode' {
1112
It 'ShouldThrowExceptionWhenInvalidScopeIsSpecified' {
1213
{ Connect-MgGraph -Scopes 'User.Read.XYZ' -ErrorAction Stop } | Should -Throw -ExpectedMessage "*The scope 'User.Read.XYZ offline_access profile openid' does not exist*"
1314
}
15+
}
16+
17+
Describe 'Connect-MgGraph In App Mode' {
18+
It 'ShouldThrowExceptionWhenCertificateThumbprintLengthIs > 40' {
19+
{ Connect-MgGraph -ClientId $RandomClientId -CertificateThumbprint '12345678901234567890123456789012345678901' -ErrorAction Stop } | Should -Throw -ExpectedMessage "*'CertificateThumbprint' must have a length of 40.*"
20+
}
21+
22+
It 'ShouldThrowExceptionWhenCertificateThumbprintLengthIs < 40' {
23+
{ Connect-MgGraph -ClientId $RandomClientId -CertificateThumbprint '123456789012345678901234567890123456789' -ErrorAction Stop } | Should -Throw -ExpectedMessage "*'CertificateThumbprint' must have a length of 40.*"
24+
}
1425
}

0 commit comments

Comments
 (0)