Single sign-on with Forms Authentication

(Note: Updates after first post are in red - Dec 2004)

Every now and then I see people asking for some way to achieve single sign-on using Forms Authentication so you may reuse the Forms ticket with along several sites. It happens that you can have this functionality (not provided out of the box) with just a few tweaks.

 

Downloads

You can download the code sample for the SSO Forms Authentication from here.  The example code is provided as source code that you can use "as is" or customize it for your own applications.

 

SSO Sample

The sample that you can download form the above link, has two sites. The one named “FormsAuth2” is the entry point site that will call the login page located on the “FormsAuth” site. After the authentication process, the Forms ticket will be reused from the first site “FormsAuth2” with all the user name and roles info inside it. After diving into the details, let me say that these two sites are structured in two areas (public and private) in order to clearly differentiate between the publicly accessible areas and restricted areas that require authenticated access andSecure Sockets Layer (SSL). I use separate subfolders beneath the virtual root folder of both applications to hold restricted pages such as the login form and other sample form with checkout links and the like, that needs to be secured by using HTTPS. By doing so, I can use HTTPS for specific pages without incurring the SSL performance overhead across the entire site.

 

Configuration

The configuration showed on the following figure is a sample of how you can set the Forms Authentication attributes with security in mind. You should follow these hints for SSO Forms Auth. First of all, you should have the same settings (see forms element attributes) that are listed below on every site that you want to adhere to SSO.·         Name·         Protection·         PathThe machineKey element might be configured on the machine.config file or on every web.config application file. In the first scenario, you may have the encryption key set to something like this (this is the default setting, albeit useless for this scenario): 
<machineKey validationKey="AutoGenerate,IsolateApps" decryptionKey= "AutoGenerate,IsolateApps" validation="SHA1"/> 
 

 

The "IsolateApps" means that a different key will be AutoGenerated for *each* application. You can either remove the isolateApps option (for apps on the same machine) or insert a specific key value for it to use (for apps on different boxes). This last option is the one that is used on following the config sample.

 

<configuration>

<system.web>

   <authentication mode="Forms">

      <forms loginUrl="Secure\login.aspx" protection="All" requireSSL="true" timeout="10" name="FormsAuthCookie" path="/FormsAuth" slidingExpiration="true" />

      </authentication>     <!-- The virtual directory root folder contains general pages.          Unauthenticated users can view them and they do not need           to be secured with SSL. -->      <authorization>        <allow users="*" /> <!-- Allow all users -->   

      </authorization>

      <machineKey validationKey="C50B…CABE" decryptionKey= "8A9BE8FD67AF6979E7D20198CFEA50DD3D3799C77AF2B72F" validation="SHA1"/>   </system.web>   <!-- The restricted folder is for authenticated and SSL access only.        All pages on the Secure subfolder will be under SSL access. --> 

<location path="Secure" >

   <system.web>

      <authorization>

        <deny users="?" />

      </authorization>

   </system.web>

</location>

</configuration> 
 Note: Check ouy the path attribute. This should be aligned with the app name. If you want to have SSO on every app, just leave the default value "/".

 

Principal Creation

After gathering the user credentials you will perform the authentication process and after that you will retrieve the user roles if you want to use the .NET role authorization pattern. This implies the creation of an Identity and a Principal object that will contain this data. So on the login page server side and after the auth process you will get the Forms ticket and save there your roles info and may be any other user profile related data (beware of size constrains, less than 4KB). 

 

