Пользовательский WIF запрос валидатора бесконечный цикл - PullRequest
5 голосов
/ 05 января 2012

Исправляя проблему, описанную здесь , я создал еще одну, которую я могу найти где-либо еще в Интернете:

SignInResponseMessage message = WSFederationMessage.CreateFromFormPost(context.Request) as SignInResponseMessage;

Приведенный выше код продолжает вызывать IsValidRequestString (), что вызывает бесконечный цикл. Вызов каждый раз один и тот же, и стек выглядит так:

>   TestIdentityBroker.dll!TestIdentityBroker.Service.WsFederationRequestValidator.IsValidRequestString(System.Web.HttpContext context, string value, System.Web.Util.RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex) Line 19    C#
[External Code] 
TestIdentityBroker.dll!TestIdentityBroker.Service.WsFederationRequestValidator.IsValidRequestString(System.Web.HttpContext context, string value, System.Web.Util.RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex) Line 19 + 0x21 bytes   C#
[External Code] 
TestIdentityBroker.dll!TestIdentityBroker.Service.WsFederationRequestValidator.IsValidRequestString(System.Web.HttpContext context, string value, System.Web.Util.RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex) Line 19 + 0x21 bytes   C#
[External Code] 
TestIdentityBroker.dll!TestIdentityBroker.Service.WsFederationRequestValidator.IsValidRequestString(System.Web.HttpContext context, string value, System.Web.Util.RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex) Line 19 + 0x21 bytes   C#
[External Code] 

Это происходит в пользовательской службе маркеров безопасности проверяющей стороны, которая объединяет идентификационные данные моей проверяющей стороны с ip, созданным инструментом FedUtil. Кто-нибудь знает, почему WSFederationMessage.CreateFromFormPost() будет вызывать валидатор запроса? Возвращенный неправильно кажется нормальным.

РЕДАКТИРОВАТЬ : Это происходит только тогда, когда я уже был один раз аутентифицирован ранее. Если я очищу кеш браузера, этого не произойдет.

<?xml version="1.0"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=152368
  -->
<configuration>
  <configSections>
    <section name="microsoft.identityModel" type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  </configSections>
  <connectionStrings>
    <add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient" />
  </connectionStrings>
  <appSettings>
    <add key="webpages:Version" value="1.0.0.0" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
    <add key="FederationMetadataLocation" value="X:\WebTest\TestIdentityBroker\TestIdentityBroker_STS\FederationMetadata\2007-06\FederationMetadata.xml" />
    <add key="SigningCertificateName" value="CN=Dev4"/>
  </appSettings>
  <location path="FederationMetadata">
    <system.web>
      <authorization>
        <allow users="*" />
      </authorization>
    </system.web>
  </location>
  <system.web>
    <!--<authorization>
      <deny users="?" />
    </authorization>-->
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      </assemblies>
    </compilation>
    <!--<authentication mode="Forms">
      <forms loginUrl="~/Federation/Authenticate" timeout="2880" />
    </authentication>-->
    <authentication mode="None" />
    <membership>
      <providers>
        <clear />
        <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
      </providers>
    </membership>
    <profile>
      <providers>
        <clear />
        <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/" />
      </providers>
    </profile>
    <roleManager enabled="false">
      <providers>
        <clear />
        <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" />
        <add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
      </providers>
    </roleManager>
    <pages>
      <namespaces>
        <add namespace="System.Web.Helpers" />
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
        <add namespace="System.Web.WebPages" />
      </namespaces>
    </pages>
    <httpRuntime requestValidationType="TestIdentityBroker.Service.WsFederationRequestValidator" />
    <httpModules>
      <add name="WSFederationAuthenticationModule" type="Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      <add name="SessionAuthenticationModule" type="Microsoft.IdentityModel.Web.SessionAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </httpModules>
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true">
      <add name="WSFederationAuthenticationModule" type="Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler" />
      <add name="SessionAuthenticationModule" type="Microsoft.IdentityModel.Web.SessionAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler" />
    </modules>
  </system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <microsoft.identityModel>
    <service>
      <audienceUris>
        <add value="https://rp_sts.local/" />
        <add value="https://rp_sts.local/Federation/LogOn" />
      </audienceUris>
      <federatedAuthentication>
        <wsFederation passiveRedirectEnabled="false" issuer="https://ip.local/" realm="https://rp_sts.local/" requireHttps="false" />
        <cookieHandler requireSsl="true" />
      </federatedAuthentication>
      <applicationService>
        <claimTypeRequired>
          <!--Following are the claims offered by STS 'http://ip.local/'. Add or uncomment claims that you require by your application and then update the federation metadata of this application.-->
          <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" optional="true" />
          <claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" optional="true" />
        </claimTypeRequired>
      </applicationService>
      <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
        <trustedIssuers>
          <add thumbprint="xx" name="https://ip.local/" />
        </trustedIssuers>
      </issuerNameRegistry>
    </service>
  </microsoft.identityModel>
