Question

Since our website cannot take credit cards directly we are routing the user, with credential and other misc variables, to a 'hosted page' on another site.

To go more in detail, this is how the user would access this generally:

  1. Go to our site and login with a username and password that they created previously. This uses the asp.net membership provider.

  2. Once logged in, we show them their account and they have a button to make a payment. Once they click this...

  3. They are prompted with a 'prepayment' page to verify the amount and various other bits of information. They click continue from here...

  4. So, the payment page is displayed within an iframe of our website. We redirect them to the external hosted webpage with the following code:

    < div align="center"> < iframe width="100%" height="600px" src="@Html.Raw(@ViewBag.GateWayWebsite)"> < /div>

  5. Once the payment page has been entered and the customer clicks submit, that site submits a post back to our website where they began and passes back the information about the charge. I grab this information and save it to our database and display a receipt.

Everything works fine except for #5. That works most of the time but about 1 in 10 come back with this message:

Event code: 4006 
Event message: Membership credential verification failed. 
Event time: 12/16/2013 4:32:22 AM 
Event time (UTC): 12/16/2013 12:32:22 PM 
Event ID: 42c509f2a25d46f0af17e72a52dfbbe5 
Event sequence: 38 
Event occurrence: 1 
Event detail code: 0 

Application information: 
    Application domain: /LM/W3SVC/3/ROOT/SuburbanCustPortal-1-130316693110399868 
    Trust level: Full 
    Application Virtual Path: /SuburbanCustPortal 
    Application Path: C:\inetpub\wp\SuburbanCustPortal\ 
    Machine name: WIN-OB929P97YAR 

Process information: 
    Process ID: 3620 
    Process name: w3wp.exe 
    Account name: NT AUTHORITY\NETWORK SERVICE 

Request information: 
    Request URL: https://myurl:443/SuburbanCustPortal/Account/Logon2 
    Request path: /SuburbanCustPortal/Account/Logon2 
    User host address: xx.xx.xx.xx 
    User:  
    Is authenticated: False 
    Authentication Type:  
    Thread account name: NT AUTHORITY\NETWORK SERVICE 

Name to authenticate: testuser 

I cannot get to happen on the handful of test cases that I've run which makes it that much more frustrating.

This is my web.config:

<?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>

  <appSettings>
    <add key="webpages:Version" value="1.0.0.0"/>
    <add key="ClientValidationEnabled" value="true"/>
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
    <add key="suburbanServiceUrl" value=""/>
  </appSettings>

  <system.web>

    <sessionState
      mode="InProc"
      stateConnectionString="tcpip=127.0.0.1:42424"
      stateNetworkTimeout="60"
      sqlConnectionString="data source=127.0.0.1;Integrated Security=SSPI"
      cookieless="false"
      timeout="60"
    />

    <customErrors mode="Off"/>
    <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"/>
      </assemblies>
    </compilation>
    <authentication mode="Forms">
      <!-- timeout: Gets and sets the amount of time, in minutes, allowed between requests
                    before the session-state provider terminates the session. -->
      <forms loginUrl="~/Account/LogOn" timeout="60"/>
    </authentication>

    <membership>
      <providers>
        <clear/>
        <add name="AspNetSqlMembershipProvider"
             type="System.Web.Security.SqlMembershipProvider"
             connectionStringName="ApplicationServices"
             enablePasswordRetrieval="false"
             enablePasswordReset="true"
             requiresQuestionAndAnswer="false"
             requiresUniqueEmail="true"
             maxInvalidPasswordAttempts="30"
             minRequiredPasswordLength="6"
             minRequiredNonalphanumericCharacters="0"
             passwordAttemptWindow="10"
             applicationName="webportal"/>
      </providers>

    </membership>

    <profile>
      <providers>
        <clear/>
        <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/"/>
      </providers>
    </profile>

    <roleManager enabled="true">
      <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 enableSessionState="true">
      <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>
  </system.web>

  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules runAllManagedModulesForAllRequests="true">
      <remove name="Session"/>
      <add name="Session" type="System.Web.SessionState.SessionStateModule"/>
    </modules>
    <httpProtocol>
    </httpProtocol>
    <staticContent>
      <clientCache cacheControlCustom="public"
      cacheControlMaxAge="00:00:01" cacheControlMode="UseMaxAge" />
    </staticContent>   
  </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>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_ISuburbanService" maxReceivedMessageSize="128072" />
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://localhost:2181/ISuburbanService.svc"
        binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ISuburbanService"
        contract="SuburbanService.ISuburbanService" name="BasicHttpBinding_ISuburbanService" />
    </client>
    <!--<bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_ISuburbanService" closeTimeout="00:01:00"
          openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
          allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
          maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
          messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
          useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <security mode="Transport">
            <transport clientCredentialType="Basic" proxyCredentialType="None"
              realm="" />
            <message clientCredentialType="UserName" algorithmSuite="Default" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="https://localhost/SuburbanHUB/ISuburbanService.svc"
        binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ISuburbanService"
        contract="SuburbanService.ISuburbanService" name="BasicHttpBinding_ISuburbanService" />
    </client>-->
    <!--<behaviors>
      <serviceBehaviors>
        <behavior name="SomeServiceServiceBehavior">
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>-->
  </system.serviceModel>