// Do auth with your preferred auth method  WindowsIdentity identity = WinAccessHelper.LogonUser( UserId, Password );   // Add roles  string[] roles = WinAccessHelper.Roles( new WindowsPrincipal( identity ) );                    HttpCookie cookie = FormsAuthentication.GetAuthCookie( UserId.Text, false );  FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);   // Store roles inside the Forms cookie.  FormsAuthenticationTicket newticket = new FormsAuthenticationTicket(                                                              ticket.Version,                                                               ticket.Name,                                                                  ticket.IssueDate,                                                             ticket.Expiration,                                                            ticket.IsPersistent,                                                          String.Join( "|", roles),                                                      ticket.CookiePath);                                                                                                    cookie.Value = FormsAuthentication.Encrypt(newticket);  Context.Response.Cookies.Set(cookie);  Response.Redirect( FormsAuthentication.GetRedirectUrl( newticket.Name, newticket.IsPersistent ) );                  // For different domains, should use the cookie domain//HttpCookie formsCookie = FormsAuthentication.GetAuthCookie( UserId.Text, false );//formsCookie.Domain = "localhost.com";//Response.AppendCookie( formsCookie );//Response.Redirect( FormsAuthentication.GetRedirectUrl( UserId.Text, false ) );//FormsAuthentication.RedirectFromLoginPage( UserId.Text, false ); 
 

 

Principal Retrieving

