Welcome to MSDN Blogs Sign in | Join | Help

A sa(i)mple Online Exam Engine on ASP.NET

Some time ago, a customer that attended my MSDN session, asked me to help him developing an online exam engine. They wanted something simple that retrieved questions from a database or a file and allowed employees to take some online exams. In order to simplify deployment, they wanted to do this on ASP.NET and SQL Server.

As I browsed in the internet, I did find a few samples but none that completely satisfied me. So, for the exercise, I decided to develop my own sample in a way that each of its components could be changed with ease. So, I decided to use a standard three tier model: presentation, business logic and data access.

For the presentation layer, I decided to use a simple ASP.NET web user control (ascx). This allows you to simply drag the control to your page to use it and also allows you to customize the display with the help of the VS.NET IDE.

The business logic layer is the one that I believe you will not want to change much. Possibly add a few things. I did the sample for illustration purposes. It's not intended to be a full-scale online exam engine, but rather a starting point for developing your own.

The data access layer is actually the one you WILL want to change. In order to get the sample working in a way you can test it with ease, I retrieve the exam questions from an xml file. I built this layer (QuestionRetriever.cs) in a way that it uses very simple methods to get simple pieces of information (number of questions, get question number x, time limit for this exam, etc.) so you shouldn't have any problems changing this methods to get the same data from a SQL server or another database engine.

This was the main concern when developing the sample: build the exam engine in a way that the physical location of the data is irrelevant.

You can test the sample here: http://nunosilva.members.winisp.net/samples/working/OnlineExamEngine/

The xml file that is used to generate this exam can be found here: http://nunosilva.members.winisp.net/samples/working/OnlineExamEngine/math.xml

The zip file containing the sample can be found here: http://nunosilva.members.winisp.net/samples/OnlineExamEngine.zip

Drilling down a bit, let's look at some of the main features here:

The ascx basically is responsible for displaying the exam from start to finish. To use it, you simply drag and drop it into a page. Then you must declare it in your code-behind file. The only thing that I don’t like here is you have to name it myQuestion1…

Why? Well, I do use some JavaScript to implement the timer. We set the timer to an initial value, the timer decrements itself each second and when it reaches 0, disables the buttons and sends the user to the scoring report. To implement this, and because I’m not a JavaScript expert, I have to reference the buttons and other controls on the page by its id. The problem is that, because we’re in a user control, ASP.NET renders all controls inside it with the user control name as a prefix (e.g. myQuestion1_timer) to avoid collisions. So, when I need to reference a control in JavaScript by its id, I have to make sure the user control name is a particular one. Of course you can choose another name but you’ll have to change the JavaScript yourself. By the way, if someone has a suggestion on how to change this please post a comment to this post.

After you declare the control, you set a property called exam_url that specifies where the exam file (xml) is located. One way to quickly change this to SQL server is setting this property to the exam id on the database and change the data access layer to access the database instead of a file.

Buy as far as using the sample as is that’s all you have to do: put the control on the page and specify where the exam is found. Nice!

The business logic tier defines a set of classes that encapsulate all the exams logic. It has objects that represent a question, an answer and has all the logic needed to advance to next question, score the exam, etc.

The code is pretty self-explanatory although there are some tricks I had to use mostly related to the interaction between the JavaScript timer and my server side code. However, of course you are free to ask me questions about this sample.

 

Hope this code might prove useful to you.

Posted by nunos | 4 Comments
Filed under:

Storing images in a database - MSDN session related

Well, after receiving lots of feedback about the code used in the MSDN sessions in November, I seem to have forgotten something. In the title generation sample in which we retrieve one of several images from the database (the one currently selected as the site title template) and use a handler to write the string with the desired title over it, most users seem to be faced with the following problem: how do we get images in a database in the first place.

Well, it's not really difficult: you can create a stream that points to the file, read the bytes and store them in an Image column in the db (assuming SQL Server or MSDE for this). Here is an example on how to do this in an ASP.NET application, more specifically, in a File Upload page. This makes sense because one of the other samples was about a digital photo sharing web application, so you might want to integrate both things.

