Sultan's Blogs

Fixing Problem with Session Handling and Caching for Frequently Using Transactional Pages

During last few months we had several problems with user session handling. For large financial transactional forms very often one user gets data that is requested by another user. At first shot it seems that one user session is overlapping with other. But very soon we figure out it is not like that. The problem lies inside the caching mechanism of ASP.Net. Therefore, we start to locate where the caching causes problem for us and start eliminating them.

 

Here I have summarized the different caching scenarios and the ways to disabling them (yes now I want to disable Cache!).

 

Well, in ASP.Net here are three type of caching:

1.  Page Caching

2.  Object Caching

3.  Kernel Caching

 

To handle the page caching to none (do either one of the following):

 

·      Change at the page directive

            <%@ OutputCache Duration="1" VaryByParam="None" %>

 

·     Set the value at web.config

<caching>

                                    <outputCacheSettings>

                <outputCacheProfiles>

                    <add name="MyPageCache" enabled="false" duration="1" varyByParam="None" />

                          </outputCacheProfiles>

            </outputCacheSettings>

</caching>

 

Finally change to page directive:

<%@ OutputCache CacheProfile="MyPageCache" %>

 

·     Change to the page code:

Response.Cache.SetExpires(DateTime.Now.AddSeconds(0));

Response.Cache.SetCacheability(HttpCacheability.NoCache);

Response.Cache.SetValidUntilExpires(false);

Response.Cache.SetAllowResponseInBrowserHistory(false);

 

To handle the object caching:

 

Object caching usually does not create such problem if your code is smart enough. You can do regular code review so there is not any chance of session problem due to object caching.

 

To handle the kernel caching:

 

Modify the web.config file

<httpRunTime executionTimeout="60" enableKernelOutputCache="false" />

 

Up to this point we have disabled all type of caching that can create the problem.

 

Still there exists another problem that causes the Application to restart. It is either for your virus guard that is continuously checking the wwwroot or for anything else causes your application root directory to modify and restart the application. This will kill all your live session and user will be logged out or see the yellow screen of death.

 

The solution is easier than the solution of caching problem. Do the following steps:

·         Configure your antivirus software so that it does not scan .asax and .config files.

·         Contact the antivirus software manufacturer for instructions.

·         Configure your Web application to store session data out-of-process.

 

To have an outproc session you do not need a physical server to do so. A little trick will help as follows:

 

<sessionState mode="StateServer" cookieless="false" timeout="30" stateConnectionString="tcpip=127.0.0.1:42424" />

 

The loopback of 127.0.0.1:42424 works perfectly J

Happy ProgrammingJ

Implementing Authentication & Authorization with Web Service

The ASP.Net 2.0 web service does not have any embedded mechanism to help its user do authentication and authorization. Considering this drawback, for the last few weeks, I was working with a design that helps both the web service providers and the consumers an easy way to write and consume services with less hassle for security.

The design considerations were:

1. The service hosting can be done at anywhere either in the provider location or in the client side.

2. Service provider will provide their consumer with username & password to connect to the service along with the necessary service list they are registered to consume.

3. There must be a hit count for the service so the provider can have a list about which user hit how many times for a service.

Though there are not any in-built mechanisms for authentication within ASP.Net 2.0, fortunately Microsoft has provided Microsoft Web Service Enhancement Tool (MSWSE) that can handle the authentication stuffs. However, I am not describing the detail usage of MSWSE. Instead, I try to depict a very simple usage of this tool.

For know detail about MSWSE please visit:

http://www.microsoft.com/downloads/details.aspx?familyid=3E02A6C8-128A-47C2-9F39-4082582F3FE1&displaylang=en

To download the tool please visit: (You have to install this before you use the sample provided here)

http://www.microsoft.com/downloads/details.aspx?familyid=018A09FD-3A74-43C5-8EC1-8D789091255D&displaylang=en

I have used the authentication techniques from the MSWSE and implement my own authorization system to work with. I tried to minimize the code from the part of the service consumer (of course if they use the .NET as consumer otherwise they have to consume as their own way).

The system has the following components (projects) :

1. SK.WebService.Core

2. SK.WebService.Test.Service

3. SK.WebService.Test.Web.

Let us dissect each of these step by step.

SK.WebService.Core

It contains classes related to the authentication, authorization and service methods usage logging. It consists of the following classes:

  • AuthenticationManager is used for check authentication for user who wants to access the web services. It inherits the UsernameTokenManager class from Microsoft.Web.Services3.It returns an authenticated token by checking the provided user id and password from the UserAuthentication.xml. However, the password is kept in hash format in the xml (using SHA1 algorithm), the Encode() method is do the job to convert the password to hash. Remember, as a service provider you need to give the password in plain text to your consumer but for keeping the password in the XML you need to convert it to hash string.
  • AuthorizationManager is used for check user service accessibility. It uses the user name (user id) from the Request SOAP Context and check from the UserAuthorization.xml for user accessibility in the desired service. However, it is the responsibility of the service provider to enforce this authorization. He must make a call of the following to enforce such:

