diff --git a/src/Microsoft.Identity.Web.TokenAcquisition/IDWebErrorMessage.cs b/src/Microsoft.Identity.Web.TokenAcquisition/IDWebErrorMessage.cs index 12a59bda6..e21d33406 100644 --- a/src/Microsoft.Identity.Web.TokenAcquisition/IDWebErrorMessage.cs +++ b/src/Microsoft.Identity.Web.TokenAcquisition/IDWebErrorMessage.cs @@ -51,6 +51,8 @@ internal static class IDWebErrorMessage public const string MicrosoftIdentityWebChallengeUserException = "IDW10502: An MsalUiRequiredException was thrown due to a challenge for the user. " + "See https://aka.ms/ms-id-web/ca_incremental-consent. "; public const string ProvidedAuthenticationSchemeIsIncorrect = "IDW10503: Cannot determine the cloud Instance. The provided authentication scheme was '{0}'. Microsoft.Identity.Web inferred '{1}' as the authentication scheme. Available authentication schemes are '{2}'. See https://aka.ms/id-web/authSchemes. "; + public const string InvalidAssertion = "IDW10504: Invalid assertion: contains unsupported character(s)."; + public const string InvalidSubAssertion = "IDW10505: Invalid sub_assertion: contains unsupported character(s)."; // Encoding IDW10600 = "IDW10600:" public const string InvalidBase64UrlString = "IDW10601: Invalid Base64URL string. "; diff --git a/src/Microsoft.Identity.Web.TokenAcquisition/TokenAcquisition.cs b/src/Microsoft.Identity.Web.TokenAcquisition/TokenAcquisition.cs index d51917375..89ae878f3 100644 --- a/src/Microsoft.Identity.Web.TokenAcquisition/TokenAcquisition.cs +++ b/src/Microsoft.Identity.Web.TokenAcquisition/TokenAcquisition.cs @@ -783,6 +783,10 @@ private void NotifyCertificateSelection(MergedOptions mergedOptions, IConfidenti // Special case when the OBO inbound token is composite (for instance PFT) if (dict.ContainsKey(assertionConstant) && dict.ContainsKey(subAssertionConstant)) { + + // Check assertion and sub_assertion passed from merging extra query parameters to ensure they do not contain unsupported character(s). + CheckAssertionsForInjectionAttempt(dict[assertionConstant], dict[subAssertionConstant]); + builder.OnBeforeTokenRequest((data) => { // Replace the assertion and adds sub_assertion with the values from the extra query parameters @@ -831,6 +835,20 @@ private void NotifyCertificateSelection(MergedOptions mergedOptions, IConfidenti } } + /// + /// Checks assertion and sub_assertion passed from merging extra query parameters to ensure they do not contain unsupported characters. + /// + /// The assertion. + /// The sub_assertion. + private static void CheckAssertionsForInjectionAttempt(string assertion, string subAssertion) + { + if (!assertion.IsNullOrEmpty() || !subAssertion.IsNullOrEmpty()) + { + if (!assertion.IsNullOrEmpty() && assertion.Contains('&', StringComparison.InvariantCultureIgnoreCase)) throw new ArgumentException(IDWebErrorMessage.InvalidAssertion, nameof(assertion)); + if (!subAssertion.IsNullOrEmpty() && (subAssertion.Contains('&', StringComparison.InvariantCultureIgnoreCase))) throw new ArgumentException(IDWebErrorMessage.InvalidSubAssertion, nameof(subAssertion)); + } + } + private static string? GetActualToken(SecurityToken? validatedToken) { JwtSecurityToken? jwtSecurityToken = validatedToken as JwtSecurityToken;