</configuration>

And the method that captures the post:

  [NoCache]
    [HttpPost]
    public ActionResult Receipt(string id)
    {
      var sb = new StringBuilder();
      try
      {
        sb.AppendLine("ActionResult Reciept(string account)");

        var count = 0;
        var postVals = new Dictionary<string, string>();
        foreach (var key in Request.Form.AllKeys)
        {
          sb.AppendLine("count: " + count);
          sb.AppendLine(string.Format("key:   {0}    Value:   {1}", key, Request.Form[key]));
          postVals.Add(key, Request.Form[key]);
          sb.AppendLine("finished count: " + count);
          count++;
        }
        sb.AppendLine("finished processing ALLKeys");
        var paymentReq = createPaymentRequest(postVals);
        sb.AppendLine("finished processing 'var paymentReq = createPaymentRequest(postVals)' ");
        var receipt = _client.RecordPaymentWithRequest(paymentReq);

        var retval = PartialView(receipt.Duplicate ? "Duplicate Receipt" : "Receipt", receipt);
        sb.AppendLine(string.Format("retval: {0}", retval));
        return retval;

      }
      catch (Exception ex)
      {
        sb.AppendLine(string.Format("Receipt error: {0}", ex.Message));
        Logging.LogException("Receipt error!", ex, _asName);
        throw;
      }
      finally
      {
        Logging.LogInfo(sb.ToString(), _asName);
      }
    }

As you can see above, I don't have [Authorize] on it so it shouldn't be requiring membership provider to check for access. The class level does not either.

Anyone have any suggestions of what might be going on?

UPDATE

2013-12-16 04:22:14 xxx.xxx.xxx.xxx GET /SuburbanCustPortal/Scripts/Views/logon.js - 443 - xxx.xxx.xxx.xxx Mozilla/5.0+(Linux;+Android+4.2.2;+en-us;+SAMSUNG+SGH-M919+Build/JDQ39)+AppleWebKit/535.19+(KHTML,+like+Gecko)+Version/1.0+Chrome/18.0.1025.308+Mobile+Safari/535.19 304 0 0 109
2013-12-16 04:22:14 xxx.xxx.xxx.xxx GET /SuburbanCustPortal/Content/images/mod/modavoca.png - 443 - xxx.xxx.xxx.xxx Mozilla/5.0+(Linux;+Android+4.2.2;+en-us;+SAMSUNG+SGH-M919+Build/JDQ39)+AppleWebKit/535.19+(KHTML,+like+Gecko)+Version/1.0+Chrome/18.0.1025.308+Mobile+Safari/535.19 304 0 0 93
2013-12-16 04:22:15 xxx.xxx.xxx.xxx GET /Content/favicon.ico - 443 - xxx.xxx.xxx.xxx Mozilla/5.0+(Linux;+Android+4.2.2;+en-us;+SAMSUNG+SGH-M919+Build/JDQ39)+AppleWebKit/535.19+(KHTML,+like+Gecko)+Version/1.0+Chrome/18.0.1025.308+Mobile+Safari/535.19 404 0 2 250
2013-12-16 04:22:15 xxx.xxx.xxx.xxx GET /apple-touch-icon-precomposed.png - 443 - xxx.xxx.xxx.xxx Mozilla/5.0+(Linux;+Android+4.2.2;+en-us;+SAMSUNG+SGH-M919+Build/JDQ39)+AppleWebKit/535.19+(KHTML,+like+Gecko)+Version/1.0+Chrome/18.0.1025.308+Mobile+Safari/535.19 404 0 2 250
2013-12-16 04:22:15 xxx.xxx.xxx.xxx GET /apple-touch-icon.png - 443 - xxx.xxx.xxx.xxx Mozilla/5.0+(Linux;+Android+4.2.2;+en-us;+SAMSUNG+SGH-M919+Build/JDQ39)+AppleWebKit/535.19+(KHTML,+like+Gecko)+Version/1.0+Chrome/18.0.1025.308+Mobile+Safari/535.19 404 0 2 78
#Software: Microsoft Internet Information Services 7.0
#Version: 1.0
#Date: 2013-12-16 04:39:52
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) sc-status sc-substatus sc-win32-status time-taken
2013-12-16 04:39:52 xxx.xxx.xxx.xxx GET / - 443 - xxx.xxx.xxx.xxx - 200 0 0 171
2013-12-16 04:50:12 xxx.xxx.xxx.xxx POST /SuburbanHUB/ISuburbanService.svc - 443 suburbansoftware xxx.xxx.xxx.xxx - 200 0 0 875
2013-12-16 04:50:12 xxx.xxx.xxx.xxx POST /SuburbanHUB/ISuburbanService.svc - 443 suburbansoftware xxx.xxx.xxx.xxx - 200 0 0 187
2013-12-16 04:50:12 xxx.xxx.xxx.xxx GET /SuburbanCustPortal/Account/Verify id=dde4bbfb-0d2e-4706-a604-36eea3fdcae3&verifyid=c0b4fdb5-9bb3-4d2b-b724-df42e6ea2a59 443 - xxx.xxx.xxx.xxx Mozilla/5.0+(iPhone;+CPU+iPhone+OS+7_0_3+like+Mac+OS+X)+AppleWebKit/537.51.1+(KHTML,+like+Gecko)+Version/7.0+Mobile/11B511+Safari/9537.53 200 0 0 1328
2013-12-16 04:50:12 xxx.xxx.xxx.xxx GET /SuburbanCustPortal/Content/reset.css - 443 - xxx.xxx.xxx.xxxMozilla/5.0+(iPhone;+CPU+iPhone+OS+7_0_3+like+Mac+OS+X)+AppleWebKit/537.51.1+(KHTML,+like+Gecko)+Version/7.0+Mobile/11B511+Safari/9537.53 200 0 0 453