On each AuthenticateRequest event of every SSO “federated” site you may retrieve your saved user info and create your Principal object and load them onto the User object of the current HttpContext instance. This is accomplished on the following figure. 
 protected void Application_AuthenticateRequest(Object sender, EventArgs e){     

   if (Context.Request.IsAuthenticated)

   {            // retrieve user's identity from httpcontext user              

     FormsIdentity ident = (FormsIdentity)Context.User.Identity;

     // retrieve roles from the authentication ticket userdata field            

     string[] arrRoles = ident.Ticket.UserData.Split(new char[] {'|'});                 // create principal and attach to user                Context.User = new System.Security.Principal.GenericPrincipal(ident, arrRoles);      }} 
 

 

Multiple Domain Scenarios

For Domain wide authentication scenarios, you can set domain-wide cookie only for second level domain, or for third level domain if second level domain contains three or less characters. It means that you cannot set cookie for domain "com" or "co.uk", but can for "example.com" or "example.co.uk". You can find a good example of this here.Hopefully this sample will give you a good idea of how to implement a SSO scenario with Forms Authentication. Enjoy it! This posting is provided "AS IS" with no warranties, and confers no rights. 

67 Comments

  • What I'd really like to see is a sample of SSO between an ASP and an ASP.NET application. This would help with phased migration of legacy apps from ASP to ASP.NET.



    As far as I see it could be done if the ASP app had methods to encrypt and decrypt the authentication cookie - i.e. if there were a version of the FormsAuthentication.Decrypt / Encrypt methods callable from ASP (e.g. a COM object).

  • That’s an interesting mix. As far as I know, that approach should work fine. Just be sure that you have the same machineKey settings in machine.config file of your ASP server as the one you have on your ASP.NET server. Tell me if you ever try this and whether you where successful or not.



    Thanks,

    Hernan.

  • Thanks,wonderful post!

  • I'm thinking to incluide an example of this topic on my next security talk scheduled for mid august. When I finish these samples I will post them here.



    Regards,

    Hernan.



    PD: Unfortunately I'm not able to have a solution earlier than that because of my currently overloaded bandwidth. ;-)

  • A much awaited post from you buddy!

    You go a little fast for non-Einsteins, but it's OK ;)

  • Hi,

    I tried to download SSO_FormsAuth.zip but the link is not working any more could you please send me the file @ teddytgy@gmail.com or post other alternative where I can download the zip file. Thanks,
    Teddy

  • Hi,

    I am trying to create users in the active directory using my web application. I am using the following line of code

    string domain = "LDAP://" + DomainName;
    DirectoryEntry DEntry = new DirectoryEntry(domain);
    // wants to check if exists.
    /// 1. Create user account
    DirectoryEntries Users = DEntry.Children;
    DirectoryEntry NewUser = Users.Add("CN=" + UserName, "user");
    /// 2. Set properties
    SetProperty(NewUser, "givenname", UserName);
    SetProperty(NewUser, "SAMAccountName", UserName);
    SetProperty(NewUser, "userPrincipalName", UserName);
    //SetProperty(NewUser, "mail", email);
    NewUser.CommitChanges();

    The problem I am facing is , I am not able to create any particular user under the "User" folder under the active directory. It is getting created directly under the domain heirarchy. I want them to be under the user folder.
    Could you please tell me what's wrong with my code and how to rectify it?

    Thanks

  • I see your posted is good. But your link is not working. Please help me about Signle Sign On with Multi Virtual Directory.

    Thank you,

  • Great post. Now, I have a question and maybe you can help me.... I have a set of asp.net websites running under the same domain that I already made the SSO work between them. The problem is that I need to add our exchance server webmail and our share point portal. At this point I have no clue on how to do that. We are using Active directory and people from outside the network need to have access. Any help will be appretiated.

  • SamitSamit,Samit,Samit,SamitSamitSamit,Samit,Samit,Samit,v,v,Samit,Samit,Samit

  • business references found north result

  • Thanks for sharing.

  • Will this SSO implementation work in a web farm enviorment?

  • Such a solution is disturbing, as it implies that simply having a correct cookie is sufficient to protect a user. While a centralized authorizing machine could (of course) be called to establish a pseudo-session among different machines, I've seen organizations not do this - which means that important security concerns, such as allowing a user to actually log off when done accessing resources, are not implemented correctly across all servers. I suppose this is all fine and dandy, if the application is simply some hobby site, but if there's an actual business reason for implementing security, this is NOT the model to follow.

  • Very informative post. Will share this with other techie friends. Thanks!

    Thanks,
    James A.

  • Whoa! That's a really cool design! Wonder if I can do that with Photoshop too?

    James A.

  • Thanks, it's a great article

  • Nice article. But I've a question. Will the authentication tickets work on two different domains? For example, www.domain1.com and www.domain2.com, provided both are ASP.NET 2.0 applications with same web.config settings (including the forms authentication cookie name)?

  • Hello All,

    I have 2 Web applications in the same IIS with the virtual directory structure below:

    mydomain.com/site1
    mydomain.com/site2

    both site1 an site2 are using form authentication and creating the token further adding in cookie as below,

    FormsAuthentication.Initialize();
    FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,username,DateTime.Now, DateTime.Now.AddMinutes(20),rememberMeSet,globalID ,FormsAuthentication.FormsCookiePath);

    // Encrypt the ticket.
    String hash = FormsAuthentication.Encrypt(ticket);
    //Create the authentication cookie
    HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hash);

    My problem is when I'm logging in to Both site1 and site2 then these two are not running simultaneously on single browser using different tab for same user name.

    one is being logged out when logging to the other application and vice verse.

    Has anyone run in to such problem..
    What wrong thing I'm doing here..Pls help.

    Thanks in advance!!!

  • i m using this code encryption string hashedPwd = FormsAuthentication.HashPasswordForStoringInConfigFile(pwd, "md5");
    now how i can decypt data

  • This example helped me a lot. Thanks!

  • @Satish:

    I had same problem. Was able to use the code below to resolve it.

    1. Add following code to _LoggedIn event in code behind your login control on both websites:
    string userName = Login1.UserName;
    // Add roles
    string[] roles = Roles.GetRolesForUser(userName);

    HttpCookie cookie = FormsAuthentication.GetAuthCookie(userName, false);
    FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
    // Store roles inside the Forms cookie.
    FormsAuthenticationTicket newticket = new FormsAuthenticationTicket(
    ticket.Version,
    ticket.Name,
    ticket.IssueDate,
    ticket.Expiration,
    ticket.IsPersistent,
    String.Join("|", roles),
    ticket.CookiePath);

    cookie.Value = FormsAuthentication.Encrypt(newticket);
    Context.Response.Cookies.Set(cookie);
    Response.Redirect(FormsAuthentication.GetRedirectUrl(newticket.Name, newticket.IsPersistent));

    2. Add following method into Global.asax file in both websites:

    protected void Application_AuthenticateRequest(Object sender, EventArgs e)
    {
    if (Context.Request.IsAuthenticated)
    {
    // retrieve user's identity from httpcontext user
    FormsIdentity ident = (FormsIdentity)Context.User.Identity;

    // retrieve roles from the authentication ticket userdata field
    string[] arrRoles = ident.Ticket.UserData.Split(new char[] { '|' });
    // create principal and attach to user
    Context.User = new System.Security.Principal.GenericPrincipal(ident, arrRoles);
    }
    }

    3. Add following code into web.config for both websites inside system.web tags:




    ... and that's it! When I use Chrome I still have to login to the 2nd website but at least it doesn't log me out of website 1. When I use IE it works seamlessly.

    Hope that helps.

  • Is there any dll files require?

  • what if applications are deployed in different domains? Is that supported given your approach?

  • Hi, i feel that i saw you visited my weblog thus i came to return the desire?
    .I'm trying to to find things to enhance my site!I suppose its ok to make use of some of your concepts!!

  • Hello there! Would you mind if I share your blog with my myspace group?
    There's a lot of people that I think would really appreciate your content. Please let me know. Cheers

  • Today, I went to the beach with my children.
    I found a sea shell and gave it to my 4 year old daughter and said "You can hear the ocean if you put this to your ear." She placed the shell to her ear and screamed.
    There was a hermit crab inside and it pinched her ear.
    She never wants to go back! LoL I know this is completely off topic
    but I had to tell someone!

  • I am really loving the theme/design of your website.
    Do you ever run into any web browser compatibility issues?
    A couple of my blog readers have complained about my blog not
    operating correctly in Explorer but looks great in Opera.
    Do you have any tips to help fix this issue?

  • I'm truly enjoying the design and layout of your site. It's a very
    easy on the eyes which makes it much more enjoyable for me to come here and visit more often.
    Did you hire out a designer to create your theme? Superb work!

  • Your weblog appears to be having some compatibilty
    issues in my safari browser. The wording appears to be running off the page pretty bad.
    If you would like you can e-mail me at: christina.maier@cluemail.
    com and I'll shoot you over a screen grab of the problem.

  • May I just say what a relief to discover somebody who truly understands what
    they're discussing on the web. You actually realize how to bring a problem to light and make it important. A lot more people need to check this out and understand this side of your story. I was surprised you are not more popular because you most certainly possess the gift.

  • I hardly leave a response, but i did some searching and wound up here Single
    sign-on with Forms Authentication - Hernan de Lahitte's blog. And I actually do have some questions for you if it's allright.

    Is it simply me or does it look like a few of these responses look like
    coming from brain dead individuals? :-P And, if you are writing at additional social
    sites, I would like to keep up with anything fresh you have to post.
    Could you list of all of your shared sites like your linkedin profile, Facebook page or twitter feed?

  • I totally learned something new about Korean music today.
    It’s pretty amazing to see how the Korean music
    industry can be so widespread and venturing off to other sections other than music.
    It’s so weird to see these people start off as just Korean pop rookies and seeing
    them reach this point. Totally amazed.

  • I would want to obtain a job in this particular field and after
    some latest employment interviews, the responses I've received
    is that I truly require some proper qualifications. I will get started with some sort of quick training and develop from there.
    Wish me success!

  • I always emailed this weblog post page to all
    my contacts, as if like to read it after that my contacts will too.

  • A person essentially assist to make severely posts I'd state.
    This is the first time I frequented your website page and to this
    point? I surprised with the analysis you made to create this particular put up amazing.

    Fantastic process!

  • of course like your website however you have to take a look at the spelling on several of your posts.
    Several of them are rife with spelling issues and I in finding it
    very bothersome to tell the truth on the other hand I'll surely come again again.

  • Remarkable! Its really amazing post, I have got much clear idea on the topic of from this
    post.

  • There's definately a lot to find out about this
    topic. I love all the points you made.

  • Overall CommitmentRemember dental health care, then you might be interested heating repair in checking out the AssistMedic virtual medical receptionist which supports appointment reminders.
    However, they are whiter and brighter, and we are awaiting the results heating repair of Dental Implants
    PriceThe price of dental implants.

  • Hi there! I simply would like to give a huge thumbs up for
    the good data you��ve got right here on this post.
    I will probably be coming back to your blog for more soon.

  • I like to share understanding that will I have built up with the yr to help improve team
    overall performance.

  • Good day! I simply wish to give an enormous thumbs up for the great info you have got right here on this post.
    I will likely be coming again to your blog for extra soon.

  • Howdy! I simply want to give an enormous thumbs up for the nice information you have right here
    on this post. I will probably be coming back to your weblog for
    extra soon.

  • Excellent keen analytical attention with regard to details and
    may anticipate issues before these people take place.

  • I love to disseminate understanding that will I've accumulated with the calendar
    year to assist improve team efficiency.

  • Pretty nice post. I just stumbled upon your blog and wished to say that I have truly enjoyed surfing around your blog posts.
    In any case I will be subscribing to your feed and I hope you write again soon!

  • I like to share knowledge that will I have accrued with the calendar year to help improve group overall performance.

  • Por parte argentina, recupera a su capitán,
    Fernández Lobbe, pero cuenta con algunas bajas como Patricio Albacete Felipe Contepomi, que empezará en el banquillo.

  • Hi there, You have done a great job. I'll certainly digg it and
    personally suggest to my friends. I am sure they will be benefited
    from this site.

  • This is the perfect site for anybody who really wants to find out about this topic.
    You realize so much its almost hard to argue with you (not that I actually will
    need to…HaHa). You certainly put a brand new spin on a topic that's been discussed for decades.
    Wonderful stuff, just great!

  • You ought to be a part of a contest for one of the most useful websites online.
    I will recommend this web site!

  • These are really fantastic ideas in about blogging. You have touched some fastidious things
    here. Any way keep up wrinting.

  • Hey exceptional website! Does running a blog such as this
    take a great deal of work? I've virtually no knowledge of computer programming however I was hoping to start my own blog in the
    near future. Anyhow, should you have any recommendations or techniques for
    new blog owners please share. I understand this is off
    subject but I just needed to ask. Many thanks!

  • Thank you for any other fantastic post. Where else could anybody
    get that kind of info in such an ideal way of writing?
    I have a presentation next week, and I'm on the search
    for such information.

  • Just want to say your article is as amazing. The clearness in your post is simply cool
    and i can assume you're an expert on this subject. Well with your permission allow me to grab your
    feed to keep up to date with forthcoming post. Thanks a million and please keep up the rewarding
    work.

  • Hi there to all, the contents existing at this site are genuinely remarkable for people knowledge,
    well, keep up the good work fellows.

  • Programa del Ciclo Medio Tecnico Aux de Enfermeria:. n que los beneficios tienen que usarse para pagar otros gastos, como el alojamiento y la comida.
    Este dictamen puede ser  vinculante o  meramente  referencial.

  • Everyone loves it whenever people come together and share ideas.
    Great site, continue the good work!

  • Thanks , I have recently been searching for information approximately this topic
    for ages and yours is the greatest I've came upon sso
    far. But, what in regards too the conclusion?
    Are you positive in regads to tthe supply?

  • Hi, always i used to check weblog posts here early in the morning, as i love to learn more and more.

  • I pay a visit each day som sites aand sites to read articles, bbut this webpage provides
    quality based posts.

  • First off I would like to say superb blog! I had a quick question inn which I'd
    like to ask iif you do not mind. I was curious to know how you cenfer yourself and clear your thoughts prior to writing.
    I've had difficulty clearing my mind in getting my ideas out there.
    I truly do take pleasure in writing but it just
    seems like the first 10 tto 15 minutes tend to be wasted simply
    just trying too figure out how to begin. Any ideas orr hints?
    Thank you!

  • What's up, after reading this amazing paragraph i am as well cheerful to share my knowledge here with friends.

  • You ought to be a part of a contest for one of
    the besdt blogs on the web. I'm going to highly recommend this webb
    site!

  • I can't download the code, it seems its expired.

  • It's going to be finish of mine day, however before ending I am
    reading this great piee of writing to increase my knowledge.

Comments have been disabled for this content.