Sunday, December 20, 2009

Single Sign-On with Forms Authentication across web applications

In this post, we will be discussing about Forms authentication cookies/ticket and sharing this Auth ticket across ASP. Net web applications v1.1/v2.0.

First of all, we know that Forms Authentication is basically configured in the web.config file using following <authentication> element.

<authentication mode="Forms">
<forms name="cookieName" loginurl="Logon.aspx" protection="All" timeout="30"></forms>
</authentication>

Here, 'name' in the <forms> element specifies the name of the cookie that will be created to store logged in user identity. 'loginUrl' specifies the page where anonymous user will be redirected for logon. All value in protection attribute makes sure that forms authentication ticket is encrypted and protected against tampering.

Encryption and validation of authentication tickets are done using the combination of specified algorithms and decryption/validation keys in <machinekey> element in web.config file. Basic outline for <machinekey> element with possible attribute values is shown below:

<machinekey validationkey="AutoGenerate|IsolateApps|value"
decryptionKey="AutoGenerate|IsolateApps|value"
validation="AES|MD5|SHA1|3DES"
decryption="Auto|AES|3DES|DES" />

AutoGenerate indicates random keys to be generated for each web application and IsolateApps specifies that unique keys for each web applications. validation and decryption attributes sets the algorithm to be used for authentication cookies. 'decryption' attribute is introduced in ASP. Net 2.0 and in ASP. Net 1.0/1.1 default decryption used is 3DES.

If you need a single logon to work across multiple applications located in separate virtual directories, you need to share a common authentication ticket. To configure a common authentication ticket, you must manually generate validationKey and decryptionKey values and ensure that each application shares these values.

If you want to share tickets across all applications on your server you can set these manual values on the <machinekey> element in the machine level Web.config file.
To share tickets across specific applications, you can use a <machinekey> element with common validationKey and decryptionKey values in the relevant application's Web.config files.

You should also make sure that cookie name and protection attributes set in <forms> element are same across all other web.config files.

Example machineKey element is shown below:

<machinekey validationkey="5994662690E9A40938F7C0A35A2B46AE0E1B315006864C9D5B6B5D44F405901EB49A1793DC93B1994EE4CD4BCD2B4C88A5078327B56683FF4F719568F9043922" decryptionkey="128034A8B2BF22E1BF846B5BF88FEB93C1C62077E0B08886" validation="SHA1" decryption="3DES"/>

Important point to note is that here decryption attribute is set to 3DES and this is needed when sharing authentication tickets between ASP. Net 1.1 and 2.0 applications,

you have to set this decryption="3DES" in web.config of v2.0 applications.



More information on configuring <machinekey> element is here

Also make sure that when user is authenticated in logon page, a call to method FormsAuthenication.SetAuthCookie() is there. This method sets authentication cookie for the specified user for the current browsing session. SignOut() method of this class clears forms authentication cookies and logs off the current user from all other web applications also in a web farm environment with single sign-on.


Listed below are resources available to generate values for validationKey and decryptionKey for <machinekey> element:

http://aspnetresources.com/tools/keycreator.aspx
http://www.developmentnow.com/articles/machinekey_generator.aspx

Cheers,

Friday, August 7, 2009

Converting C# code to VB.Net

A very useful web page if you are working on either c# or vb.net and you are not familiar with any one of them.
You can use below page to convert your code from c# to vb.net and vb.net to c#.

http://www.developerfusion.com/tools/convert/csharp-to-vb/


Cheers,

Wednesday, July 1, 2009

Key cannot be null. Parameter name 'Key' error

You may face this error while setting up Custom Security extension or Forms Authentication with Sql Reproting Services. This is because two new enums added in FolderOperations and CatalogOperation.

You can add this permission for those enums this way:
m_FldOperNames.Add(FolderOperation.CreateModel, OperationNames.OperCreateModel)
m_CatOperNames.Add(CatalogOperation.ExecuteReportDefinition, OperationNames.ExecuteReportDefinition)

