diff --git a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2AuthenticationContext.cs b/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2AuthenticationContext.cs index b0caa9a6af..b777bd2011 100644 --- a/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2AuthenticationContext.cs +++ b/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/Saml2AuthenticationContext.cs @@ -68,6 +68,9 @@ public ICollection AuthenticatingAuthorities /// describes the authentication context declaration that follows. /// [Saml2Core, 2.7.2.2] /// + /// + /// The check for an absolute URI can be disabled by setting . + /// /// if 'value' is null. /// if 'value' is not an absolute Uri. public Uri ClassReference @@ -78,7 +81,7 @@ public Uri ClassReference if (value == null) throw LogArgumentNullException(nameof(value)); - if (!value.IsAbsoluteUri) + if (!value.IsAbsoluteUri && !AppContextSwitches.AllowRelativeUrisInSaml2AuthnContext) throw LogExceptionMessage(new ArgumentException(FormatInvariant(LogMessages.IDX13300, MarkAsNonPII(nameof(ClassReference)), value))); _classReference = value; diff --git a/src/Microsoft.IdentityModel.Tokens/AppContextSwitches.cs b/src/Microsoft.IdentityModel.Tokens/AppContextSwitches.cs index 7f32a2fb85..4638ea5e88 100644 --- a/src/Microsoft.IdentityModel.Tokens/AppContextSwitches.cs +++ b/src/Microsoft.IdentityModel.Tokens/AppContextSwitches.cs @@ -98,6 +98,14 @@ internal static class AppContextSwitches private static bool? _useCapitalizedXMLTypeAttr; internal static bool UseCapitalizedXMLTypeAttr => _useCapitalizedXMLTypeAttr ??= (AppContext.TryGetSwitch(UseCapitalizedXMLTypeAttrSwitch, out bool useCapitalizedXMLTypeAttr) && useCapitalizedXMLTypeAttr); + /// + /// When enabled, allows using relative URIs in SAML2 authentication context. + /// + internal const string AllowRelativeUrisInSaml2AuthnContextSwitch = "Switch.Microsoft.IdentityModel.AllowRelativeUrisInSaml2AuthnContext"; + private static bool? _allowRelativeUrisInSaml2AuthnContext; + internal static bool AllowRelativeUrisInSaml2AuthnContext => _allowRelativeUrisInSaml2AuthnContext ??= (AppContext.TryGetSwitch(AllowRelativeUrisInSaml2AuthnContextSwitch, out bool allowRelativeUris) && allowRelativeUris); + + /// /// Used for testing to reset all switches to its default value. /// @@ -123,6 +131,9 @@ internal static void ResetAllSwitches() _useCapitalizedXMLTypeAttr = null; AppContext.SetSwitch(UseCapitalizedXMLTypeAttrSwitch, false); + + _allowRelativeUrisInSaml2AuthnContext = null; + AppContext.SetSwitch(AllowRelativeUrisInSaml2AuthnContextSwitch, false); } } } diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2AuthenticationContextCollectionDefinition.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2AuthenticationContextCollectionDefinition.cs new file mode 100644 index 0000000000..32f0a0eb66 --- /dev/null +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2AuthenticationContextCollectionDefinition.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Xunit; + +namespace Microsoft.IdentityModel.Tokens.Saml.Tests +{ + [CollectionDefinition("Saml2AuthenticationContextTests", DisableParallelization = true)] + public class Saml2AuthenticationContextCollectionDefinition + { + // This class is used to define a collection for the Saml2AuthenticationContext tests. + // It allows the tests to run sequentially and share setup/teardown logic if needed. + } +} diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2AuthenticationContextTests.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2AuthenticationContextTests.cs index d9a0b63f4a..73f84ab65c 100644 --- a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2AuthenticationContextTests.cs +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2AuthenticationContextTests.cs @@ -7,6 +7,7 @@ namespace Microsoft.IdentityModel.Tokens.Saml.Tests { + [Collection("Saml2AuthenticationContextTests")] public class Saml2AuthenticationContextTests { [Fact] diff --git a/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2AuthenticationContextWithAppContextTests.cs b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2AuthenticationContextWithAppContextTests.cs new file mode 100644 index 0000000000..31d276b0a9 --- /dev/null +++ b/test/Microsoft.IdentityModel.Tokens.Saml.Tests/Saml2AuthenticationContextWithAppContextTests.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Xunit; +using Microsoft.IdentityModel.Tokens.Saml2; + +namespace Microsoft.IdentityModel.Tokens.Saml.Tests +{ + [Collection("Saml2AuthenticationContextTests")] + public class Saml2AuthenticationContextWithAppContextTests + { + [Fact] + public void Saml2AuthenticationContext_RelativeClassReference_AllowRelativeUris_NoException() + { + try + { + var classRef = new Uri("resource", UriKind.Relative); + AppContext.SetSwitch(AppContextSwitches.AllowRelativeUrisInSaml2AuthnContextSwitch, true); + var authContext = new Saml2AuthenticationContext + { + ClassReference = classRef + }; + Assert.Equal(classRef, authContext.ClassReference); + } + finally + { + AppContextSwitches.ResetAllSwitches(); + } + } + } +}