Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/ITfoxtec.Identity.Saml2/Schemas/Metadata/EntitiesDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Security.Cryptography.X509Certificates;
using System.Xml;
using System.Xml.Linq;
using System.Text.RegularExpressions;
#if NETFULL
using System.IdentityModel.Tokens;
#else
Expand Down Expand Up @@ -49,6 +50,30 @@ public string IdAsString
/// </summary>
public int? ValidUntil { get; set; }

/// <summary>
/// [Optional]
/// Optional attribute indicates how long a metadata consumer should cache this metadata before attempting to re-fetch.
/// Value must be an XML Schema duration (https://www.w3.org/TR/xmlschema-2/#duration). Example: P1D, PT12H, P2Y3M.
/// Regex used for validation: ^-?P(\d*Y)?(\d*M)?(\d*D)?(T(\d*H)?(\d*M)?(\d*S)?)?$
Copy link

Copilot AI Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex pattern in the documentation (line 57) does not match the actual regex implementation. The documentation shows (\d*Y)?(\d*M)?(\d*D)? but the implementation uses (\d+Y)?(\d+M)?(\d+W)?(\d+D)? with \d+ instead of \d* and includes (\d+W)? for weeks.

Suggested change
/// Regex used for validation: ^-?P(\d*Y)?(\d*M)?(\d*D)?(T(\d*H)?(\d*M)?(\d*S)?)?$
/// Regex used for validation: ^-?P(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?$

Copilot uses AI. Check for mistakes.
/// Throws <see cref="ArgumentException"/> if set to a non-empty value that does not match the duration pattern.
/// </summary>
public string CacheDuration
{
get => _cacheDuration;
set
{
if(!string.IsNullOrEmpty(value) && !CacheDurationRegex.IsMatch(value))
{
throw new ArgumentException($"Invalid cacheDuration format. See https://www.w3.org/TR/xmlschema-2/#duration. Value: '{value}'");
}
_cacheDuration = value;
}
}

private string _cacheDuration;
// Require at least one date or time component after 'P' using a lookahead. See https://www.w3.org/TR/xmlschema-2/#duration
private static readonly Regex CacheDurationRegex = new Regex(@"^-?P(?=\d|T)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?$", RegexOptions.Compiled);
Comment on lines +74 to +75
Copy link

Copilot AI Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment and regex are placed between the private field declaration and the next property. This breaks the logical grouping of the CacheDuration property members. Move the regex and its comment to immediately follow the private field declaration at line 73.

Suggested change
// Require at least one date or time component after 'P' using a lookahead. See https://www.w3.org/TR/xmlschema-2/#duration
private static readonly Regex CacheDurationRegex = new Regex(@"^-?P(?=\d|T)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?$", RegexOptions.Compiled);
// Require at least one date or time component after 'P' using a lookahead. See https://www.w3.org/TR/xmlschema-2/#duration
private static readonly Regex CacheDurationRegex = new Regex(@"^-?P(?=\d|T)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?$", RegexOptions.Compiled);

Copilot uses AI. Check for mistakes.

/// <summary>
/// [Optional]
/// An metadata XML signature that authenticates the containing element and its contents.
Expand Down Expand Up @@ -118,6 +143,10 @@ protected IEnumerable<XObject> GetXContent()
{
yield return new XAttribute(Saml2MetadataConstants.Message.ValidUntil, DateTimeOffset.UtcNow.AddDays(ValidUntil.Value).UtcDateTime.ToString(Saml2Constants.DateTimeFormat, CultureInfo.InvariantCulture));
}
if (!string.IsNullOrEmpty(CacheDuration))
{
yield return new XAttribute(Saml2MetadataConstants.Message.CacheDuration, CacheDuration);
}
yield return new XAttribute(Saml2MetadataConstants.MetadataNamespaceNameX, Saml2MetadataConstants.MetadataNamespace);

if (Extensions != null)
Expand Down
33 changes: 33 additions & 0 deletions src/ITfoxtec.Identity.Saml2/Schemas/Metadata/EntityDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using System.Text.RegularExpressions;
#if NETFULL
using System.IdentityModel.Tokens;
#else
Expand Down Expand Up @@ -53,6 +54,30 @@ public string IdAsString
/// </summary>
public int? ValidUntil { get; set; }

/// <summary>
/// [Optional]
/// Optional attribute indicates how long a metadata consumer should cache this metadata before attempting to re-fetch.
/// Value must be an XML Schema duration (https://www.w3.org/TR/xmlschema-2/#duration). Example: P1D, PT12H, P2Y3M.
/// Regex used for validation: ^-?P(\d*Y)?(\d*M)?(\d*D)?(T(\d*H)?(\d*M)?(\d*S)?)?$
Copy link