ServiceFactoryCore.CheckUserServiceAccess("Welcome.HelloService");

  • ServiceFactoryCore is a static class that provides basic functionality for authentication and logging to its user. In addition it provides an authenticated service to consumer.

The GetToken() method read the user id and password from the configuration file and return the token if user is valid.

The CheckUserServiceAccess method call the AuthorizationManager.UserIsInService() to check the user accessibility for the service.

This includes another method named WriteLog() which writes to the Log.xml about a service method call.

The last method(s) returns an authenticated service to its consumer. Here we have only one service Welcome. So, the method GetAuthenticatedWelcomeService() return an authenticated Welcome service to its consumer. However, there can be any number of such methods depending on the number of services we have.

public static WelcomeWse GetAuthenticatedWelcomeService()

{

WelcomeWse objWelcome = new WelcomeWse();

objWelcome.SetClientCredential(GetToken());

objWelcome.SetPolicy("ClientPolicy");

return objWelcome;

}

The ClientPolicy will be described later part. But now focus on the WelcomeWse object. Why WelcomeWse and not Welcome? Before, explain the answer let us add a reference to the service proxy class to this project. Now, after configuring a service for using MSWSE it creates two proxies for each of the service.One with the typical proxy named Welcome and the other is a proxy along with the SOAP header named WelcomeWse.To consume the service with required SOAP header we must use the instance of WelcomeWse. To minimize the hassle for the consumer we, the provider, like to give this static methods that will return the consumer appropriate proxy.

The configuration files need to add few values for the location of the xml’s and related schema file:

<appSettings>

<add key="UserAuthentication" value="Data\UserAuthentication" />

<add key="UserAuthorization" value="Data\UserAuthorization" />

<add key="Services" value="Data\Services" />

<add key="Log" value="Data\Log" />

</appSettings>

SK.WebService.Test.Service

It contains all the services. Right now it has only one service Welcome. The Welcome service has two web methods: HelloService & HiService.

To make the methods compatible with the authorization we need to make a call of the following:

ServiceFactoryCore.CheckUserServiceAccess("Welcome.HelloService");

In addition we need to call the following to enable logging.

ServiceFactoryCore.WriteLog("Welcome.HelloService");

However, we can enable/disable logging by changing the setting of web configuration file.

<add key="IsLogRequired" value="false" />

Both the methods are now doing nothing except returning a message (string).

SK.WebService.Test.Web

It is the consumer of the service that we have developed in the earlier section.

The consumer (if a .Net consumer) has actually few things to do to consume the service with his identity.

Firstly, he needs to keep his identity in the configuration file:

<appSettings>

<add key="UserName" value="sultan"/>

<add key="Password" value="sultan!khan"/>

</appSettings>

Secondly, on the service call he needs to call the static method to return an authenticated service for his access:

WelcomeWse objWelcomeWse = ServiceFactoryCore.GetAuthenticatedWelcomeService();

Finally, he requires calling his necessary methods to get data. That’s it, a very simple way of consuming the service without being worried about the security token and al other authorization stuffs.

However, if the consumer is not a .Net consumer he might have to use is own mechanism to add the UserNameToken with the SOAP header for authentication.

Preparing the System for Authentication by using MSWSE

Now the complex (a bit) things to configure both the service provider and consumer for use the MSWSE.

Once again, the authenticated list of users must be described at the UserAuthentication.xml file. To enable WSE authentication follow the following steps:

· Select the SK.WebService.Test.Service and click right mouse. Select WSE Setting 3.0.

· Go to general tab and enable the check boxes.

clip_image001

· Select the security tab enter SK.WebService.Core.AuthenticationManager,SK.WebService.Core as type, http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd as namespace and UsernameToken as  local name.

clip_image002

clip_image003

· Select the policy tab and check enable policy and click the add button.

clip_image004

· Enter ServerPolicy as policy name and click ok.

clip_image005

· Click next at the new screen

clip_image006

· Select the following at the next few screens and click next until you are done.

clip_image007

clip_image008

clip_image009

· Now the similar type of setting requires at the consumer also. Select the SK.WebService.Test.Web and select the WSE Setting 3.0

· Enable the two check boxes as you did earlier.

· Select the policy tab and add a new policy named ClientPolicy.

clip_image010

clip_image011

· Now follow the steps described earlier during the service setup till the end.

These configurations will do the following at both Service & Consumer:

· Add a new section named microsoft.web.services3 at your configuration file with necessary implementation.

· Add a wse3policyCache.config file.

· Remember to add a reference to microsoft.web.services3.

Please refer to the sample project and have a look at configuration file changed settings.

Suggestion for future enhancement

1. Removing all the XML and put them into any preferred database.

2. Providing an administration tool (with GUI, like WSAT) to the service provider to add/ remove user and services from the XML.

3. And a lot of as you required :) .