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:
Go to our site and login with a username and password that they created previously. This uses the asp.net membership provider.
Once logged in, we show them their account and they have a button to make a payment. Once they click this...
They are prompted with a 'prepayment' page to verify the amount and various other bits of information. They click continue from here...
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>
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.
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).
Edit: Ok, to check your app pool recycling:
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.
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With