Copilot AI Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex pattern in the documentation (line 61) does not match the actual regex implementation. The documentation shows (\d*Y)?(\d*M)?(\d*D)? but the implementation uses (\d+Y)?(\d+M)?(\d+W)?(\d+D)? with \d+ instead of \d* and includes (\d+W)? for weeks.

Suggested change
/// Regex used for validation: ^-?P(\d*Y)?(\d*M)?(\d*D)?(T(\d*H)?(\d*M)?(\d*S)?)?$
/// Regex used for validation: ^-?P(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?$

Copilot uses AI. Check for mistakes.
/// Throws <see cref="ArgumentException"/> if set to a non-empty value that does not match the duration pattern.
/// </summary>
public string CacheDuration
{
get => _cacheDuration;
set
{
if(!string.IsNullOrEmpty(value) && !CacheDurationRegex.IsMatch(value))
{
throw new ArgumentException($"Invalid cacheDuration format. See https://www.w3.org/TR/xmlschema-2/#duration. Value: '{value}'");
}
_cacheDuration = value;
}
}

private string _cacheDuration;
// Require at least one date or time component after 'P' using a lookahead. See https://www.w3.org/TR/xmlschema-2/#duration
private static readonly Regex CacheDurationRegex = new Regex(@"^-?P(?=\d|T)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?$", RegexOptions.Compiled);
Comment on lines +78 to +79
Copy link

Copilot AI Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment and regex are placed between the private field declaration and the next property. This breaks the logical grouping of the CacheDuration property members. Move the regex and its comment to immediately follow the private field declaration at line 77.

Suggested change
// Require at least one date or time component after 'P' using a lookahead. See https://www.w3.org/TR/xmlschema-2/#duration
private static readonly Regex CacheDurationRegex = new Regex(@"^-?P(?=\d|T)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?$", RegexOptions.Compiled);
// Require at least one date or time component after 'P' using a lookahead. See https://www.w3.org/TR/xmlschema-2/#duration
private static readonly Regex CacheDurationRegex = new Regex(@"^-?P(?=\d|T)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?$", RegexOptions.Compiled);

Copilot uses AI. Check for mistakes.

/// <summary>
/// [Optional]
/// An metadata XML signature that authenticates the containing element and its contents.
Expand Down Expand Up @@ -154,6 +179,10 @@ protected IEnumerable<XObject> GetXContent()
{
yield return new XAttribute(Saml2MetadataConstants.Message.ValidUntil, DateTimeOffset.UtcNow.AddDays(ValidUntil.Value).UtcDateTime.ToString(Saml2Constants.DateTimeFormat, CultureInfo.InvariantCulture));
}
if (!string.IsNullOrEmpty(CacheDuration))
{
yield return new XAttribute(Saml2MetadataConstants.Message.CacheDuration, CacheDuration);
}
yield return new XAttribute(Saml2MetadataConstants.MetadataNamespaceNameX, Saml2MetadataConstants.MetadataNamespace);

if (Extensions != null)
Expand Down Expand Up @@ -208,6 +237,8 @@ public virtual EntityDescriptor ReadIdPSsoDescriptor(string idPMetadataXml)

Id = entityDescriptorElement.Attributes[Saml2MetadataConstants.Message.Id].GetValueOrNull<Saml2Id>();

CacheDuration = entityDescriptorElement.Attributes[Saml2MetadataConstants.Message.CacheDuration].GetValueOrNull<string>();

var idPSsoDescriptorElement = entityDescriptorElement[Saml2MetadataConstants.Message.IdPSsoDescriptor, Saml2MetadataConstants.MetadataNamespace.OriginalString];
if (idPSsoDescriptorElement != null)
{
Expand Down Expand Up @@ -236,6 +267,8 @@ public virtual EntityDescriptor ReadSPSsoDescriptor(string spMetadataXml)

Id = entityDescriptorElement.Attributes[Saml2MetadataConstants.Message.Id].GetValueOrNull<Saml2Id>();

CacheDuration = entityDescriptorElement.Attributes[Saml2MetadataConstants.Message.CacheDuration].GetValueOrNull<string>();

var spSsoDescriptorElement = entityDescriptorElement[Saml2MetadataConstants.Message.SPSsoDescriptor, Saml2MetadataConstants.MetadataNamespace.OriginalString];
if (spSsoDescriptorElement != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ public class Message

public const string ValidUntil = "validUntil";

public const string CacheDuration = "cacheDuration";

public const string ContactType = "contactType";

public const string Company = "Company";
Expand Down