Skip to content

Commit

Permalink
split id web into smaller nuget packages (tokencache & certificate) (#…
Browse files Browse the repository at this point in the history
…1437)

* separate token cache out, initial commit

* fix component governance issue w/microsoft.extensions 3.1.18

* Adding net standard 2.0 target

* support net standard 2.0 and remove 462 472

* few more updates

* move certificates to nuget package

* fix test

* add 462 472 target frameworks

* few more updates

* governance fix

* remove more dependencies

* fix governance

* move claimsPrincipalExtensions over

* merge conflicts 2

* move netstandard to 2.0

* fix nuget description & references

* remove internalsVisisibleTo.
implement George's FB

* update build w/new names

* fix build

* fix renaming issue

* feedback from karel

* use 2.1 for net standard 2.0

* re-add data protection for distributed cache

* move down to 3.0.0 for netcoreapp3.1

Co-authored-by: Jean-Marc Prieur <jmprieur@microsoft.com>
  • Loading branch information
jennyf19 and jmprieur authored Sep 20, 2021
1 parent 0e8a08d commit b31140f
Show file tree
Hide file tree
Showing 40 changed files with 1,551 additions and 3,528 deletions.
12 changes: 12 additions & 0 deletions Microsoft.Identity.Web.sln
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "mvcwebapp-graph", "tests\Mu
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GenerateMergeOptionsMethods", "tools\GenerateMergeOptionsMethods\GenerateMergeOptionsMethods.csproj", "{5B9AD363-6A27-4AF2-939E-B20E7C941ADF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Identity.Web.TokenCache", "src\Microsoft.Identity.Web.TokenCache\Microsoft.Identity.Web.TokenCache.csproj", "{7885DFBB-0D20-4115-86E2-709C2E12253B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Identity.Web.Certificate", "src\Microsoft.Identity.Web.Certificate\Microsoft.Identity.Web.Certificate.csproj", "{1E0B96CD-FDBF-482C-996A-775F691D984E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -288,6 +292,14 @@ Global
{5B9AD363-6A27-4AF2-939E-B20E7C941ADF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5B9AD363-6A27-4AF2-939E-B20E7C941ADF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5B9AD363-6A27-4AF2-939E-B20E7C941ADF}.Release|Any CPU.Build.0 = Release|Any CPU
{7885DFBB-0D20-4115-86E2-709C2E12253B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7885DFBB-0D20-4115-86E2-709C2E12253B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7885DFBB-0D20-4115-86E2-709C2E12253B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7885DFBB-0D20-4115-86E2-709C2E12253B}.Release|Any CPU.Build.0 = Release|Any CPU
{1E0B96CD-FDBF-482C-996A-775F691D984E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E0B96CD-FDBF-482C-996A-775F691D984E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E0B96CD-FDBF-482C-996A-775F691D984E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E0B96CD-FDBF-482C-996A-775F691D984E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
3 changes: 3 additions & 0 deletions build/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
- [template-pack-and-sign-nuget.yaml](template-pack-and-sign-nuget.yaml) `('$(Build.SourcesDirectory)\src\Microsoft.Identity.Web.MicrosoftGraph')`
- [template-pack-and-sign-nuget.yaml](template-pack-and-sign-nuget.yaml) `('$(Build.SourcesDirectory)\src\Microsoft.Identity.Web.MicrosoftGraphBeta')`
- [template-pack-and-sign-nuget.yaml](template-pack-and-sign-nuget.yaml) `('$(Build.SourcesDirectory)\ProjectTemplates')`
- [template-pack-and-sign-nuget.yaml](template-pack-and-sign-nuget.yaml) `('$(Build.SourcesDirectory)\src\Microsoft.Identity.Web.TokenCache')`
- [template-pack-and-sign-nuget.yaml](template-pack-and-sign-nuget.yaml) `('$(Build.SourcesDirectory)\src\Microsoft.Identity.Web.Certificate')
- [template-pack-and-sign-nuget.yaml](template-pack-and-sign-nuget.yaml) `('$(Build.SourcesDirectory)\src\Microsoft.Identity.Certificate')`
- 'Copy Files from `$(Build.SourcesDirectory)` to: `$(Build.ArtifactStagingDirectory)\packages'`
- Sign Packages `'('$(Build.ArtifactStagingDirectory)\packages')`
- [template-publish-packages-and-symbols.yaml](template-publish-packages-and-symbols.yaml)
Expand Down
18 changes: 16 additions & 2 deletions build/template-pack-and-sign-all-nugets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,34 @@ steps:
ProjectRootPath: '$(Build.SourcesDirectory)\src\Microsoft.Identity.Web.UI'
AssemblyName: 'Microsoft.Identity.Web.UI*'

# Pack and sign Microsoft.Identity.Web.UI
# Pack and sign Microsoft.Identity.Web.MicrosoftGraph
- template: template-pack-and-sign-nuget.yaml
parameters:
BuildConfiguration: ${{ parameters.BuildConfiguration }}
ProjectRootPath: '$(Build.SourcesDirectory)\src\Microsoft.Identity.Web.MicrosoftGraph'
AssemblyName: 'Microsoft.Identity.Web.MicrosoftGraph*'

# Pack and sign Microsoft.Identity.Web.UI
# Pack and sign Microsoft.Identity.Web.MicrosoftGraphBeta
- template: template-pack-and-sign-nuget.yaml
parameters:
BuildConfiguration: ${{ parameters.BuildConfiguration }}
ProjectRootPath: '$(Build.SourcesDirectory)\src\Microsoft.Identity.Web.MicrosoftGraphBeta'
AssemblyName: 'Microsoft.Identity.Web.MicrosoftGraphBeta*'

# Pack and sign Microsoft.Identity.TokenCache
- template: template-pack-and-sign-nuget.yaml
parameters:
BuildConfiguration: ${{ parameters.BuildConfiguration }}
ProjectRootPath: '$(Build.SourcesDirectory)\src\Microsoft.Identity.Web.TokenCache'
AssemblyName: 'Microsoft.Identity.Web.TokenCache*'

# Pack and sign Microsoft.Identity.Certificate
- template: template-pack-and-sign-nuget.yaml
parameters:
BuildConfiguration: ${{ parameters.BuildConfiguration }}
ProjectRootPath: '$(Build.SourcesDirectory)\src\Microsoft.Identity.Web.Certificate'
AssemblyName: 'Microsoft.Identity.Web.Certificate*'

# Pack and sign Microsoft.Identity.Web.ProjectTemplates
- template: template-pack-and-sign-nuget.yaml
parameters:
Expand Down
15 changes: 15 additions & 0 deletions src/Microsoft.Identity.Web.Certificate/CertificateConstants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace Microsoft.Identity.Web
{
/// <summary>
/// General constants for Microsoft Identity Certificates.
/// </summary>
internal static class CertificateConstants
{
// Certificates
internal const string MediaTypePksc12 = "application/x-pkcs12";
internal const string PersonalUserCertificateStorePath = "CurrentUser/My";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public static CertificateDescription FromPath(string path, string? password = nu
/// <param name="certificateStoreLocation">Store location where to find the certificate.</param>
/// <param name="certificateStoreName">Store name where to find the certificate.</param>
/// <returns>A certificate description.</returns>
[Obsolete(IDWebErrorMessage.FromStoreWithThumprintIsObsolete, false)]
[Obsolete(CertificateErrorMessage.FromStoreWithThumprintIsObsolete, false)]
public static CertificateDescription FromStoreWithThumprint(
string certificateThumbprint,
StoreLocation certificateStoreLocation = StoreLocation.CurrentUser,
Expand Down Expand Up @@ -238,7 +238,7 @@ internal string? Container
/// </summary>
public string? Base64EncodedValue { get; set; }

#if DOTNET_462
#if DOTNET_462 || DOTNET_STANDARD_20
/// <summary>
/// Defines where and how to import the private key of an X.509 certificate.
/// </summary>
Expand Down
33 changes: 33 additions & 0 deletions src/Microsoft.Identity.Web.Certificate/CertificateErrorMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace Microsoft.Identity.Web
{
/// <summary>
/// Constants related to the error messages.
/// </summary>
internal static class CertificateErrorMessage
{
// Configuration IDW10100 = "IDW10100:"
public const string ClientSecretAndCertficateNull =
"IDW10104: Both client secret and client certificate cannot be null or whitespace, " +
"and only ONE must be included in the configuration of the web app when calling a web API. " +
"For instance, in the appsettings.json file. ";
public const string BothClientSecretAndCertificateProvided = "IDW10105: Both client secret and client certificate, " +
"cannot be included in the configuration of the web app when calling a web API. ";
public const string ClientCertificatesHaveExpiredOrCannotBeLoaded = "IDW10109: All client certificates passed to the configuration have expired or can't be loaded. ";

// Encoding IDW10600 = "IDW10600:"
public const string InvalidBase64UrlString = "IDW10601: Invalid Base64URL string. ";

// Certificates IDW10700 = "IDW10700:"
public const string OnlyPkcs12IsSupported = "IDW10701: Only PKCS #12 content type is supported. Found Content-Type: {0}. ";
public const string IncorrectNumberOfUriSegments = "IDW10702: Number of URI segments is incorrect: {0}, URI: {1}. ";
public const string InvalidCertificateStorePath = "IDW10703: Certificate store path must be of the form 'StoreLocation/StoreName'. " +
"StoreLocation must be one of 'CurrentUser', 'CurrentMachine'. " +
"StoreName must be empty or one of '{0}'. ";

// Obsolete messages IDW10800 = "IDW10800:"
public const string FromStoreWithThumprintIsObsolete = "IDW10803: Use FromStoreWithThumbprint instead, due to spelling error. ";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,60 @@ public void LoadIfNeeded(CertificateDescription certificateDescription)
}
}

/// <summary>
/// Load the first certificate from the certificate description list.
/// </summary>
/// <param name="certificateDescriptions">Description of the certificates.</param>
/// <returns>First certificate in the certificate description list.</returns>
public static X509Certificate2? LoadFirstCertificate(IEnumerable<CertificateDescription> certificateDescriptions)
{
DefaultCertificateLoader defaultCertificateLoader = new DefaultCertificateLoader();
CertificateDescription? certDescription = certificateDescriptions.FirstOrDefault(c =>
{
defaultCertificateLoader.LoadIfNeeded(c);
return c.Certificate != null;
});

return certDescription?.Certificate;
}

/// <summary>
/// Load all the certificates from the certificate description list.
/// </summary>
/// <param name="certificateDescriptions">Description of the certificates.</param>
/// <returns>All the certificates in the certificate description list.</returns>
public static IEnumerable<X509Certificate2?> LoadAllCertificates(IEnumerable<CertificateDescription> certificateDescriptions)
{
DefaultCertificateLoader defaultCertificateLoader = new DefaultCertificateLoader();
if (certificateDescriptions != null)
{
foreach (var certDescription in certificateDescriptions)
{
defaultCertificateLoader.LoadIfNeeded(certDescription);
if (certDescription.Certificate != null)
{
yield return certDescription.Certificate;
}
}
}
}

/// <summary>
/// Resets all the certificates in the certificate description list.
/// Use, for example, before a retry.
/// </summary>
/// <param name="certificateDescriptions">Description of the certificates.</param>
public static void ResetCertificates(IEnumerable<CertificateDescription>? certificateDescriptions)
{
if (certificateDescriptions != null)
{
foreach (var cert in certificateDescriptions)
{
cert.Certificate = null;
}
}
}

private static X509Certificate2 LoadFromBase64Encoded(string certificateBase64, X509KeyStorageFlags x509KeyStorageFlags)
{
byte[] decoded = Convert.FromBase64String(certificateBase64);
Expand Down Expand Up @@ -143,7 +197,7 @@ private static X509Certificate2 LoadFromBase64Encoded(string certificateBase64,
{
throw new InvalidOperationException(string.Format(
CultureInfo.InvariantCulture,
IDWebErrorMessage.IncorrectNumberOfUriSegments,
CertificateErrorMessage.IncorrectNumberOfUriSegments,
segments.Length,
certificate.SecretId));
}
Expand All @@ -155,21 +209,21 @@ private static X509Certificate2 LoadFromBase64Encoded(string certificateBase64,

// For PEM, you'll need to extract the base64-encoded message body.
// .NET 5.0 preview introduces the System.Security.Cryptography.PemEncoding class to make this easier.
if (Constants.MediaTypePksc12.Equals(secret.Properties.ContentType, StringComparison.OrdinalIgnoreCase))
if (CertificateConstants.MediaTypePksc12.Equals(secret.Properties.ContentType, StringComparison.OrdinalIgnoreCase))
{
return LoadFromBase64Encoded(secret.Value, x509KeyStorageFlags);
}

throw new NotSupportedException(
string.Format(
CultureInfo.InvariantCulture,
IDWebErrorMessage.OnlyPkcs12IsSupported,
CertificateErrorMessage.OnlyPkcs12IsSupported,
secret.Properties.ContentType));
}

private static X509Certificate2? LoadFromStoreWithThumbprint(
string certificateThumbprint,
string storeDescription = Constants.PersonalUserCertificateStorePath)
string storeDescription = CertificateConstants.PersonalUserCertificateStorePath)
{
StoreLocation certificateStoreLocation = StoreLocation.CurrentUser;
StoreName certificateStoreName = StoreName.My;
Expand All @@ -194,7 +248,7 @@ private static X509Certificate2 LoadFromBase64Encoded(string certificateBase64,

private static X509Certificate2? LoadFromStoreWithDistinguishedName(
string certificateSubjectDistinguishedName,
string storeDescription = Constants.PersonalUserCertificateStorePath)
string storeDescription = CertificateConstants.PersonalUserCertificateStorePath)
{
StoreLocation certificateStoreLocation = StoreLocation.CurrentUser;
StoreName certificateStoreName = StoreName.My;
Expand All @@ -217,22 +271,11 @@ private static X509Certificate2 LoadFromBase64Encoded(string certificateBase64,
return cert;
}

internal static void ResetCertificates(IEnumerable<CertificateDescription>? clientCertificates)
{
if (clientCertificates != null)
{
foreach (var cert in clientCertificates)
{
cert.Certificate = null;
}
}
}

private static X509Certificate2 LoadFromPath(
string certificateFileName,
string? password = null)
{
#if DOTNET_462
#if DOTNET_462 || DOTNET_STANDARD_20
return new X509Certificate2(
certificateFileName,
password,
Expand All @@ -258,7 +301,7 @@ private static void ParseStoreLocationAndName(
{
throw new ArgumentException(string.Format(
CultureInfo.InvariantCulture,
IDWebErrorMessage.InvalidCertificateStorePath,
CertificateErrorMessage.InvalidCertificateStorePath,
string.Join("', '", typeof(StoreName).GetEnumNames())));
}
}
Expand All @@ -285,30 +328,5 @@ private static void ParseStoreLocationAndName(
var cert = signingCert.OfType<X509Certificate2>().OrderByDescending(c => c.NotBefore).FirstOrDefault();
return cert;
}

internal /*for test only*/ static X509Certificate2? LoadFirstCertificate(IEnumerable<CertificateDescription> certificateDescription)
{
DefaultCertificateLoader defaultCertificateLoader = new DefaultCertificateLoader();
CertificateDescription? certDescription = certificateDescription.FirstOrDefault(c =>
{
defaultCertificateLoader.LoadIfNeeded(c);
return c.Certificate != null;
});

return certDescription?.Certificate;
}

internal /*for test only*/ static IEnumerable<X509Certificate2?> LoadAllCertificates(IEnumerable<CertificateDescription> certificateDescriptions)
{
DefaultCertificateLoader defaultCertificateLoader = new DefaultCertificateLoader();
foreach (var certDescription in certificateDescriptions)
{
defaultCertificateLoader.LoadIfNeeded(certDescription);
if (certDescription.Certificate != null)
{
yield return certDescription.Certificate;
}
}
}
}
}
Loading

0 comments on commit b31140f

Please sign in to comment.