-
Notifications
You must be signed in to change notification settings - Fork 401
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(feature): Add ActiveTokenEndpoint to WsFederationConfiguration (#2100)
Added WsFederationConfigurationValidator, updates to WsFederationMetadataSerializer/WsFederationConfiguration Added support to the WsFederationMetadataSerializer to read the SecurityTokenSerivceEndpoint element from WS-Federation metadata and exposed it via the WsFederationConfiguration object as ActiveTokenEndpoint. Added WsFederationConfigurationValidator and related test cases.
- Loading branch information
1 parent
5068c6e
commit 23808d5
Showing
12 changed files
with
900 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
205 changes: 205 additions & 0 deletions
205
....IdentityModel.Protocols.WsFederation/Configuration/WsFederationConfigurationValidator.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,205 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
using System.Security.Cryptography; | ||
using System.Security.Cryptography.X509Certificates; | ||
using Microsoft.IdentityModel.Tokens; | ||
using Microsoft.IdentityModel.Xml; | ||
using static Microsoft.IdentityModel.Logging.LogHelper; | ||
|
||
namespace Microsoft.IdentityModel.Protocols.WsFederation | ||
{ | ||
/// <summary> | ||
/// Defines a class for validating the WsFederationConfiguration. | ||
/// </summary> | ||
public class WsFederationConfigurationValidator : IConfigurationValidator<WsFederationConfiguration> | ||
{ | ||
/// <summary> | ||
/// Validates a WsFederationConfiguration. | ||
/// </summary> | ||
/// <param name="configuration">WsFederationConfiguration to validate</param> | ||
/// <returns>A <see cref="ConfigurationValidationResult"/> containing the validation result.</returns> | ||
/// <exception cref="ArgumentNullException">If the provided configuration is null</exception> | ||
public ConfigurationValidationResult Validate(WsFederationConfiguration configuration) | ||
{ | ||
if (configuration == null) | ||
throw LogArgumentNullException(nameof(configuration)); | ||
|
||
if (string.IsNullOrWhiteSpace(configuration.Issuer)) | ||
{ | ||
return new ConfigurationValidationResult | ||
{ | ||
ErrorMessage = LogMessages.IDX22700, | ||
Succeeded = false | ||
}; | ||
} | ||
|
||
if (configuration.Signature == null) | ||
{ | ||
return new ConfigurationValidationResult | ||
{ | ||
ErrorMessage = LogMessages.IDX22701, | ||
Succeeded = false | ||
}; | ||
} | ||
|
||
if (configuration.Signature.KeyInfo == null) | ||
{ | ||
return new ConfigurationValidationResult | ||
{ | ||
ErrorMessage = LogMessages.IDX22702, | ||
Succeeded = false | ||
}; | ||
} | ||
|
||
if (string.IsNullOrWhiteSpace(configuration.Signature.SignatureValue)) | ||
{ | ||
return new ConfigurationValidationResult | ||
{ | ||
ErrorMessage = LogMessages.IDX22703, | ||
Succeeded = false | ||
}; | ||
} | ||
|
||
if (configuration.Signature.SignedInfo == null) | ||
{ | ||
return new ConfigurationValidationResult | ||
{ | ||
ErrorMessage = LogMessages.IDX22704, | ||
Succeeded = false | ||
}; | ||
} | ||
|
||
if (string.IsNullOrWhiteSpace(configuration.Signature.SignedInfo.SignatureMethod)) | ||
{ | ||
return new ConfigurationValidationResult | ||
{ | ||
ErrorMessage = LogMessages.IDX22705, | ||
Succeeded = false | ||
}; | ||
} | ||
|
||
if (configuration.Signature.SignedInfo.References == null || configuration.Signature.SignedInfo.References.Count == 0) | ||
{ | ||
return new ConfigurationValidationResult | ||
{ | ||
ErrorMessage = LogMessages.IDX22706, | ||
Succeeded = false | ||
}; | ||
} | ||
|
||
if (string.IsNullOrWhiteSpace(configuration.ActiveTokenEndpoint)) | ||
{ | ||
return new ConfigurationValidationResult | ||
{ | ||
ErrorMessage = LogMessages.IDX22707, | ||
Succeeded = false | ||
}; | ||
} | ||
|
||
if (!Uri.IsWellFormedUriString(configuration.ActiveTokenEndpoint, UriKind.Absolute)) | ||
{ | ||
return new ConfigurationValidationResult | ||
{ | ||
ErrorMessage = LogMessages.IDX22708, | ||
Succeeded = false | ||
}; | ||
} | ||
|
||
if (string.IsNullOrWhiteSpace(configuration.TokenEndpoint)) | ||
{ | ||
return new ConfigurationValidationResult | ||
{ | ||
ErrorMessage = LogMessages.IDX22709, | ||
Succeeded = false | ||
}; | ||
} | ||
|
||
if (!Uri.IsWellFormedUriString(configuration.TokenEndpoint, UriKind.Absolute)) | ||
{ | ||
return new ConfigurationValidationResult | ||
{ | ||
ErrorMessage = LogMessages.IDX22710, | ||
Succeeded = false | ||
}; | ||
} | ||
|
||
if (configuration.SigningKeys == null || configuration.SigningKeys.Count == 0) | ||
{ | ||
return new ConfigurationValidationResult | ||
{ | ||
ErrorMessage = LogMessages.IDX22711, | ||
Succeeded = false | ||
}; | ||
} | ||
|
||
// Get the thumbprint of the cert used to sign the metadata | ||
string signingKeyId = string.Empty; | ||
var signatureX509Data = configuration.Signature.KeyInfo.X509Data.GetEnumerator(); | ||
|
||
if (signatureX509Data.MoveNext()) | ||
{ | ||
var signatureCertData = signatureX509Data.Current.Certificates.GetEnumerator(); | ||
if (signatureCertData.MoveNext() && !string.IsNullOrWhiteSpace(signatureCertData.Current)) | ||
{ | ||
X509Certificate2 cert = null; | ||
|
||
try | ||
{ | ||
cert = new X509Certificate2(Convert.FromBase64String(signatureCertData.Current)); | ||
signingKeyId = cert.Thumbprint; | ||
} | ||
catch (CryptographicException) | ||
{ | ||
return new ConfigurationValidationResult | ||
{ | ||
ErrorMessage = LogMessages.IDX22712, | ||
Succeeded = false | ||
}; | ||
} | ||
finally | ||
{ | ||
if (cert != null) | ||
{ | ||
((IDisposable)cert).Dispose(); | ||
} | ||
} | ||
} | ||
} | ||
|
||
// We know the key used to sign the doc is part of the token signing keys as per the spec. | ||
// http://docs.oasis-open.org/wsfed/federation/v1.2/os/ws-federation-1.2-spec-os.html#_Toc223174958:~:text=%3C/fed%3ATargetScopes%20%3E-,3.1.15%20%5BSignature%5D%20Property,-The%20OPTIONAL%20%5BSignature | ||
// If the metadata is for a token issuer then the key used to sign issued tokens SHOULD | ||
// be used to sign this document. This means that if a <fed:TokenSigningKey> is specified, | ||
// it SHOULD be used to sign this document. | ||
|
||
foreach (SecurityKey key in configuration.SigningKeys) | ||
{ | ||
if (key == null || key.CryptoProviderFactory == null || signingKeyId != key.KeyId) | ||
continue; | ||
|
||
try | ||
{ | ||
configuration.Signature.Verify(key, key.CryptoProviderFactory); | ||
|
||
return new ConfigurationValidationResult | ||
{ | ||
Succeeded = true | ||
}; | ||
} | ||
catch (XmlValidationException) | ||
{ | ||
// We know the signature is invalid at this point | ||
break; | ||
} | ||
} | ||
|
||
return new ConfigurationValidationResult | ||
{ | ||
ErrorMessage = LogMessages.IDX22713, | ||
Succeeded = false | ||
}; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.