Skip to content

Commit e251c9e

Browse files
authored
Merge pull request #85 from thadumi/certificateUserIDsModule
CertificateUserIDs module
2 parents 2cdcbd6 + c80959f commit e251c9e

File tree

5 files changed

+330
-0
lines changed

5 files changed

+330
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ View the latest list of cmdlets on the [cmdlet summary](../../wiki/Cmdlets) page
6666
| [Split-MsIdEntitlementManagementConnectedOrganization](https://github.com/AzureAD/MSIdentityTools/wiki/Split-MsIdEntitlementManagementConnectedOrganization) | Split elements of a connectedOrganization |
6767
| [Test-MsIdAzureAdDeviceRegConnectivity](https://github.com/AzureAD/MSIdentityTools/wiki/Test-MsIdAzureAdDeviceRegConnectivity) | Test connectivity on Windows OS for Azure AD Device Registration |
6868
| [Test-MsIdCBATrustStoreConfiguration](https://github.com/AzureAD/MSIdentityTools/wiki/Test-MsIdCBATrustStoreConfiguration) | Test & report for common mis-configuration issues with the Entra ID Certificate Trust Store |
69+
| [Get-MsIdCBACertificateUserIdFromCertificate](https://github.com/AzureAD/MSIdentityTools/wiki/Get-MsIdCBACertificateUserIdFromCertificate) | Creates an object with all values from a certificate file for configuring CertificateUserIDs in Entra ID |
6970
| [Update-MsIdApplicationSigningKeyThumbprint](https://github.com/AzureAD/MSIdentityTools/wiki/Update-MsIdApplicationSigningKeyThumbprint) | Update a Service Princpal's preferredTokenSigningKeyThumbprint to the specified certificate thumbprint |
7071
| [Update-MsIdGroupWritebackConfiguration](https://github.com/AzureAD/MSIdentityTools/wiki/Update-MsIdGroupWritebackConfiguration) | Update an Azure AD cloud group settings to writeback as an AD on-premises group |
7172

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
# ------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.
3+
# ------------------------------------------------------------------------------
4+
5+
<#
6+
.SYNOPSIS
7+
Generates an object representing all the values contained in a certificate file that can be used in Entra ID for configuring CertificateUserIDs in Certificate-Based Authentication.
8+
9+
.DESCRIPTION
10+
Retrieves and returns an object with the properties 'PrincipalName', 'RFC822Name', 'IssuerAndSubject', 'Subject', 'SKI', 'SHA1PublicKey', and 'IssuerAndSerialNumber' from a certificate file for use in CertificateUserIDs configuration in Certificate-Based Authentication, according to the guidelines outlined in the Microsoft documentation for certificate-based authentication
11+
12+
.PARAMETER Path
13+
The path to the certificate file. The file can be in .cer or .pem format.
14+
15+
.PARAMETER Certificate
16+
An X509Certificate2 object
17+
18+
.PARAMETER CertificateMapping
19+
The certificate mapping property to retrieve. Valid values are PrincipalName, RFC822Name, IssuerAndSubject, Subject, SKI, SHA1PublicKey, and IssuerAndSerialNumber.
20+
21+
.EXAMPLE
22+
PS > Get-MsIdCBACertificateUserIdFromCertificate -Path "C:\path\to\certificate.cer"
23+
24+
This command retrieves all the possible certificate mappings and returns an object to represent them.
25+
26+
.EXAMPLE
27+
PS > Get-MsIdCBACertificateUserIdFromCertificate -Certificate $cert
28+
29+
This command retrieves all the possible certificate mappings and returns an object to represent them.
30+
31+
.EXAMPLE
32+
PS > Get-MsIdCBACertificateUserIdFromCertificate -Path "C:\path\to\certificate.cer" -CertificateMapping Subject
33+
34+
This command retrieves and returns the PrincipalName property.
35+
36+
.OUTPUTS
37+
Returns an object containing the certificateUserIDs that can be used with the givin certificate.
38+
39+
@{
40+
PrincipalName = "X509:<PN>[email protected]"
41+
RFC822Name = "X509:<RFC822>[email protected]"
42+
IssuerAndSubject = "X509:<I>DC=com,DC=contoso,CN=CONTOSO-DC-CA<S>DC=com,DC=contoso,OU=UserAccounts,CN=mfatest"
43+
Subject = "X509:<S>DC=com,DC=contoso,OU=UserAccounts,CN=mfatest"
44+
SKI = "X509:<SKI>aB1cD2eF3gH4iJ5kL6mN7oP8qR"
45+
SHA1PublicKey = "X509:<SHA1-PUKEY>cD2eF3gH4iJ5kL6mN7oP8qR9sT"
46+
IssuerAndSerialNumber = "X509:<I>DC=com,DC=contoso,CN=CONTOSO-DC-CA<SR>eF3gH4iJ5kL6mN7oP8qR9sT0uV"
47+
}
48+
49+
#>
50+
51+
function Get-MsIdCBACertificateUserIdFromCertificate {
52+
param (
53+
[Parameter(Mandatory = $false)]
54+
[string]$Path,
55+
[Parameter(Mandatory = $false)]
56+
[System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate,
57+
[Parameter(Mandatory = $false)]
58+
[ValidateSet("PrincipalName", "RFC822Name", "IssuerAndSubject", "Subject", "SKI", "SHA1PublicKey", "IssuerAndSerialNumber")]
59+
[string]$CertificateMapping
60+
)
61+
62+
function Get-Certificate {
63+
param (
64+
[string]$filePath
65+
)
66+
if ($filePath.EndsWith(".cer")) {
67+
return [System.Security.Cryptography.X509Certificates.X509Certificate]::new($filePath)
68+
} elseif ($filePath.EndsWith(".pem")) {
69+
$pemContent = Get-Content -Path $filePath -Raw
70+
$pemContent = $pemContent -replace "-----BEGIN CERTIFICATE-----", ""
71+
$pemContent = $pemContent -replace "-----END CERTIFICATE-----", ""
72+
$pemContent = $pemContent -replace "(\r\n|\n|\r)", ""
73+
$pemBytes = [Convert]::FromBase64String($pemContent)
74+
$certificate = [System.Security.Cryptography.X509Certificates.X509Certificate]::new($pemBytes)
75+
76+
return $certificate
77+
} else {
78+
throw "Unsupported certificate format. Please provide a .cer or .pem file."
79+
}
80+
}
81+
82+
function Get-DistinguishedNameAsString {
83+
param (
84+
[System.Security.Cryptography.X509Certificates.X500DistinguishedName]$distinguishedName
85+
)
86+
87+
$dn = $distinguishedName.Decode([System.Security.Cryptography.X509Certificates.X500DistinguishedNameFlags]::UseNewLines -bor [System.Security.Cryptography.X509Certificates.X500DistinguishedNameFlags]::DoNotUsePlusSign)
88+
89+
$dn = $dn -replace "(\r\n|\n|\r)", ","
90+
return $dn.TrimEnd(',')
91+
}
92+
93+
function Get-SerialNumberAsLittleEndianHexString {
94+
param (
95+
[System.Security.Cryptography.X509Certificates.X509Certificate2]$cert
96+
)
97+
98+
$littleEndianSerialNumber = $cert.GetSerialNumber()
99+
100+
if ($littleEndianSerialNumber.Length -eq 0)
101+
{
102+
return ""
103+
}
104+
105+
[System.Array]::Reverse($littleEndianSerialNumber)
106+
$hexString = -join ($littleEndianSerialNumber | ForEach-Object { $_.ToString("x2") })
107+
return $hexString
108+
}
109+
110+
function Get-SubjectKeyIdentifier {
111+
param (
112+
[System.Security.Cryptography.X509Certificates.X509Certificate2]$cert
113+
)
114+
foreach ($extension in $cert.Extensions) {
115+
if ($extension.Oid.Value -eq "2.5.29.14") {
116+
$ski = New-Object System.Security.Cryptography.X509Certificates.X509SubjectKeyIdentifierExtension -ArgumentList $extension, $false
117+
return $ski.SubjectKeyIdentifier
118+
}
119+
}
120+
121+
return ""
122+
}
123+
124+
# Function to generate certificate mapping fields
125+
function Get-CertificateMappingFields {
126+
param (
127+
[System.Security.Cryptography.X509Certificates.X509Certificate2]$cert
128+
)
129+
$subject = Get-DistinguishedNameAsString -distinguishedName $cert.SubjectName
130+
$issuer = Get-DistinguishedNameAsString -distinguishedName $cert.IssuerName
131+
$serialNumber = Get-SerialNumberAsLittleEndianHexString -cert $cert
132+
$thumbprint = $cert.Thumbprint
133+
$principalName = $cert.GetNameInfo([System.Security.Cryptography.X509Certificates.X509NameType]::UpnName, $false)
134+
$emailName = $cert.GetNameInfo([System.Security.Cryptography.X509Certificates.X509NameType]::EmailName, $false)
135+
$subjectKeyIdentifier = Get-SubjectKeyIdentifier -cert $cert
136+
$sha1PublicKey = $cert.GetCertHashString()
137+
138+
return @{
139+
"SubjectName" = $subject
140+
"IssuerName" = $issuer
141+
"SerialNumber" = $serialNumber
142+
"Thumbprint" = $thumbprint
143+
"PrincipalName" = $principalName
144+
"EmailName" = $emailName
145+
"SubjectKeyIdentifier" = $subjectKeyIdentifier
146+
"Sha1PublicKey" = $sha1PublicKey
147+
}
148+
}
149+
150+
function Get-CertificateUserIds {
151+
param (
152+
[System.Security.Cryptography.X509Certificates.X509Certificate2]$cert
153+
)
154+
155+
$mappingFields = Get-CertificateMappingFields -cert $cert
156+
157+
$certUserIDs = @{
158+
"PrincipalName" = ""
159+
"RFC822Name" = ""
160+
"IssuerAndSubject" = ""
161+
"Subject" = ""
162+
"SKI" = ""
163+
"SHA1PublicKey" = ""
164+
"IssuerAndSerialNumber" = ""
165+
}
166+
167+
if (-not [string]::IsNullOrWhiteSpace($mappingFields.PrincipalName))
168+
{
169+
$certUserIDs.PrincipalName = "X509:<PN>$($mappingFields.PrincipalName)"
170+
}
171+
172+
if (-not [string]::IsNullOrWhiteSpace($mappingFields.EmailName))
173+
{
174+
$certUserIDs.RFC822Name = "X509:<RFC822>$($mappingFields.EmailName)"
175+
}
176+
177+
if ((-not [string]::IsNullOrWhiteSpace($mappingFields.IssuerName)) -and (-not [string]::IsNullOrWhiteSpace($mappingFields.SubjectName)))
178+
{
179+
$certUserIDs.IssuerAndSubject = "X509:<I>$($mappingFields.IssuerName)<S>$($mappingFields.SubjectName)"
180+
}
181+
182+
if (-not [string]::IsNullOrWhiteSpace($mappingFields.SubjectName))
183+
{
184+
$certUserIDs.Subject = "X509:<S>$($mappingFields.SubjectName)"
185+
}
186+
187+
if (-not [string]::IsNullOrWhiteSpace($mappingFields.SubjectKeyIdentifier))
188+
{
189+
$certUserIDs.SKI = "X509:<SKI>$($mappingFields.SubjectKeyIdentifier)"
190+
}
191+
192+
if (-not [string]::IsNullOrWhiteSpace($mappingFields.Sha1PublicKey))
193+
{
194+
$certUserIDs.SHA1PublicKey = "X509:<SHA1-PUKEY>$($mappingFields.Sha1PublicKey)"
195+
}
196+
197+
if ((-not [string]::IsNullOrWhiteSpace($mappingFields.IssuerName)) -and (-not [string]::IsNullOrWhiteSpace($mappingFields.SerialNumber)))
198+
{
199+
$certUserIDs.IssuerAndSerialNumber = "X509:<I>$($mappingFields.IssuerName)<SR>$($mappingFields.SerialNumber)"
200+
}
201+
202+
return $certUserIDs
203+
}
204+
205+
function Main
206+
{
207+
$cert = $Certificate
208+
if ($null -eq $cert)
209+
{
210+
$cert = Get-Certificate -filePath $Path
211+
}
212+
213+
$mappings = Get-CertificateUserIds -cert $cert
214+
215+
if ($CertificateMapping -eq "")
216+
{
217+
return $mappings
218+
}
219+
else
220+
{
221+
$value = $mappings[$CertificateMapping]
222+
return "$($value)"
223+
}
224+
}
225+
226+
# Call main function
227+
return Main
228+
}

src/MSIdentityTools.psd1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
'.\Show-MsIdSamlToken.ps1'
140140
'.\Test-MsIdAzureAdDeviceRegConnectivity.ps1'
141141
'.\Test-MsIdCBATrustStoreConfiguration.ps1'
142+
'.\Get-MsIdCBACertificateUserIdFromCertificate.ps1'
142143
'.\Resolve-MsIdTenant.ps1'
143144
'.\Set-MsIdWindowsTlsSettings.ps1'
144145
'.\Get-MsIdSigningKeyThumbprint.ps1'
@@ -201,6 +202,7 @@
201202
'Show-MsIdSamlToken'
202203
'Test-MsIdAzureAdDeviceRegConnectivity'
203204
'Test-MsIdCBATrustStoreConfiguration'
205+
'Get-MsIdCBACertificateUserIdFromCertificate'
204206
'Get-MsIdSigningKeyThumbprint'
205207
'Update-MsIdApplicationSigningKeyThumbprint'
206208
'Get-MsIdIsViralUser'
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
---
2+
sidebar_class_name: hidden
3+
description: Creates an object with all values from a certificate file for configuring CertificateUserIDs in Entra ID
4+
id: Get-MsIdCBACertificateUserIdFromCertificate
5+
title: Get-MsIdCBACertificateUserIdFromCertificate
6+
hide_title: false
7+
hide_table_of_contents: false
8+
custom_edit_url: https://github.com/azuread/msidentitytools/blob/main/src/Get-MsIdCBACertificateUserIdFromCertificate.ps1
9+
---
10+
## SYNOPSIS
11+
Generates an object representing all the values contained in a certificate file that can be used in Entra ID for configuring CertificateUserIDs in Certificate-Based Authentication.
12+
13+
## SYNTAX
14+
```syntax
15+
Get-MsIdCBACertificateUserIdFromCertificate [-Path] <string> [[-CertificateMapping] <string>] [<CommonParameters>]
16+
```
17+
18+
## DESCRIPTION
19+
20+
Returns an object containing the certificateUserIDs configurations for Certificate-Based Authentication based on the given certificate file. The properties in the object are constructed according to the guidelines outlined in the Microsoft [documentation](https://learn.microsoft.com/en-us/entra/identity/authentication/concept-certificate-based-authentication-certificateuserids
21+
) for certificate-based authentication.
22+
23+
```powershell
24+
@{
25+
PrincipalName = "X509:<PN>[email protected]"
26+
RFC822Name = "X509:<RFC822>[email protected]"
27+
IssuerAndSubject = "X509:<I>DC=com,DC=contoso,CN=CONTOSO-DC-CA<S>DC=com,DC=contoso,OU=UserAccounts,CN=mfatest"
28+
Subject = "X509:<S>DC=com,DC=contoso,OU=UserAccounts,CN=mfatest"
29+
SKI = "X509:<SKI>aB1cD2eF3gH4iJ5kL6mN7oP8qR"
30+
SHA1PublicKey = "X509:<SHA1-PUKEY>cD2eF3gH4iJ5kL6mN7oP8qR9sT"
31+
IssuerAndSerialNumber = "X509:<I>DC=com,DC=contoso,CN=CONTOSO-DC-CA<SR>eF3gH4iJ5kL6mN7oP8qR9sT0uV"
32+
}
33+
```
34+
35+
## EXAMPLES
36+
37+
### EXAMPLE 1
38+
```powershell
39+
> $output = Get-MsIdCBACertificateUserIdFromCertificate C:\path\to\certificate.cer
40+
> $output
41+
Name Value
42+
---- -----
43+
Subject X509:<S>DC=com,DC=contoso,OU=UserAccounts,CN=mfatest
44+
IssuerAndSerialNumber X509:<I>DC=com,DC=contoso,CN=CONTOSO-DC-CA<SR>eF3gH4iJ5kL6mN7oP8qR9sT0uV
45+
RFC822Name X509:<RFC822>[email protected]
46+
SHA1PublicKey X509:<SHA1-PUKEY>cD2eF3gH4iJ5kL6mN7oP8qR9sT
47+
IssuerAndSubject X509:<I>DC=com,DC=contoso,CN=CONTOSO-DC-CA<S>DC=com,DC=contoso,OU=UserAccounts,CN=mfatest
48+
SKI X509:<SKI>aB1cD2eF3gH4iJ5kL6mN7oP8qR
49+
PrincipalName X509:<PN>[email protected]
50+
```
51+
### EXAMPLE 2
52+
```powershell
53+
> $output = Get-MsIdCBACertificateUserIdFromCertificate C:\path\to\certificate.cer -CertificateMapping Subject
54+
> $output
55+
X509:<S>DC=com,DC=contoso,OU=UserAccounts,CN=mfatest
56+
```
57+
58+
## PARAMETERS
59+
### -Path
60+
61+
Path to the certificate file, it can be either a cer or pem file.
62+
63+
### -Certificate
64+
Certificate from which the certificateUserIDs mappings will be extracted
65+
66+
### -CertificateMapping
67+
One of the values `PrincipalName`, `RFC822Name`, `IssuerAndSubject`, `Subject`, `SKI`, `SHA1PublicKey`, and `IssuerAndSerialNumber`
68+
To filer
69+
### CommonParameters
70+
71+
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
72+
73+
## INPUTS
74+
75+
### System.String
76+
77+
## OUTPUTS
78+
79+
### System.String
80+
81+
###
82+
```powershell
83+
@{
84+
PrincipalName = "X509:<PN>[email protected]"
85+
RFC822Name = "X509:<RFC822>[email protected]"
86+
IssuerAndSubject = "X509:<I>DC=com,DC=contoso,CN=CONTOSO-DC-CA<S>DC=com,DC=contoso,OU=UserAccounts,CN=mfatest"
87+
Subject = "X509:<S>DC=com,DC=contoso,OU=UserAccounts,CN=mfatest"
88+
SKI = "X509:<SKI>aB1cD2eF3gH4iJ5kL6mN7oP8qR"
89+
SHA1PublicKey = "X509:<SHA1-PUKEY>cD2eF3gH4iJ5kL6mN7oP8qR9sT"
90+
IssuerAndSerialNumber = "X509:<I>DC=com,DC=contoso,CN=CONTOSO-DC-CA<SR>eF3gH4iJ5kL6mN7oP8qR9sT0uV"
91+
}
92+
```
93+
## NOTES
94+
95+
## RELATED LINKS
96+
97+
[https://aka.ms/aadcba](https://aka.ms/aadcba)
98+
[certificateUserIds](https://learn.microsoft.com/en-us/entra/identity/authentication/concept-certificate-based-authentication-certificateuserids)

website/docs/commands/docusaurus.sidebar.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ module.exports = [
6161
'commands/Split-MsIdEntitlementManagementConnectedOrganization',
6262
'commands/Test-MsIdAzureAdDeviceRegConnectivity',
6363
'commands/Test-MsIdCBATrustStoreConfiguration',
64+
'commands/Get-MsIdCBACertificateUserIdFromCertificate',
6465
'commands/Update-MsIdApplicationSigningKeyThumbprint',
6566
'commands/Update-MsIdGroupWritebackConfiguration'
6667
];

0 commit comments

Comments
 (0)