There is a lapse in the log from 04:22:15 through 04:39:52

Is this normal?

EDIT

I clarified the steps above for those who asked.

Was it helpful?

Solution

That's awfully suspicious to happen right at that time.

I would agree, but it seems that in step #4 you redirect off the site, and then the user does data entry. If a user occasionally takes 10-20 minutes to enter that information (due to distraction, etc.), it makes it much more likely than if it were just a simple race condition.

If you still have the data from all the errors, you may be able to look back to see if you can find a pattern to the times when this happens (or every xx hours--see below).

  1. Check your IIS settings to see when the app pool recycles. Does it recycle around 4am every night? Is it on a rolling schedule? By default, IIS recycles on some odd number of hours for some reason (I think every 28 hours).
  2. Get off of InProc Session state and into State Server (or SQL). InProc is only going to cause you pain anyway in the long run. Note that when you make this change, you have to ensure that all objects you put into session are serializable, otherwise you will get errors. InProc does not require objects to be serialized in session.

Edit: Ok, to check your app pool recycling:

  1. In IIS Manager, select the appropriate app pool and select Advanced Settings (right click or use right side menu).
  2. Scroll to the bottom, to section Recycling
  3. Regular Time Interval will reset the app pool every xx minutes. The default is 1740 minutes, or every 29 hours.
  4. The Specific Times setting allows you to set a scheduled time for it to recycle.

In general, you DO want to recycle the app pool periodically (probably daily).

To answer your second question: if this is indeed the cause, it's not a question of timeout; it's a question of whether the app pool recycles during the period of time between when they are redirected away and when they get redirected back. Changing your session state to something other than InProc should solve this problem.

That said, the session expiring could ALSO be the cause of this, so setting your session timeout to a larger value could also resolve this.

If you take a more extensive look at the logs during periods of time when this happened, it might give more clues to what is happening.

Edit #2

See if you can isolate the occurrences of the error in the logs. If you can, see if there is a pattern to the browser that is being used. I would also look for other patterns to see if anything jumps out.

You might just test with a bunch of different browsers (including mobile) to see if you can reproduce. Also, try different versions of IE and different security settings on IE.

OTHER TIPS

Please refer to the following article by ScottGu http://weblogs.asp.net/scottgu/archive/2006/04/22/Always-set-the-_2200_applicationName_2200_-property-when-configuring-ASP.NET-2.0-Membership-and-other-Providers.aspx.