Adding this also means that you have to increase those hashtable counters like:
Private Const NrFldOperations As Integer = 10
Private Const NrCatOperations As Integer = 16

With this setting that error should disappear.

Cheers,

Tuesday, June 30, 2009

Error in Custom security extension for SQL Reporting services

If Custom security extension developed with vs.net 2003 is deployed to a report server having sql 2005 reporting services installed will throw an exception:
System.TypeLoadException: Method 'CheckAccess' in type '' from assembly '' does not have an implementation.

Obvious reason is :
IAuthorizaitonExtension has one overridable method CheckAccess with following signature
bool CheckAccess(string userName, IntPtr userToken,
byte[] secDesc, ModelItemOperation requiredOperation);

ModelItemOperation enum is new in sql 2005 reporting services which was not in earlier sql 2000.


Cheers,

Tuesday, June 23, 2009

Custom Functions/Code in SQL Reporting Service

There can be certain instances where we want to call our custom functions on certain Database fields or any other value.

We can write code in .Net class library and Integrate that assembly with our Reports to gain the functionality.

Here I am listing steps to do so:

1. Create a class library project in Visual Studio.
Add the function implementation (for example given below)


Public Class ResourceHelper

Public Function GetString(ByVal Key As String) As String

Return "Formatted Value is " & Key

End Function

End Class


2. Strong name the Assembly.

3. Build the Solution and Deploy this dll to following two locations:

  • Program Files\Microsoft Visual Studio 8\Common7\IDE\PrivateAssemblies
  • Program Files\Microsoft SQL Server\MSSQL.3\Reporting Services\ReportServer\bin
4. Click on Report in Designer area and navigate to "Report/Report Properties..." menu.

5. Go to References tab and add a reference to our .dll

6. Under Classes panel, Give Class name as . (here, ResourceTestClassLibrary.ResourceHelper) and Instance name as say objResource and Click OK. (This step is not required when we have function declaration 'static')

7. Add a TextBox to the report and Right Click and go to "Expression..."
Enter following text

=Code.myObj.GetString("Yahoo!!!")

and click OK.
Here we can pass any Database field value or other argument we wish.

8. Build Report Project and see if it succeeds.

On successful Run, you can see this text box containing the result output of that Custom function with that argument.

This is it.

Likewise, we can use Resource files to localize our labels and headers on report. Though deployment of .resx file will slightly wary in that case.


Cheers,


Wednesday, February 18, 2009

Exporting SSRS Report to Image file

Hi All,

Here I am putting a piece of code which exports SQL Server Reporting Service Report an Image file of type GIF. You can also export to other image file types as well.
Basically, we need to set DeviceInfo according to our requirement and pass that device info to Report's rendering extension mechanism.

string reportType = "Image";
string mimeType;
string encoding;
string fileNameExtension;

string deviceInfo = String.Format(@"
<DeviceInfo>
<OutputFormat>GIF</OutputFormat>
<PageWidth>{0}</PageWidth>
<PageHeight>{1}</PageHeight>
<MarginTop>{2}</MarginTop>
<MarginLeft>{3}</MarginLeft>
<MarginRight>{4}</MarginRight>
<MarginBottom>{5}</MarginBottom>
</DeviceInfo>",
"11in",
"8in",
"0in",
"0in",
"0in",
"0in"
);
Warning[] warnings;
string[] streams;
byte[] renderedBytes;

//Render the report
renderedBytes = reportViewer1.LocalReport.Render(
reportType,
deviceInfo,
out mimeType,
out encoding,
out fileNameExtension,
out streams,
out warnings);

string file = "C:\\MyImage" + "." + fileNameExtension;
Stream streamReportImage = new FileStream(file, FileMode.Create);
streamReportImage.Write(renderedBytes, 0, renderedBytes.Length);
streamReportImage.Position = 0;


Here you can see that, when we set OutPutFormat to GIF then, Render method returns us file extension accordingly which we can use the rendered bytes to output to a stream.

You can find more infromation about DeviceInfo for different output format on below link
Ref: http://msdn.microsoft.com/en-us/library/ms155397.aspx

Cheers,