The first thing you need to do is create a new webform in your asp.net application, and add the following piece of code to your HTML form declaration:


enctype="multipart/form-data"

 

The next thing you need to do is add an HtmlInputFile. To do this, open the toolbox, choose the Html Tag and add the File Field control. Then, right-click the control and check "Run as a server control" (this basically just adds the runat="server" in the HTML declaration and declares the control in the code-behind file).

You're almost there! What we just did was preparing the web form to receive uploaded files.

Now add a Button control (ASP.NET button control) and doble click it to write the event handler for the click event.

Add this code to your web form:


private void Button1_Click(object sender, System.EventArgs e)

{

SqlConnection cn = new SqlConnection("server=<server_name>;database=<database_name>;user ID=<user_id>;password=<password>");

SqlCommand cmd = new SqlCommand("INSERT INTO Pictures (name,type,picture_data) VALUES (@name,@type,@data)", cn);

cmd.Parameters.Add("@name", SqlDbType.VarChar,50);

cmd.Parameters.Add("@type", SqlDbType.VarChar,50);

cmd.Parameters.Add("@data", SqlDbType.Image);

byte[] data = new byte[filMyFile.PostedFile.InputStream.Length];

Request.Files[0].InputStream.Read(data, 0, (int) Request.Files[0].InputStream.Length);

cmd.Parameters["@data"].Value = data;

string aux = filMyFile.PostedFile.FileName;

string name = aux.Substring(aux.LastIndexOf("\\")+1);

cmd.Parameters["@name"].Value = name;

cmd.Parameters["@type"].Value = filMyFile.PostedFile.ContentType;

cn.Open();

cmd.ExecuteNonQuery();

cn.Close();

 

 

Ok, this code doesn't perform any error handling so I leave that your exercise. Be sure to replace the correct values in the connection string.

The InputStream property that we use here is in fact a System.IO.Stream. In this case the stream is created for us through the HtmlInputFile control. If you want to do this in a console or windows forms application, you can create the Stream yourself, point it to a file and use the rest of the code in a similar fashion.

So, in the database we will store the name of the file, the type (jpeg, gif, etc) and the data itself. This actually can be used to store any type of file in the database. We keep the content type stored with the file because when we use a page or handler to retrieve one of these files, we need to set the correct response content type before writing the data to the response stream, so that the browser can understand what is sent to him.

That is all. If you have any questions about the code feel free to comment the post or send me an email.

Cheers

Edit: Slight correction: if you intend to put other content besides image in the database, the column type used should not be "image" but "binary". Of course you would have to change the parameter in the code above.

 

Posted by nunos | 7 Comments
Filed under:

MSDN Session - Sample Code

Ok, as promised, here is the code that I used in the MSDN session: http://nunosilva.members.winisp.net/samples/CustomPipelineDemo.zip

Any questions you might have about it, either post a comment to this post, or send me an email.

Have fun!

Posted by nunos | 0 Comments
Filed under:

November MSDN event in Portugal

Well, it's been three great days acting as a speaker at the MSDN event in Portugal. My session was about extending ASP.NET with Http Handlers, Modules and SOAP Extensions and we held the event in three cities in Portugal: Aveiro, Porto and Lisboa. Besides my session, that was targeted to asp.net developers, we had sessions about WSE 2.0 (WS-Security), a very practical session about Debugging (all kinds of debugging: scripts, web services, post mortem debugging, etc) and we rapped-up the event with a session about deployment and maintenaince of .NET applications.

If you're following my posts you see that I recently started writing an article about the asp.net pipeline. That article will cover all the information that my session contained and hopefully I will be able to finish it next week. The samples that I used in my session have been highly requested and, because I don't work well without deadlines, I promise I will at least post the link to a zip file containing all the code and some documentation to make it work until December, 3rd.

I would like to take this opportunity to thank everyone involved in the event: the other speakers with whom I learned so much in the last few days, the support staff that made everything be ready when we needed to, and obviously the audience that gave us great feedback about the sessions and the event in general.

So, drop by at the end of next week to check out the code. You can get the slides now by visiting http://www.microsoft.com/portugal/msdn (portuguese only :)) 

Thanks for attending!

Posted by nunos | 1 Comments

Great article on Http Handlers and Modules

I'm still writing part 2 and 3 of the "Let's Extend ASP.NET" article. I'll really try to post at least part 2 until the end of the week but I can make no promises. In the meantime, if you want to look further, there's a MSDN article that shows a great implementation of Http Modules and Handlers to build an error logging mechanism. This is actually one of the common utilizations of Http Modules but they did a great job in this specific implementation allowing you to view the error log in a web interface or even as a rss feed. Cool!

http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnaspp/html/elmah.asp

Posted by nunos | 1 Comments
Filed under:

Let's Extend ASP.NET (part 1 of 3)

I’m currently preparing a session for a MSDN event in Portugal about Http Handlers, Http Modules and SOAP extensions. I actually never touched the subject until the request for the session came in, so I was really unaware of the possibilities this kind of components offers us. So, when I started to dig in the subject I can honestly say that I was amazed.

 

“Once upon a time” I had to develop an ISAPI extension to perform some URL redirection and I didn’t like the experience that much. Of course, you always end up being proud of the result if it actually works, but the development experience was far from enjoyable. The .NET components covered in this article allow you to perform most of the functions you would require in ISAPI extensions while giving you the flexibility and the great development experience you already expect when working with .NET.

 

I have to say that none of the information contained in this article is ground-breaking. I used a lot of resources available on the internet and compiled it into a single, comprehensive article that should shed some light over this all-too-often forgotten subject. Specifically most of my starting knowledge came from the Michelle Bustamante’s TechEd 2004 Session on Extending ASP.NET. Michelle has a very good technical web log where you can find a lot of good examples on using these components www.dasblonde.net.

 

I divided this article in three parts. In the first I shall cover most of the theory around these components and the ASP.NET pipeline. The second part focus on how you can develop and configure the components, what interfaces should be implemented, what methods you should use, etc.

Finally, on the third part of this article I will give practical examples that will show you how we can use this knowledge to build useful and reusable components that integrate with our web applications.

 

So, let’s start by understanding how a request gets handled by asp.net in the first place.

 

When IIS receives a request it will look in the configurations included in its metabase to find out if some sort of special processing should me made. These configurations are actually application mappings that associate resources to ISAPI extensions. All .NET resources (*.aspx, *.asmx, *.resx, etc.) are mapped to an unmanaged ISAPI extension called aspnet_isapi.dll. The function of this dll is to pass requests to asp.net runtime so that they can be handled in our .NET managed code. This is the default configuration but can be extended according to our needs.

 

This means that only the resources that are mapped to this specific ISAPI extension will be handled by ASP.NET. And this is important because you have to understand the scope of the rules you define in your application configuration files (machine.config and web.config). I’ll give an example on this subject: imagine you have an ASP.NET application in a virtual directory in IIS. That application consists of aspx pages, some images (gifs, jpegs) and a web.config file. All pretty standard. In your web.config file you define the following rule:

 

<authorization>

<deny users="?" />

<authorization>

 

What will happen if you open a browser and access an aspx page belonging to this application? As you might expect, unless you can provide some sort of credentials that identify you in the application, your request will not be authorized. But what if you change the URL to reference an image file in the same vdir? Your request will always be satisfied no matter if you provided credentials or not. Why? Because IIS is not configured to hand over the processing of these resources to ASP.NET by default, meaning that the configuration files will not affect this request. Actually, the ASP.NET runtime won’t even know that this request ever existed, because IIS will handle it directly.

 

Thankfully, we can configure IIS in order to change this behaviour. As you probably guessed, we have to map the required extensions to the aspnet_isapi.dll. That way, the requests will cross the boundary to ASP.NET for processing.

 

When that happens, ASP.NET will get an HttpApplication object that will be responsible for determining how this request will get processed. This decision will be based on the configuration that you define in machine.config or web.config. Actually what the HttpApplication object does is choosing an HttpHandler or an HttpHandlerFactory object that will in fact process the request and generate the corresponding response.

 

It may or may not come as a surprise to you, but actually all requests are eventually processed by an Http Handler. Confused? What about the pages that you developed? Well, these are handlers also. As you may know, every aspx page has an object that represents the functionality included in its code behind. This object will always inherit from the Page class that in turn implements an interface called IHttpHandler. So even you’re first Hello World page is actually an Http handler. So you see, this cannot be too complicated.

 

If you look at machine.config you’ll see the following section:

 

<httpHandlers>

<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory"/>

<add verb="*" path="trace.axd" type="System.Web.Handlers.TraceHandler"/>

<add verb="*" path="*.config" type="System.Web.HttpForbiddenHandler"/>

</httpHandlers>

 

 

There are a lot more handlers defined but these will be enough to explain things for now. What this means is that after the mapping at IIS level where it’s decided if a request should be handed over to ASP.NET, there is a second level of mapping, internal to ASP.NET where you assign resources to the components that process them.

 

In the first mapping you see that all aspx extensions are processed by the PageHandlerFactory. Why a factory? You use a factory when you have several HttpHandler objects available to process the same type of request and you have to make a decision on which one will be used. The page access example is probably the best one I can give you: so, every page has its own code behind object that we now know implements a handler. The job of the PageHandlerFactory is actually to create an instance of that object and pass it to the ASP.NET runtime so that the request can be processed.

 

In the second example you see that requests targeting trace.axd will be processed by TraceHandler. If you used tracing you know what these requests are. Trace.axd shows you the all the tracing information of your application and it’s used mostly on troubleshooting asp.net applications when in production. Instead of configuring the trace at page-level (which would show you the information on the bottom of the page), you can define it at the application level and view it in trace.axd. Have you ever wondered how this works since the trace.axd file is nowhere to be found on your application? The answer is above: all requests for a trace.axd file will be handled by a component called TraceHandler that dynamically gathers all the info and outputs it in the response stream. So, as you can see the resource doesn’t have to exist if the component that processes the requests that target it doesn’t actually need its contents.

 

In the third mapping that I presented, all config files are mapped to the HttpForbiddenHandler. The job of this handler is simply to throw an exception. That is the mechanism that prohibits your web.config file to be served by IIS. If this wasn’t configured then IIS would simply serve the file when requested. So remember, IIS is configured to pass requests for *.config resources to ASP.NET. And ASP.NET in turn is configured to use this handler that generates an exception when it receives this kind of requests.

 

So what does the extension of a resource mean? Actually nothing after the application gets built and deployed. It is just a routing mechanism. Let’s try a simple example. Create a new ASP.NET Web Application in Visual Studio and call it HandlerTest. Add a WebForm called TestExtension.aspx. Add the following code on the code-behind file:

 

private void Page_Load(object sender, System.EventArgs e)

{

            Response.Write(“My really stupid extension test”);

}

 

Build your application and then rename TestExtension.aspx to TestExtension.rse (where ‘rse’ means Really Stupid Extension J). Try to access TestExtension.rse in Internet Explorer. Nothing shows up right? IIS served the request by sending the contents of the file and the Page_Load method didn’t run. Now add a mapping in IIS for .rse extensions to the aspnet_isapi.dll. Finally add the following information to your web.config file:

 

<add verb="*" path="*.rse" type="System.Web.UI.PageHandlerFactory" />

 

Now refresh the page. It worked! Why? Because we mapped the rse extensions to the same handler factory used by aspx applications, so our code-behind object will be created and the method will be executed. This will work for any aspx page no matter how complicated it is.     

 

Now that we understand how the routing of a request is made until it reaches the component that processes it, let’s look at the components that we can use to extend this behaviour.

 

Http Modules: these are components that are able to interact with the HTTP request throughout the entire round-trip. Meaning, they are not suited to generate a response per-se but are actually there so that you can perform some additional processing over the request and usually build-up some information and include it in the HttpContext object so that it is available for your page or web service to access. Modules can be used for many things and we’ll see in part two that in fact there are already a bunch of modules configured by default that implement things like Session State Management, Windows Authentication, Output Cache management and so on.

 

Http Handlers: this is a special type of component that is responsible for actually processing a request and generating a response. We know that handlers are created when we develop a page or a web service. So, why would we want to create new custom handlers? To create custom endpoints in our application. In part three you’ll see how we can create a handler for jpeg files that generates thumbnails when we request the image with a specific parameter in the query string or simply sends the flat image if no parameter is specified. You can also create handlers for xml files so you can turn them into reports instead of just sending the xml contents as a response to the browser.

 

Http Handler Factories: a component that chooses one handler based on request specifics. Used when you have several handlers available to process the same type of request.

 

SOAP Extensions: a component that only applies to web services invocation and that allows you to interact with the request in the serialization/deserialization stages. Soap extensions are commonly used to encrypt/decrypt the request and the response to provide secure communication, to log invalid messages in their original format or even to enforce authentication by checking information that is sent out of band in a Soap Header (like user credentials).

 

The following image sums up what we've talked about so far and shows how these components relate in a round-trip. The image presents the pipeline used for processing aspx and asmx resources:



Image Hosted by ImageShack.us


This covers the subject that makes up part one of this article. I hope to be able to post the remaining parts in the next few days. Yes, I know it’s long but things will start to get more interesting once we get to the actual code.

Posted by nunos | 1 Comments
Filed under:

Redirect web services at run time

Well, this is not an advanced topic or anything like it. Actually it's a very simple thing to do. However, every so often I run into someone who is developing and consuming web services and don't know about this.

So here comes a typical scenario: you are developing a multi-tier application and some interactions between your tiers are done through web services. You develop the web service on your dev machine, you then consume it from an application also on your local machine. To do this you add a web reference to your local web service and everything just works. However, you are faced with the following problem (the common question that I'm getting a lot lately): when in production my tiers won't be in the same machine. I don't know the ip of the web services machine so, how can I prepare my application so it can work in that scenario? And, if the machine changes after some time, how can I update my application's web reference without recompiling?

Other typical scenario would be using the same web service but having to make a decision at runtime about the specific machine that will be used.

Ok....this is very simple and actually you should use this practice even in a situation that you perfectly control all your application deployment and maintenance. So… how to do it?

Let's get one thing straight right from the start: when you add a web reference you're not binding your client application to that specific URL. This operation is only intended to get the wsdl and creating the proxy class so you can get all the method and data type information you need to use the web service. After this, what you actually do is a soap request that can be directed anywhere.

Let's start by creating an entrance in web.config that configures your web service endpoint (meaning the URL). To do this, add the following section to your web.config file:

 

<configuration>

  <appSettings>

    <add key="WebServicesUrl" value="http://x.x.x.x/Services/books.asmx" />

  </appSettings>

</configuration>

 

You should use the appSettings section to set some values that are used within your application and subject to change overtime. This way, you can change them at runtime because they are read using the ConfigurationSettings.AppSettings property as we shall see.

So, if you look at the code of your proxy class, you see that there is a property called 'Url'. Yes, that's just it. To find this you have to set the option in Solution Explorer to 'Show All Files', expand your web reference, expand Reference.map, and inside Reference.cs you'll find something like this:

 

public Books() {

this.Url = "http://x.x.x.x/Services/books.asmx";

}

We see that in the constructor of the proxy class a reference is set to specify where the web service is located.

So, you see that an easy way to do this is just to replace this code with the following lines:

public Books() {

this.Url = ConfigurationSettings.AppSettings["WebServicesUrl"]

}

 

This way, if the web service changes location you can simply change the web.config file to update your application on-the-fly. Because this property is also publicly available, you can also change it before invoking the web service methods.

 

So, like I said...it's pretty simple...no rocket science...but hopefully it will help some of you.

 

Posted by nunos | 7 Comments
Filed under:

How to create a "Loading" page in ASP.NET

Many times we are faced with heavy or slow processing pages in our projects. If we cannot improve performance, how do we display some sort of information in the browser while the page is processing?

I used to have this problem when accessing slow databases or retrieving a large amount of information from it. Sometimes, the queries lasted for 30 seconds or even more and it's not very user-friendly to just sit there waiting. Many impatient users will often assume that the application has hanged and close the browser before the query results are shown.

Let's imagine the following scenario. We have a form where the user specifies some sort of search pattern. He then clicks a button and the results are shown in a datagrid in the same page. Ok, solving this is easy...you just add some client scripting to the button that triggers the round-trip to the database so that on the client side a message will be displayed (something like: please wait...loading the data).

But what if you want to show the results in another aspx? By this I mean you access a page and on the page_load you retrieve the data and populate the datagrid? What if you have a complex form with lots of drop down lists that must be populated and you want to show some sort of info to your users while they are waiting for the page to appear on the browser? And, what if you want to do something like a dynamic bar to show that something is actually happening?

Well, I recently discovered a very useful method of the Response object. Because it functions like a Stream, you are able to say Flush several times during a request. What this means is that you don't have to wait for the entire page to be rendered to send the response down to the client. So, basically this looks like a good way of solving this problem: we create a mixed blend of HTML and JavaScript in the beginning of the Page_Load event, we flush it to the client and we proceed with our server-side processing. When we get the data we don't have to do anything special. The Page_Load event will end and the HTML will be rendered by ASP.NET. All we have to do is possibly hide the information we previously sent in order to display the page correctly.

I encapsulated the entire logic into a single class (C#):

using System;

using System.Web;

namespace WaitPage

{

/// <summary>

/// To use this class, simply insert in the beggining of your page load the following line:

/// Wait.Send_Wait_Info(Response);

///

/// Also, in the HTML part of your web form add the following line at the end of the head section:

/// <script>Stop_Wait();</script>

/// </summary>

public class Wait

{

public Wait()

{

}

const string MAIN_IMAGE = "images/logo.bmp";

const int PROGRESS_BAR_SIZE = 10; //number of steps in your progress bar

const string PROGRESS_BAR_STEP = "images/pro.bmp"; //image for idle steps

const string PROGRESS_BAR_ACTIVE_STEP = "images/pro2.bmp"; //image for active step

 

public static void Send_Wait_Info(System.Web.HttpResponse Response)

{

Response.Write("<div id=\"mydiv\" align=\"center\">");

Response.Write("<img src=\"" + MAIN_IMAGE + "\">");

Response.Write("<div id=\"mydiv2\" align=\"center\">");

for(int i=1;i<=PROGRESS_BAR_SIZE;i++)

{

Response.Write("<img id='pro" + i.ToString() + "' src='" + PROGRESS_BAR_STEP + "'>&nbsp;");

}

Response.Write("</div>");

Response.Write("</div>");

Response.Write("<script language=javascript>");

Response.Write("var counter=1;var countermax = " + PROGRESS_BAR_SIZE + ";function ShowWait()");

Response.Write("{ document.getElementById('pro' + counter).setAttribute(\"src\",\"" + PROGRESS_BAR_ACTIVE_STEP + "\"); if (counter == 1) document.getElementById('pro' + countermax).setAttribute(\"src\",\"" + PROGRESS_BAR_STEP + "\");else {var x=counter - 1; document.getElementById('pro' + x).setAttribute(\"src\",\"" + PROGRESS_BAR_STEP + "\");} counter++;if (counter > countermax) counter=1;}");

Response.Write("function Start_Wait(){mydiv.style.visibility = \"visible\";window.setInterval(\"ShowWait()\",1000);}");

Response.Write("function Stop_Wait(){ mydiv.style.visibility = \"hidden\";window.clearInterval();}");

Response.Write("Start_Wait();</script>");

Response.Flush();

}

}

}

This code will simply send some HTML and Javascript to the client creating an animated progress-like bar. You can download the source code of a demo app showing it's usage here.

The Stop_Wait script block must be inserted in the end of the head section. When the final response is sent, the bar is cleared and the JavaScript cycle that animates the bar is stopped. Pretty simple .

Also, all the images presented can easily be changed. There are 4 constants defined in the class.

  • The main image
  • The size of the bar (how many steps)
  • The image representing a step
  • The image representing the active step

so you can customize this at will. Also, I believe the code will help build your own mechanism. I just did it for the exercise so it's not very pretty :P

Hope this proves of some use to you.

Posted by nunos | 29 Comments
Filed under:

Adding security patches to a new Windows XP installation

It's common knowledge that you can integrate a service pack with the installation bits of Windows (a technique called splistreaming). However, the security update that prevents the Blaster worm is post SP1. Recently I've been asked to figure out a way to prevent 10.000 new XP workstations of infection. We were installing Windows XP SP1 in a network where the Blaster worm was running loose. Because the installation was made through the network using unnatended setup, we wanted to avoid all these machines to get infected during the installation itself.

Well this didn't seem like an easy problem to solve. Tests were being made at the customer and the results were overwhelming. All workstations installed through this process were getting infected.

The first thing that we tried was enabling ICF during the unnatended install. You can accomplish this by specifying the following keys in the unnatended.txt file:

[Homenet]

InternetConnectionFirewall=Adapter1, [adapter2]

where Adapter1, adapter2 are known references inserted in the [NetAdapters] section of the same file. Please look at ref.chm in the deploy.cab package included in the Windows XP CD.

However, this approach did not work. ICF only gets enabled in the final boot so we would still get some infected machines. I assume they were getting infected soon after the network settings configuration.

So, I started to worry and began working on a script to run on the first logon that would clean the workstation from the Blaster worm. However this approach was not the best either.

Fortunately, I found out that in XP (and 2003) it is possible to integrate hotfixes during an unattended setup. This is documented in a KB article but I found out that it wasn't really common knowledge. Here you can find a link to the section of the article that covers this procedure:

http://www.microsoft.com/WindowsXP/pro/downloads/servicepacks/sp1/hfdeploy.asp#the_combination_installation_gxsi

Oh, and in case you're wondering...we tried it and it worked ;)

Posted by nunos | 4 Comments
Filed under:

Accessing an external CRL through a proxy

One of the good ways to safely authenticate users in a web application is using client certificates. When accessing the web application, IIS will ask the client for a certificate installed on the local machine, check if it's valid or not and then allows you to read the certificate and grant rights to the user.

When checking the certificate, one of the steps performed is accessing a CRL, or a Certificate Revocation List, that contains all certificates issued by a particular entity that have been revoked. One thing that everyone must understand is that if the CRL cannot be reached, than the certificate will be assumed revoked for security reasons. In that case, IIS will return an HTTP error 403.13 (see http://support.microsoft.com/?id=294305).

In the problem we were facing none of the proposed solutions worked. If we opened a browser on the web server and tried accessing the CRL with it's URL that would work. So, it had to do with proxy settings on the server. 

After some investigation I found the following KB articles:

819961 How to Configure Client Proxy Server Settings by Using a Registry File
http://support.microsoft.com/?id=819961

218970 Proxy Settings Can Be Set Only on a Per-User Basis
http://support.microsoft.com/?id=218970

The first article tells us how to force proxy settings for users. Because proxy settings are set in a per-user basis these values will not be read when accessing the CRL because the Local System account is used to run the IIS Admin and the W3SVC services. That's why opening a browser and accessing the CRL works. In this case we are running in the context of a real user and using the proxy settings defined through IE. You can actually try to change the account running IIS Admin and W3SVC to a user account. This will work but at the end of the day you'll create a lot more problems and it is not a supported configuration.

The second article tells us about a registry value called "ProxySettingsPerUser". If we force it to 0, we tell the machine to read proxy settings from HKLM instead of HKCU thus forcing a general proxy setting for all users (by the way, the article mentions an hotfix but in Windows 2000 it isn't needed).

So, I tried adding the following registry information:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings]
"AutoConfigProxy"="wininet.dll"
"ProxyEnable"=dword:00000001
"ProxyOverride"=""
"MigrateProxy"=dword:00000001
"ProxyServer"="x.x.x.x:8080"

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings]
"ProxySettingsPerUser"=dword:00000000

And it worked. I must point out again that we do not fully support this configuration. If a web server needs to contact a CRL, there shouldn't be any proxy or firewall restricting its access. However, this workaround does work rather nicely :D

Hope it helps

This posting is provided "AS IS" with no warranties, and confers no rights.

Posted by nunos | 2 Comments
Filed under: ,

Concerning the credentials double hop issue

Being an ASP.NET enthusiast, I've soon came across this issue and had to deal with it. This happened very shortly after the release of the .NET Framework and, at the time, seemed like a major headache for developers. Well, actually it still does seem like a major headache but I've came to accept it as a "normal" thing :P.

Because I regularly post in ASP.NET newsgroups, I realized that every so often someone sends in an email stating that they lose the user credentials connecting to a SQL Server or accessing a file in a network share from within their ASP.NET application. And this is called the "double hop" issue.

The typical scenario follows: you're building an intranet application and using Integrated Security. You're also setting "<identity impersonate="true" />" in your web.config file. During an ASP.NET request you can identify the current user but when accessing SQL Server in a trusted connection you get a logon failure stating that user Anonymous isn't allowed. So, basically, it seems that the credentials get lost somewhere in the middle.

Let's look at it step-by-step:

Integrated Security -  What this means is that IIS doesn't explicitly ask the users for credentials. Instead the credentials used to log on to their workstation are used to authenticate against IIS. And here is the first hop: the user's credentials are passed from the workstation to the web server in a secure way.

Impersonate - This is a very cool feature. You can access resources in the context of the user currently using your application. This simplifies resource access control but it's only suited for resources hosted on the web server itself.

Double hop - For security reasons, NTLM credentials cannot hop between servers at will. So, accessing a SQL Server instance running on another machine other than the web server will result in a logon failure error. It would be the second hop: the web server would have to pass the user's credentials to the SQL Server machine. For security reasons this is not allowed. Imagine that you access a site through your browser, the site collects your credentials without your knowledge (Integrated security) and then starts doing whatever the developer desires with your identification. Clearly, this is not a good scenario.

Ok, and now that we identified the problem, how do we workaround it?

There are a lot of possible ways to workaround this issue, but I actually couldn't find one that completely satisfies me. Oh well, security is a process and one that should be between our major concerns when writing an application. Here you'll find possible solutions to this problem. Note that you should carefully analyze each of these options and choose whichever fits your security and design requirements.

  1. Basic Authentication (consider HTTPS in this case)
  2. Kerberos and Trust computer for delegation privilege in AD
  3. Specify explicit credentials

1. When using basic authentication, users are asked to insert their credentials when accessing the site. In this case, they are authenticating against the web server and the machine can now use the credentials provided to access SQL Server. You can think of this as the user giving permission to the machine to use his/her identification. This doesn't change anything in your code, it's only an IIS setting. Careful though, because the credentials are sent in clear text between the client machine and the web browser, so you should think of getting a SSL certificate and using https to secure communications.

2. It's a lot more complex to handle authentication this way but Kerberos would allow you to hop the user's identification between servers. You'll also have to give the web server the "Trust machine for delegation" privilege in AD. You'll need to ask a domain admin to do this and normally they don't really like to accept this type of request. It's not a question of bad attitude but concerns for security. If your domain admin refuses your request feel happy that he knows what he's doing ;) Take a look here:

http://support.microsoft.com/default.aspx?scid=kb;en-us;810572

3. This is the solution more commonly used. Basically, you do not connect to SQL Server using a trusted connection, you specify a username and a password in the connection string or you specify this values in the impersonation settings and still use a trusted connection. The connection is still secure, and the only problem you have is where to store the these values so that it'll be safe. Of course, you could hard-code it, but that would leave you with no easy way to change it afterwards. One way is to store it in web.config and that would give you an easy way to change the parameters in runtime. Although the web.config file is not served by IIS (meaning that a client cannot view it in the browser) it's not the safest way to store this valuable piece of information. The recommendation is storing this values in the registry. This article although not specifically written for this issue, does show a way to accomplish this:

http://support.microsoft.com/default.aspx?scid=kb;en-us;329290

That's about it. This is not meant to be a complete article on ASP.NET security. It justs aims to give a few pointers on working around this common problem.

Hope it helps.

Posted by nunos | 13 Comments
Filed under:
 
Page view tracker