In addition,make sure that the “ApplicationName” value in “aspnet_Applications” database table and the “applicationName” property value for all providers in web.config (Membership provider, Role provider, Profile provider etc.) must have the same value carefully again.

Hope this would fix your problem!

The few things I found in your web.config are -

  1. You have multiple applicationName. Normally, IsUserInRole and GetRolesForUser should fail if applicationName are not same.

  2. In addition, you want to set defaultProvider for each provider especially if you have more than one provider like roleManager - <roleManager ... defaultProvider="DefaultRoleProvider">

Current Web.config

<membership>
   <providers>
      <clear/>
          <add ... applicationName="webportal"/>
   </providers>
</membership>

<profile>
   <providers>
      <clear/>
      <add ... applicationName="/"/>
    </providers>
</profile>

<roleManager enabled="true">
   <providers>
      <clear/>
      <add ... applicationName="/"/>
      <add ...  applicationName="/"/>
   </providers>
</roleManager>

Take a look at web.config of Scott Hanselman's ASP.NET Universal Providers blog.

<sessionState
   mode="InProc"
   stateConnectionString="tcpip=127.0.0.1:42424"
   stateNetworkTimeout="60"
   sqlConnectionString="data source=127.0.0.1;Integrated Security=SSPI"
   cookieless="false"
   timeout="60"
/>

You do not need stateConnectionString, stateNetworkTimeout and sqlConnectionString for InProc. More information here.

Its been a while since I have troubleshot issues like this (but I did it for pss over 7 yrs ago).

Everything that @PhilSandler recommended is good. However I have a gut feeling the root cause is NOT AppPool recycling or Session time outs, if you do get desperate you could try Out-Of-Process Session State.

I'm thinking if its roughly 1 out of 10 users and it appears intermittent (as you cannot reproduce it), then its probably going to be a browser specific setting. I'm guessing users which encounter the problem have cookies disabled in their browsers (FF and Chrome users are more switched on than regular IE users).

This hypothesis would slightly match up with @SilverlightFox theory:

the frameset that is preventing 3rd party cookies


<authentication mode="Forms">

I'm thinking that the forms authentication cant store the session data on client side. Membership credential verification failed event log entries can be caused due to disabled cookies.

Please disable cookies in FF or Chrome and try out my hypothesis. Fingers crossed this allows you to reproduce it.

After looking around the web, here are the solutions I've found where people have had your 4006 error and ultimately fixed the issue.

  • applicationName field set to "/". - This is the most common conversation about your issue. But, your applicationName field looks fine so that's definitely not it.

  • Problem with ActiveDirectoryMembershipProvider - Link. This seems unlikely to be your problem because you're using the SqlMembershipProvider.

  • Internet user missing permissions on the .mdf and .ldf files - Link. The references to this problem that I saw were with people using SQLExpress because it runs under the ASP.NET user account and needs read/write access. Again, this seems unlikely to be be your problem because your only having it intermittently. But it is related to the 4006 error, so verifying permissions on the user seems worth looking at.

  • Duplicated User Passwords - I didn't save a link, but if you don't have unique constraints on both username and password in the database, it can return the 4006 response. So, far this seems most probable too me because it would explain the intermittent behavior and because people frequently double-click when using the internet. I would double and triple check your constraints.

I'll be happy to see what else I can find, but ruling out the last two of these first seems like a good idea. Also, the thing that seems the most odd about the gap in your logs is the fact that the EventLog data shows the error happening almost in the middle of the IIS gap. Then after it resumes, there is another log gap. It looks like it might be two completely different users. Maybe not, Just throwing that out there. Let me know. Good luck.

I notice that the src isn't set correctly on the IFrame.

<div align="center"> <iframe width="100%" height="600px" src="@Html.Raw(@ViewBag.GateWayWebsite)"></iframe></div>

The GateWayWebsite should be properly HTML encoded in case it contains special characters that are relevant but are not being passed properly:

<div align="center"> <iframe width="100%" height="600px" src="@ViewBag.GateWayWebsite"></iframe></div>

Another thought is that it could be that the frameset that is preventing 3rd party cookies - either the browser setting or the P3P privacy policy header. Try opening the link outside of the IFrame (i.e. so the address bar changes to the external site), just as a test to see if this resolves your issues.

Edit: I shouldn't have edited my answer as you have now reverted your upvote. My answer is technically correct, although it might not be the answer that fixes your current problem, I am right that the output of the URL is wrong as you are not HTML encoding it. I find it is best to fix everything as this reduces the chances of niggly bugs occurring in future that are difficult to debug.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top