</configuration>

Ответы [ 3 ]

2 голосов
/ 15 июля 2012

Проблема в том, что когда пользователь проходит аутентификацию, доступ к System.HttpContext.Current.Request во всех запускает RequestValidator для выполнения.

Таким образом, передача System.HttpContext.Current.Request ссылки в WSFederationMessage.CreateFromFormPost внутри RequestValidator запускает бесконечный цикл. Я не изучал причину возникновения этой проблемы.

Хотя вы можете решить не обрабатывать запросы пользователей, уже прошедших проверку подлинности на вашем STS (как вы это сделали), это не сработает, если ваш код является промежуточным STS, который зависит от другого поставщика. Например, если запрашивающий RP передает другой WHR, вы все равно хотите повторно обработать его до родительского STS в случае, если разные домашние области выдают разные утверждения.

В моем случае я был вынужден изменить свой валидатор запросов, просто возвращая true, если присутствует параметр wresult. При этом ответственность за проверку входящего сообщения делегируется коду, который обрабатывает запросы на вход:

public class WIFRequestValidator : RequestValidator
{
    protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)
    {
        validationFailureIndex = 0;

        if (requestValidationSource == RequestValidationSource.Form && collectionKey.Equals(WSFederationConstants.Parameters.Result, StringComparison.Ordinal))
        {
            return true;

            //SignInResponseMessage message = WSFederationMessage.CreateFromFormPost(context.Request) as SignInResponseMessage;
            //if (message != null)
            //{
                //return true;
            //}
        }

        return base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);
    }
}   
2 голосов
/ 18 ноября 2013

Оригинальная Technet вики-страница теперь содержит исправленную версию кода. Решение состоит в том, чтобы явно пропустить проверку при получении сбора данных POST.

var unvalidatedFormValues = System.Web.Helpers.Validation.Unvalidated(context.Request).Form;
SignInResponseMessage message = WSFederationMessage.CreateFromNameValueCollection( WSFederationMessage.GetBaseUrl( context.Request.Url ), unvalidatedFormValues ) as SignInResponseMessage;

Класс Validation принадлежит сборке System.Web.WebPages.dll, которая обычно устанавливается вместе с ASP.NET MVC.

Я не хотел связывать свою служебную библиотеку с MVC, поэтому я посмотрел на класс Validation с помощью декомпилятора и использовал метод более низкого уровня из Microsoft.Web.Infrastructure.dll, на который я уже ссылался:

var baseUrl = WSFederationMessage.GetBaseUrl(context.Request.Url);
Func<NameValueCollection> formGetter, queryStringGetter;
Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidationUtility.GetUnvalidatedCollections(context, out formGetter, out queryStringGetter);
if (WSFederationMessage.CreateFromNameValueCollection(baseUrl, formGetter()) is SignInResponseMessage)
    return true;
0 голосов
/ 06 марта 2012

В моем валидаторе пользовательских запросов (установленном в конфигурации):

<httpRuntime requestValidationType="TestIdentityBroker.Service.WsFederationRequestValidator" />

Он попытался преобразовать сообщение в сообщение WIF, и это вызвало функцию проверки, что привело к ... переполнению стека.

Исправлено путем обеспечения того, что поля являются полями WIF.

...