Welcome to MSDN Blogs Sign in | Join | Help

Issue with ActiveDirectoryMembershipProvider and account lock policy

Recently I was working on issue with ActiveDirectoryMembershipProvider of ASP.NET 2.0 and I came across interesting finding which I thought of sharing.

The scenario which I had was a little tricky. One of my customers was using ActiveDirectoryMembershipProvider along with the maxInvalidPasswordAttempts for locking the Active Directory User after 4 invalid attempts.

(Note - As per the information documentation around maxInvalidPasswordAttempts, this property does not control the number of failed logon attempts a user can make before being locked out. The Active Directory server handles failed logon attempts and is not affected by the value of this property.)

In the Active Directory configuration for account lock policy we had “Account lockout threshold” set to 4. So we set the value of maxInvalidPasswordAttempts to 4 to be in sync with the Active Directory configuration. But interestingly, when we try doing it… just after 2 invalid attempts the user’s account gets locked. That means if we set the “Account lockout threshold” to X then while using ActiveDirectoryMembershipProvider in ASP.NET 2.0 application, the account will get locked after just X/2 attempts.

I have confirmed that this behavior is by design. The reason behind that is internally ActiveDirectoryMembershipProvider uses IADsOpenDsObject::OpenDsObject method or the ADsOpenObject function. This function is supposed to validate the user via Kerberos first and if it fails then it tries with NTLM and in turn increments the BadPwdCount count by 2.

So in case if one is willing to use ActiveDirectoryMembershipProvider with account lock policy in place, then we have to make sure that we double the value for “Account lockout threshold” than required.

I hope this helps!

Posted by amitsh | 1 Comments
Filed under:

Why cacheRolesinCookie does not work well with the Ajax Extensions 1.0 and RoleManager of .NET Framework 2.0?

One of my customers ran into this issue couple of months ago. I wanted to blog it earlier but I was waiting for the Fix to come out.

The typical scenario is - you are using the System.Web.RoleManager of .NET Framework 2.0 along with Ajax Extensions. When you do a callback you might run into exception as below (changed the names as required) -

Event Type: Warning

Event Source:     ASP.NET 2.0.50727.0

Event Category:   Web Event

Event ID:   1309

Date:       10/16/2007

Time:       11:24:13 PM

User:       N/A

Computer:   ABCD

Description:

Event code: 3005

Event message: An unhandled exception has occurred.

Event time: 10/16/2007 11:24:12 PM

Event time (UTC): 10/17/2007 5:24:12 AM

Event ID: 3984df620d5148d58cfddc59a2c64559

Event sequence: 17219

Event occurrence: 95

Event detail code: 0

 

Application information:

    Application domain: /LM/W3SVC/12345/Root/Client-11-128370461828028786

    Trust level: Full

    Application Virtual Path: /Client

    Application Path: C:\Inetpub\wwwroot\Test\

    Machine name: ABCD

 

Process information:

    Process ID: 4448

    Process name: w3wp.exe

    Account name: ABCD\ABCD

 

Exception information:

    Exception type: HttpException

    Exception message: Server cannot modify cookies after HTTP headers have been sent.

 

Request information:

    Request URL: <http://Test/App_Themes/Default/Styles/Base.css>

    Request path: /App_Themes/Default/Styles/Base.css

    User host address: 71.123.134.143

    User: ABCD@ABCD.com

    Is authenticated: True

    Authentication Type: Forms

    Thread account name: ABCD\ABCD

 

Thread information:

    Thread ID: 18

    Thread account name: ABCD\ABCD

    Is impersonating: False

    Stack trace:    at System.Web.HttpCookieCollection.Add(HttpCookie cookie)

   at System.Web.Security.RoleManagerModule.OnLeave(Object source, EventArgs eventArgs)

   at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()

   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

 

 Custom event details:

For more information, see Help and Support Center at <http://go.microsoft.com/fwlink/events.asp>.

 

This comes up because you can’t send a set-cookie header after anything has been sent to the client.

Now the OnLeave event of RoleManager is set to be executed on App.EndRequest (Code taken from Reflector) –

public void Init(HttpApplication app)

{

    if (Roles.Enabled)

    {

        app.PostAuthenticateRequest += new EventHandler(this.OnEnter);

        app.EndRequest += new EventHandler(this.OnLeave);

    }

}

 

And when you use Ajax, HTTP Headers are sent back to client before Application_End and this OnLeave event will try  to modify the cookie if CacheRolesInCookie is true –

private void OnLeave(object source, EventArgs eventArgs)

{

    if (Roles.Enabled && Roles.CacheRolesInCookie)

    {

                .......

                .......

    }

}

 

Since the content is flushed by the time that code runs and the code does not check if something is sent to client already, the exception comes up.

This issue has been fixed in the .NET Framework 3.5 release. It still doesn’t send the cookie, but you won’t throw an exception. The code looks like below -

private void OnLeave(object source, EventArgs eventArgs)

{

    HttpApplication application = (HttpApplication) source;

    HttpContext context = application.Context;

    if (((Roles.Enabled && Roles.CacheRolesInCookie) && !context.Response.HeadersWritten) && (((context.User != null) && (context.User is RolePrincipal)) && context.User.Identity.IsAuthenticated))

    {

                .....

                .....

    }

}

 

There is no workaround for this issue in .NET Framework other than not using CacheRolesInCookie itself by setting it to false.

I hope this help!

Posted by amitsh | 1 Comments
Filed under: ,

Why I am not able Turn Off CustomErrors?

This week I got an interesting issue altogether. One of my customers was unable to turn off the CustomErrors at all. We checked all the web.config files in hierarchy including the web.config and machine.config in C:\WINNT\Microsoft.NET\Framework\v2.0.50727\CONFIG. All files had an entry <customErrors mode="Off"/>, purposefully added to avoid this behavior. But we were still getting below message whenever any exception comes up –

Server Error in '/Test' Application.

--------------------------------------------------------------------------------

Runtime Error

Description: An application error occurred on the server. The current custom error settings for this application prevent the details of the application error from being viewed.

Details: To enable the details of this specific error message to be viewable on the local server machine, please create a <customErrors> tag within a "web.config" configuration file located in the root directory of the current web application. This <customErrors> tag should then have its "mode" attribute set to "RemoteOnly". To enable the details to be viewable on remote machines, please set "mode" to "Off".

<!-- Web.Config Configuration File -->

<configuration>

    <system.web>

        <customErrors mode="RemoteOnly"/>

    </system.web>

</configuration>

 

Notes: The current error page you are seeing can be replaced by a custom error page by modifying the "defaultRedirect" attribute of the application's <customErrors> configuration tag to point to a custom error page URL.

<!-- Web.Config Configuration File -->

<configuration>

    <system.web>

        <customErrors mode="On" defaultRedirect="mycustompage.htm"/>

    </system.web>

</configuration>

 

This message was common while browsing the application on both client and server. So one thing was for sure that some setting in some config file is turning on the CustomErrors with mode = “on”.

Now customer wanted to see the exception which was coming up. Though ASP.NET 2.0 by default logs it in the event logs, it is not possible for all of the developers to log onto the server and check the event logs.

So while troubleshooting this issue we found the machine.config on the server is bigger than usual size (19KB).

So when I checked the machine.config file, we found it was having <deployment retail="true"/> added in it. This entry reminded me of Praveen’s Blog entry around debugging issue when retail is set to true. We removed it and we were spot on.

The use of the <deployment retail="true"/> switch in the machine.config file turns off the ability to show detailed ASP.NET error messages both to remote clients and locally. So effectively it acts as <customErrors mode="On"/> is set.

This deployment retail switch should still be your primary method of turning off these error messages (detailed errors on browsers) if you are running ASP.NET 2.0. (To get detailed information regarding ASP.NET exceptions, use the Application Event Log.)

The only resolution for this to remove the <deployment retail="true"/> switch by either commenting it out or setting retail= false.

Alternatively you can show the custom error pages itself as the messages suggest.

For more information on Retail member check http://msdn2.microsoft.com/en-us/library/system.web.configuration.deploymentsection.retail(VS.80).aspx.

I hope this help! 

 

Posted by amitsh | 8 Comments
Filed under:

Global.asa of 0 KB acts funny on Windows 2003 after installing SP2.

Few days’ back one funny issue came to me.  All of a sudden on one of the Windows 2003 server my customer was getting “HTTP/1.1 500 Server Error” for any .asp pages in the application. It stopped working since last couple days and used to work earlier. So here the obvious question would be - What was changed two days ago?

Customer confirmed that nothing but the installation of Service Pack 2(SP2) of Windows 2003 was done.

This sounded funny to me but when I tested the universal Time.asp (script showing the current time using <%=now()%>) in the same application, interestingly even that gave “HTTP/1.1 500 Server Error” too! No extra filters nothing and still this behavior and I was confused.

I started thinking about this issue and checked the entire IIS pipeline which can interfere with the request – ISAPI, Extension mapping etc. but no luck. So the only thing which remains is the “Global.asa” which comes in the pipeline before the page execution starts. And bingo found an empty (0 KB) Global.asa in the application. Renaming it to Global.asa.old and everything worked.

So I tried this on my own test machine and got to conclusion that having empty (0 KB) Global.asa breaks the .asp page request execution after SP2 is installed on Windows 2003 Server and you will start getting “HTTP/1.1 500 Server Error”.  Resolution to this would be not to leave this unwanted creature to live in the application :)

So if you have installed SP2 and simple test page is throwing an error “HTTP/1.1 500 Server Error”, make sure that you don’t have any Global.asa of 0 KB size in the application (possibilities are endless and it's one of them).

I hope this help!

Posted by amitsh | 2 Comments
Filed under: ,

What Vista Firewall settings required for enabling remote debugging?

This a bit tricky thing. We all know the famous KB for “How to turn on remote debugging in Windows XP with Service Pack 2, in Windows Server 2003 Service Pack 1, or in Windows Vista” and we do all these settings on the Vista box to turn on debugging.

But this is not quite enough some times and in one of the issues I came across we were getting below error message –

Unable to connect to the Microsoft Visual Studio Remote Debugging Monitor named 'server-computer name'. The Microsoft Visual Studio Remote Debugging Monitor on the remote computer cannot connect to the local computer. A firewall may be preventing communication via DCOM to the local computer. Please see Help for assistance.

 

This was a quite a puzzle for me as I was able to see that RDM was running and was showing the user as connected.

I was luckily able to repro the same on my machine as well and started looking for options. From the error message I thought windows 2003 server firewall might be blocking it. I tried turning on the firewalls completely on the server but still no luck for me at all.

So finally we have the situation it is the Vista Firewall setting but which one to change. Here are the steps which I followed –

- Opened “Control Panel -> Administrative Tools -> Local Security policy”.

- In the section "Windows Firewall with Advanced Security" I found "Windows Firewall with Advanced Security - Local Group Policy Object".  When I clicked on this, on the right hand side I found "Windows Firewall Properties"

- I clicked on that, it opened the "Windows Firewall with Advanced Security - Local Group Policy Object" dialog box.

- In this dialog box, we have different tabs to configure for various scenarios like "Domain Profile", "Private Profile" etc..

- For my scenario "Domain Profile" is the one as both my machines are in same domain. Under this tab, we have "Firewall State" which was set to "Not configured".

We also have Inbound connections and outbound connection which is set to "Not configured".

- I set the options as follows:

1. Firewall State = "On (recommended)"

2. Inbound connections = "Allow"

3. Outbound connections = "Allow (default)"

 This solved the problem. I was able to manually attach to the remote machine. I could see the process in the list and I could attach to remote W3WP process and successfully debug and hit the break points.

The similar settings I think we can do via command line as well as per the thread on discussion group.

I hope this help!

Posted by amitsh | 2 Comments
Filed under:

Need a Hotfix.. Get it online

At Microsoft PSS, we get a lot of Hotfix requests. Till few days ago we always required customers to call into Microsoft Product Support to get a Hotfix. But since few days we have made many, if not all, Hotfixes available on web. So now on getting Hotfix is as simple as filling up a simple online form and receive the Hotfix by email.

You can get detailed information about it here. And the link for the Hotfix form is this.

I hope this helps and makes you happy!

Posted by amitsh | 2 Comments
Filed under: ,

Why I cannot execute two requests from the same session simultaneously for an ASP.NET application?

Many a times we need pop-up windows to appear in Web Applications. In such a scenario we have the same user session used by the two instances of browser. So N pop-ups we open, N instances of browsers using the same user session.

So the question which will come in mind is will these requests using the same user session be executed concurrently?

So the answer to the question would be - may or may not be.

The request execution would be working fine concurrently till the time we are not accessing session data at all. If we would have accessed the session data anywhere in the request then the requests won’t be served concurrently. Requests will be executed one at a time.

We can check this behavior with a simple demo –

Have 2 pages in ASP.NET application as Default.aspx and LongRunningPage.aspx as below –

Default.aspx

<%@ Page Language="C#" %>
<html>
<head runat="server">
    <title>Default Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
      <a href="LongRunningPage.aspx?interval=50000" mce_href="LongRunningPage.aspx?interval=50000" target="_blank">Interval 50000</a><br />
        <br />
        <a href="LongRunningPage.aspx?interval=1000" mce_href="LongRunningPage.aspx?interval=1000" target="_blank">Interval 1000</a>
    </div>
    </form>
</body>
</html>

 

 LongRunningPage.aspx

<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
    protected void Page_Load(object sender, EventArgs e)
    {
        int interval = Convert.ToInt32(Request.QueryString["interval"].ToString());
        System.Threading.Thread.Sleep(interval);
    }
</script>

<html xmlns="
http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Long Running Page</title>
</head>
<body>
    <form id="form1" runat="server">
     <div>
       Displayed!!!
     </div>
    </form>
</body>
</html> 

Now when you click on the link “Interval 50000” on Default.aspx the first page will come up and will keep waiting for 50000ms. Meanwhile if you click on the link “Interval 1000” it will come up after waiting for 1000ms.

Now clear the browser cache and change the Page_Load for LongRunningPage.aspx as below –

protected void Page_Load(object sender, EventArgs e)
{
        int interval = Convert.ToInt32(Request.QueryString["interval"].ToString());
        Session["Test"] = "Test";
        System.Threading.Thread.Sleep(interval);
}

 

Now when you click on the link “Interval 50000” on Default.aspx the first page will come up and will keep waiting for 50000ms. Meanwhile if you click on the link “Interval 1000” it won’t come up till the first page comes (opened by clicking on the link “Interval 50000”) and then it will for 1000ms and then it will be rendered.

This is an expected behavior. The reason behind this is session state implements a reader/writer locking mechanism:

- A page (or frame) that has session state write access (e.g. <%@ Page EnableSessionState="True" %>)   will by default hold a writer lock on the session until the request finishes.

- A page (or frame) that has session state read access (e.g. <%@ Page EnableSessionState="ReadOnly" %>) will hold only a reader lock on the session until the request finishes.

- As we can understand based on concepts of locks - Reader lock will block a writer lock; Reader lock will NOT block reader lock; Writer lock will block all reader and writer lock.

This lock is acquired within the event AcquireRequestState and released in the event ReleaseRequestState of a request. That's why if two frames/pages both have session state write access (the default option unless you use EnableSessionState="ReadOnly" ), one frame/page has to wait for the other to finish first.

So the work around for your problem would be to use the ReadOnly Session access mode (for example using EnableSessionState="ReadOnly"   ) if we have requirement of only reading the session state else we have to make sure the requests are NOT long running.

Additionally you will also see similar behavior when we have a Global.asax in the application. By default if you do not have any Global.asax file in an ASP.Net application and there is no access to any session reading/writing effectively no session exists from ASP.Net perspective. So one trigger to make ASP.net create session infrastructure is to have Global.asax file and have events in there regarding Session’s start, end etc. This will trigger the sessions to be created and the request ultimately accesses the session via session events. So we will see the similar behavior when there is a Global.asax in the application as well and if you fire a next request for this same session it will be put on hold until the first one completes.

I hope this help. Happy Reading!!!

Posted by amitsh | 0 Comments
Filed under: ,

Why I get "Invalid postback or callback argument." Errors?

Introduction:

This is the first post of mine so thought of starting with a simple but tricky issue which I came across in few support incidents I handled.

I have got a scenario where one of customers were getting error message like -

Invalid Postback or callback argument . Event validation is enabled using <pages enableEventValidation="true"/> in configuration or <%@ Page EnableEventValidation="true" %> in a page.  For security purposes, this feature verifies that arguments to Postback or callback events originate from the server control that originally rendered them.  If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the Postback or callback data for validation.

 

Many of us get this error message lot of times either in event viewer or on the page itself. But what does it signify? When does it come up? What we can do to eliminate this exception due coding mistakes?

 

What does it signify?

In ASP.NET 2.0 we have added a feature called event validation. Event validation checks the incoming POST request to ensure that the event causing the Postback / callback is valid and the event which triggered the Postback /callback is expected by the Runtime. If the runtime finds a Postback / callback by an event which is not registered for validation, it throws an exception.  This has been added in ASP.NET 2.0 explicitly to prevent the attack to the application by spoofing a Postback. Event validation can help prevent injection attacks from malicious users who are trying to POST data by an event which does not come up from the controls registered to the page.

You can enable or disable this feature by simply setting up Property EnableEventValidation = true in the web.config or on the page level. By default it is enabled.

You can find more information about this property in the MSDN link as below -

http://msdn2.microsoft.com/en-us/library/system.web.configuration.pagessection.enableeventvalidation(VS.80).aspx

So this is about all the “good” which event validation signifies. Agreed that this is a very good security feature which helps preventing script injection attacks but if it is coming during the normal execution of an application, the exception is not expected and does not hold “good” anymore. That is where we need to troubleshoot and find out the problem area.

 

When does it come up? What we can do to eliminate this exception due coding mistakes?

As I have already spoken about the script injection attack can cause this exception, we should not bother about why it is coming up. Rather in that case we can track down the client who is trying to inject the attack and take appropriate action. So I will rather focus upon the scenarios when it comes up due some coding mistakes.

These mistakes are many in number so I would rather cover couple of them in this Post.

At this point I have few scenarios when it comes up –

1.     You have migrated ASP.NET application from version 1.1 to version 2.0. In 1.1 we had to manipulate the "Select" button column for selecting the record and we normally set the visible property of this button column to FALSE.

The button column has "LinkButton" /”Button” for selecting records and we manually do a Postback using the __dopostback() method.

Agreed that the "LinkButton" /”Button” should register this method for event validation by internally calling the ClientScript.RegisterForEventValidation(). But with the “Visible” property set to FALSE, the control is not rendered and therefore control is not registered for EventValidation by ASP.NET 2.0. However, the DataGrid still utilizes this event. Since the event is not registered, it results in the above error.

In this scenario manually registering the client script for each DataGrid rows will help.

You can simply loop through the rows as mentioned in below code.

 

protected override void Render(HtmlTextWriter writer)

{

foreach (DataGridItem row in DataGrid1.Items)

ClientScript.RegisterForEventValidation(row.UniqueID.ToString() +":_ctl0");

base.Render(writer);

}

 

So this signifies that if you are not rendering control then it is not registered for the validation internally. You need to do that manually using the RegisterForEventValidation function.

 

2.     You are having an ASP.NET 2.0 application which has a page with a lot of Javacript adding dynamic controls. On the POST of this particular page you will get the above mentioned exception for Invalid Postback or callback argument. This happens if Javascript is adding a FORM tag as well while adding dynamic controls resulting in the nested form Tags.

This can be reproduced quite easily as well –

In Default.aspx have the below code -

 

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs"

Inherits="_Default" %>

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

<title>Untitled Page</title>

</head>

<body>

<form id="form1" runat="server">

<div>

<asp:Button ID="Button1" runat="server" Text="Button" />

<form></form>

</div>

</form>

</body>

</html>

 

So this signifies that if you have nested form tags the above mentioned error message will come up.

 

So with these couple of scenarios I will stop at this point. I hope this first post of mine might help you and happy reading.

Posted by amitsh | 25 Comments
Filed under:
 
Page view tracker