Quaiso
  • 首页
  • 世界
  • 美国
  • 中国
  • 加拿大
  • 财经
  • 科技

Single Sign On (SSO) for cross-domain Asp.net applications, Part-I - The design blue print

8/25/2013 2:24:45 AM

By Al-Farooque Shubho | 5 Sep 2010 | Unedited contribution Part of The SQL Zone.
Architectural approach of a domain independent Single Sign On implementation for Asp.net applications

Introduction  

"Yet another Monday morning at your office. Just started to wonder how fast the weekend just passed away, and how hard are the days going to be in this week. You got a mail! Oh no, not a lucrative job offer. Its just another requirement from your new client. Your client has a number of Asp.net of sites, and all he wants is to enable his users to log onto all sites just by logging into a single site. And, obviously, log out of all sites by logging out from a single site.

OK, so your client wants a
"Single Sign On" implementation. You thought, oh, it’s not that hard. The Asp.net forms authentication is the solution. It allows to share the same cookie across the sites under a same domain using the same configuration key using the <machineKey> element. A quick Google search gives you some pretty fine examples of Single Sign on implementation using <machineKey> in Asp.net applications. OK, so life is not that hard as a programmer after all.

Hold on. Something just caught your eyes. The requirement says, "your client has a number of sites, but they are not necessarily under the same domain". You just missed this important point to notice, and, the very first day at your office just started to appear harder to you. It’s not easy to implement a Single Sign On for sites under different domain, for the very fundamental reason that, cookie of a particular domain cannot be shared with another domain. Who doesn’t know that, it’s the cookie that is used to maintain authentication information across different page requests?"


I just depicted a scenario that is pretty common these days. This is an era of web 2.0 and social networking, as they say. Standalone and “iland” like systems are very rare these days. You do a tweet from the Twitter and update your status at LinkedIn and Facebook at the same time without doing anything else. You write an article on CodeProject and share it on hundreds of sites within a seconds. So, it’s pretty natural that you would expect to log onto a site and jump to another related one without having to re-login again, doesn’t matter to you what domain these sites are deployed under.

So I thought, how about developing something that allows to implement a Single Sign On (Of course, for Asp.net sites) for cross-domain sites easily? People may have tried to implement this in many different ways, and, commercial solutions are also available upon purchase. But, what if I try to develop something which is simple, free and most importantly, which works.

How Authentication works in Asp.net?

Well, this may not be something new to you. But while we try to solve the hardest problems on earth, we often need to go back to the basics, to try to understand how things really work. So, it wouldn’t be bad to revisit the ABS’s of Asp.net Forms authentication mechanism.

Here is how Asp.net forms authentication works:

Forms_Authentication.png

Figure : Forms authentication in Asp.net

Sequence of operations:

  • You hit a page in an Asp.net application, which is accessible only to the authenticated users (Logged in users) of the application.
  • The Asp.net runtime looks for a cookie (Forms authentication cookie) in the request, and, if the cookie is not found, it redirects the current request to the Login page (The login page location is configured in the web.config).
  • You provide the login credentials and hit “Login” button. Assuming that the credentials are correct, your system validates the credentials successfully against the data storage, sets the user name to the Thread.CurrentPrincipal.Identity.Name property, writes a cookie in the Response (Along with setting cookie value with the user information and setting some properties like cookie name, expiration datetime etc) and redirects to the originally requested page.
  • You hit another page in the application (Or, click a link that navigates you to another page) and your browser sends the authentication cookie (With any any other cookie that were written by the same site earlier) this time because the browser has already got the authentication cookie in last response.
  • As usual, the Asp.net runtime looks for the authentication cookie in the request and this time it finds the cookie. It checks the cookie properties (Like expiration date/time, path etc) and if not expired already, reads the cookie value, retrieves the user information from the cookie, sets the user name into the Thread.CurrentPrincipal.Identity.Name property, checks if the user has permission to access the requested page and if he/she the permission, executes and serves the page to the browser.

Pretty simple, no?

How Authentication works in multiple Asp.net sites under same domain?

As depicted already, the Asp.net forms authentication is fully dependent on Cookie. So, if two different sites can share the same Authentication cookie, it is possible to make the same user to log onto both sites just by logging onto a single site.

Now, the HTTP protocol says, two different sites can share a cookie if and only if both sites are deployed under the same domain (Or, sub-domain). Internally, your browser stores the cookies locally (Either in disk or in memory) against the web site’s URL. When you hit subsequent requests to any site, browser read those cookie which have the matching domain or sub domain names comparing to the currently requested URL and sends those cookies with the request.

So, let’s assume you have two sites as follows:

www.mydomain.com/site1

www.mydomain.com/site2

These two sites share the same host address (Same domain mydomain.dom and sub-domain www) and both sites have been configured to use forms authentication for user authentication and authorization. Suppose, you just logged onto the www.mydomain.com/site1 site and as described above, your browser now has a forms authentication cookie originated from www.mydomain.com/site1.

Now, if you click/hit any subsequent URL of www.mydomain.com/site1 , the forms authentication cookie will be sent with the request, Why? because, the cookie originally belongs to this site? Yes, but not 100% correct. To be exact, the cookie will be sent because the request URL www.mydomain.com/site1 has the same matching sub domain and domain name (Host address) www.mydomain.com.

So, after you logged onto www.mydomain.com/site1 if you hit a URL of www.mydomain.com/site2, the forms authentication cookie (Or, any other matching cookie) will be sent with the request for the very same reason that, the www.mydomain.com/site2 has the same matching host address (www.mydomain.com) even if this is a different application (site2). So, it’s obvious that, as the same forms authentication cookie can be shared across two different web application under the same host address, its possible to log onto both web application at a time just by logging onto a single web application (Hence, Single Sign On).

However, Asp.net does not allow you to automatically implement the single sign on just by implementing forms authentication for multiple web application under same host address. Why? because, each different Asp.net web application uses it’s own encryption keys to encrypt and decrypt cookie data (And other data such as ViewState) for ensuring security. So, unless you specify a single encryption key for each Asp.net application, cookies will be sent from the browser, but, one application won’t be able to read the value of authentication cookie that is originated from the other application.

Specifying a single authentication key is the solution. For each Asp.net application, you have to use the same<machinekey> element in the web.config as follows:

Collapse | Copy Code
<machineKey validationKey="21F090935F6E49C2C797F69BBAAD8402ABD2EE0B667A8B44EA7DD4374267A75D" decryptionKey="ABAA84D7EC4BB56D75D217CECFFB9628809BDB8BF91CFCD64568A145BE59719F" validation="SHA1" decryption="AES"/> 
If the same machinekey (With validationKey and decryptionKey) is used across all applications under the same domain, each will be able to read cookie value that is originated from other application.

What if two sites have same domain and different sub domains?

Suppose yous sites are not deployed under the following host addresses:

site1.mydomain.com
site2.mydomain.com

These two sites share the same domain (Same 2nd level domain mydomain.com) but has difference in their 3rd level domain (Different sub domain site1 and site2).

By default browser sends cookies for matching host address only (Matching domain and sub domain). So, site site1.mydomain.com won’t get any cookie that is originated form site2.mydomain.com (Because, they don’t have the same host address, their sub domain is different) and hence even if you configure the same machinekey for these two sites, one site won’t be able to get cookie originated from another.

So, in addition to implement the same machineKey across all sites, you also need to instruct Asp.net runtime to define the domain of the authentication cookie so that, the cookie is sent from the browser with any request that have matching domain name. You need to configure the forms authentication cookie as follows:

Collapse | Copy Code
<forms name="name" loginUrl="URL" defaultUrl="URL" domain=”mydomain.com”/>

So, how to share the authentication cookie across multiple domains?

Well, there is absolutely no way to do that. The fundamental barrier of Http protocol prevents you to share a cookie across different domain, primarily for security reasons.

Say, you have following two sites under two different domains :

www.domain1.com
www.domain2.com

Now, if you log onto the www.domain1.com site using forms authentication, and hit a URL of www.domain2.com, browser wouldn’t simply send the authentication cookie of domain1.com to domain2.com . So, there is no built in mechanism in Asp.net to implement a Single Sign On across these two different sites.

In order to implement a Single Sign On across these two sites under different domain, there has to be some “workaround” or some implementation model that lets these two sites to access a single cookie via some “indirect” mechanism.

A very basic Cross Domain SSO implementation model

Suppose we have to implement SSO in these following two sites:

www.domain1.com

www.domain2.com

www.domain3.com

In order to implement SSO across these sites, we need to set an authentication cookie to the client’s browser for all three sites when the user is authenticated in any one of the two sites.

If user1 is authenticated into www.domain1.com , browser will add an authentication cookie in the response before returning a response to www.domain1.com . But as we need to be able to log onto the www.domain2.com and www.domain3.com, we need to set the authentication cookie in the same client’s browser for www.domain2.com and www.domain3.com at the same time. So, before returning response to browser, www.domain1.com will have to redirect to the browser to www.domain2.com and www.domain3.com for setting authentication cookie.

Following diagram depicts the basic idea (Arrows denote the Redirections):

Basic_SSO_model_overview.png

Figure: Basic SSO Model overview

And. the following Sequence diagram depicts the detail idea:SSO_Basic_Model.png

Figure : Sequence diagram of Login operation in basic SSO model

Sequence of operations:

  • User hits the URL of an authenticated page of www.domain1.com in the URL.
Collapse | Copy Code
[Status: browser has no authentication cookie]
  • Browser send a request to www.domain1.com with no authentication cookie (Because, it has got no cookie that belongs to www.domain1.com).
Collapse | Copy Code
[Status: browser has no authentication cookie]
  • www.domain1.com sees there is no authentication cookie in the request. So, it redirects the request to the Login page of www.domain1.com.
Collapse | Copy Code
[Status: browser has no authentication cookie]
  • User provides login credentials and hit “Login” button. Browser sends a POST request to www.domain1.com.
Collapse | Copy Code
[Status: browser has no authentication cookie]
  • www.domain1.com accepts the Login credentials, verifies the credentials against a data storage, and upon success marks the user as logged in, creates an authentication cookie with the logged in user’s information and adds to the response.
Collapse | Copy Code
[Status : browser has no authentication cookie]
  • Instead of returning the response to the browser, www.domain1.com redirects the request to a page of www.domain2.com, along with a ReturnUrl set to the original URL location of www.domain1.com. As the authentication cookie is already set in the response, the cookie is sent to the browser.
Collapse | Copy Code
[Status : browser has no authentication cookie]
  • Browser accepts the response, that contains the authentication cookie and a redirect command to www.domain2.com. So, browser stores the authentication cookie for www.domain2.com and sends a request to www.domain2.com along with setting the authentication cookie in the request.
Collapse | Copy Code
[Status : browser has an authentication cookie for www.domain2.com]
  • www.domain2.com immediately redirects to the ReturnUrl address with setting an authentication cookie for www.domain1.com by reading cookie value from the request. Eventually the authentication cookie is also sent with the response with the redirect command.
Collapse | Copy Code
[Status : browser has an authentication cookie for www.domain2.com]
  • Browser accepts the response that contains the authentication cookie and a redirect command to www.domain1.com. So, browser stores the authentication cookie now for www.domain1.com and sends a request to www.domain1.com along with setting the authentication cookie in the request.
Collapse | Copy Code
[Status : browser has authentication cookie for both www.domain1.com and www.domain2.com].
  • www.domain1.com sees that the authentication cookie is already set in the request and hence instead of returning the login page, it serves the page that is requested.
Collapse | Copy Code
[Status : browser has authentication cookie for both www.domain1.com and www.domain2.com].

So, if user hits an authenticated page of www.domain2.com in the browser now, as the authentication cookie is already stored in the browser for www.domain2.com, it is sent with the request and www.domain2.com retrieves the user information from the authentication cookie, logs in the user and serves the page output that is requested by the user.

As browser now has authentication cookie for both www.domain2.com and www.domain3.com, the user is considered to be logged onto both sites, and hence, Single Sign On implemented in both sites :)

How about “Single Sign Out”?

If we only had to manage logging onto the sites for users, we would have been done so far. But as part of the Single Sign On, we also have to manage the "Single Sign Out". That is, when user signs out of a single site, the user should be marked as signed out of all sites.

Internally, when the user signs out of a single site (Say,www.domain1.com), the authentication cookie of all other sites needs to be removed from the browser (In this case www.domain2.com). A cookie can be removed from the browser by removing the cookie from the response, before sending the response to the browser.

To remove all authentication cookies for all sites the same flow of request-redirect-response described above should be followed and instead of setting the authentication cookie, this time the authentication cookie should be removed from the response.

Problem with this SSO model

This model should work fine for 2 sites. For logging into a site and for logging out of a site, the corresponding site internally should follow a request-redirect-response flow with all other sites (That are under SSO). Once user is logged onto a single site, for all other subsequent requests onto any site, there is no request-redirect-response loop because each site has it’s own authentication cookie stored at the browser.

But, if the number of sites are more than 2, the complexity increases. That is, if user logs onto www.domain1.com, this site will internally redirect to www.domain2.com and www.domain3.com for setting authentication cookie in the browser and finally www.domain3.com redirects to www.domain1.com serve the originally requested page output to the browser. This will make the Login and Logout functionality of each site costly and complex. What if there are more than 3 sites? What if we have 20+ sites to integrate under a Single Sign On model which are deployed under different domains? The model is obviously not going to fit.

This model also requires each site to have knowledge about all other sites which are configured under a same SSO umbrella (Because, each site has to redirect to all other sites for setting the authentication cookie). Also, this would require the user authentication and authorization logic to be implemented on each site.

It’s clearly understandable, as the number of sites increases, this SSO model will become messy and will lose it’s acceptance and this model can’t really be considered a “generic” SSO model for cross-domain applications. So, we need a better model that should be independent of the number of sites to integrate under a Single Sign On umbrella.

A Proposed model for Cross-domain SSO

The previous model was kind of a “Mesh-up” where each site had to be redirected to N-1 other sites for setting and removing authentication cookie for signing in and signing out respectively. So, each site had to be configured with knowledge of the other N-1 sites and some complex and expensive login and logout logic had to be implemented.

What if we maintain a single authentication cookie for tracking user authentication for all sites? What about introducing a new dedicated site for authenticating the users and setting the authentication cookie? Sounds lucrative.

In order to implement SSO for multiple sites, the user database should be a Unified one and hence, it makes good sense to implement the user authentication and authorization functionality within a dedicated site where each site can access the functionality via a web or WCF service. So, this allows the sites to get rid of redundant user authentication/authorization functionality. But the most important question is, how this dedicated site is going to help implementing Single Sign On?

Well, in this model, the browser will not store authentication cookie for each different site. Rather, it will store an authentication cookie for only the dedicated site which will be used by the other sites to implement Single Sign On. Let’s call this site www.sso.com.

In this model, each and every request to any site (Which take part in the SSO model) will internally be redirected to the SSO site (www.sso.com) for setting and checking the existence of authentication cookie. If the cookie is found, the authenticated pages are served to the browser, and if not found, user is being redirected to the login page of the corresponding site.

The following diagram depicts the basic idea:

Proposed_SSO_model_overview.png

Figure : A dedicated site (www.sso.com) for managing authentication cookie in the proposed SSO model.

For understanding the model in detail, let’s imagine we are trying to apply this model to implement SSO to following two sites:

www.domain1.com

www.domain2.com

And, we now have a dedicated site for managing authentication cookie:

www.sso.com

Here is how this model works:

SSO_Proposed_Model_Part_I.png

Figure : Sequence diagram of an authenticated page hit without login.

Sequence of operations:

  • User hits a URL of an authenticated page of www.domain1.com
  • www.domain1.com redirects the request to www.sso.com with adding a ReturnUrl query string parameter set to the originally requested URL.
  • www.sso.com checks if there is any authentication cookie, or if there is any user Token in the request. There isn’t any. So, it redirects to the site www.domain1.com with an indication in the URL that, user needs to log in. It also appends the ReturnUrl parameter value with the query string.
  • www.domain1.com checks the query string parameters that is just being redirected from www.sso.com. The query string has indication that the user authentication cookie is not found and hence, it redirects the current request to the www.domain1.com ’s Login page, along with an indication that this request should not be redirected to the www.sso.com.SSO_Proposed_Model_Part_II.png


Figure : Sequence diagram of Login.

  • User provides credentials and hits “Login” button. No postback request is redirected to the SSO site in this model. This time, www.domain1.com invokes the web/WCF service of www.sso.com) to check the provided user credentials and upon success, returns the user object with a Token property that is generated each time a user logs in (Say, a GUID)
  • www.domain1.com marks the user as logged in (say, stores the user object in the session), prepare a URL with the user Token and redirects the current request to www.sso.com to set the authentication cookie, with the ReturnUrl parameter value being set to original request URL.
  • www.sso.com checks the incoming request URL and finds a user Token, with no authentication cookie being available yet. That indicates, user has been authenticated into the client site (www.domain1.com) and the authentication cookie now needs to be set in the browser for www.sso.com. So, it retrieves the user from the cache using the Token, prepares an authentication cookie with the user info and sets other cookie properties (Expiration date/time etc), adds the cookie to the response and finally redirects to the originally requested URL found in the ReturnUrl query string value (A URL of www.domain1.com), along with adding the Token value in the query string.
  • Browser gets a Redirect command now with ReturnUrl to www.domain1.com and also gets an authentication cookie from www.sso.com. So, it stores the authentication cookie for www.sso.com and hits a request to the URL at www.domain1.com.
  • www.domain1.com now sees that, a user Token is presented in the query string. It validates the user token via a web/WCF service call at www.sso.com and upon validation, executes the originally requested page of www.domain1.com and writes output in the response.SSO_Proposed_Model_Part_III.png


Figure : Sequence diagram of browsing an authenticated page after login.

  • User hits an authenticated page URL of www.domain2.com now.
  • www.domain2.com redirects the request to www.sso.com in the client’s browser, with setting the ReturnUrl property to the originally requested URL of www.domain2.com.
  • Browser gets a redirect command to www.sso.com. It already has an authentication cookie stored for this site and hence add this cookie to the request before sending request to www.sso.com.
  • www.sso.com checks the incoming request and looks for any authentication cookie in the request. If finds on authentication cookie this time and checks whether the cookie is expired. If not expired, it retrieves the user Token from the cookie and redirects the request to the originally requested page URL at www.domain2.com, along with setting user Token in the query string.
  • www.domain2.com sees that, there is a user Token presented in the query string. So, it validates the user token via a web/WCF service call at www.sso.com and upon validation, executes the originally requested page of www.domain2.com and writes output in the response.

To summarize,

Wow, sounds a lot of things are happening! Let me summarize those here:

Initially, browser doesn’t have any authentication cookie for www.sso.com . So, hitting any authenticated page in the browser for www.domain1.com or www.domain2.com redirects the user to the login page (Via an internal redirection to www.sso.com for checking the existence of the authentication cookie). Once a user is logged onto a site, the authentication cookie for www.sso.com is set in the browser with the logged in user information (Most importantly, the user Token, which is valid only for the user’s login session).

Now, if user hits any authenticated page URL of www.domain1.com or www.domain2.com, the request is internally redirected to www.sso.com in user’s browser and browser sends the authentication cookie, which is already set. www.sso.com finds the authentication cookie, extract the user Token and redirects to the originally requested URL in the browser with the user token and the originally requested site validates the Token and serves the page that was originally requested by the user.

Once the user is logged onto any site under this SSO model, hitting any authenticated page on www.domain1.com and www.domain2.com results in an internal redirection to www.sso.com (For checking authentication cookie and retrieving the user Token) and then serving the authentication page in the browser output.

Traffic

Following are the summary of traffics for each difference scenario:

Scenario1 : A public page hit

A trip from browser to client site + A trip from client site to browser

Summary : 1 Request + 1 Response

Scenario2 : An authenticated page hit without login

A trip from browser to client site (Page hit)+ A redirect command to browser and a trip from browser to SSO site (Redirect to SSO for cookie check)+ A redirect command to browser and a trip from browser to client site (Redirect to Client Site without cookie)+ A trip from client site to browser (Login page)

Summary : 1 Request + 2 Redirects + 1 Response

Scenario3 : Login

A trip from browser to client site (PostBack) + An invocation of authentication web service (User authentication)+ A redirect command to browser and and a trip from browser to SSO site (Redirect to SSO with Token) + A redirect command to browser and a trip from browser to client site (Setting authentication cookie) + An invocation of web service method (Token validation) + A trip from client site to browser (Serve authenticated page).

Summary : 1 Request + 2 web service calls at server + 2 Redirects + 1 Response

Scenario4 : Browse an authenticated page while logged in

A trip from browser to client site (URL hit) + A redirect command to browser and a trip from browser to SSO site (Redirect to SSO with authenticatino cookie) + A redirect command to browser and a trip from browser to client site (Checking authentication cookie) + An invocation of web service method (Token validation) + A trip from client site to browser (Serve page page)

Summary : 1 Request + 2 Redirect + 1 web service call at server + 1 Response

Scenario5 : Logout

A trip from browser to client site (Click logout link) + A redirect command to browser and a trip from browser to SSO site (Instruction to log out) + A redirect command to browser and a trip from browser to client site (After removing authentication cookie) + A trip from client site to browser (Serve login page)

Summary : 1 Request + 2 Redirects + 1 Response

Trade offs

Comparing the basic SSO model and the proposed one, it seems the basic model suits well for 2, or, at most 3 sites. In case of the basic SSO model, the Login and Logout functionality will be complex in terms of implementation and execution time, but, the subsequent pages would be served in normal request-response cycle (1 request and 1 response).

However, extending the SSO is difficult (Addition of new sites), configuration management is maximum (Each site has to manage their own cookie and each have dependency on other sites) and redundant user authentication functionality has to be implemented on multiple sites.

On the other hand, the proposed model does not have any dependency on the number of sites to integrate (You can add as many sites as you want and the SSO model won’t change). The configuration management is minimum for the participating site (No site have to know about the other sites, they only should know about the SSO site), the authentication and cookie management is handed over to a dedicated site (www.sso.com), the SSO related functionality can be easily integrated with the site if implemented smartly and could be extended easily (New sites could be added easily).

However, there is a small performance penalty. Unlike the basic model, each authenticated page access requires 3 requests from the browser to the SSO site and the client site (Two additional requests are due to two internal redirects). Though, the additional two requests take minimum execution time (A blank redirect request, just for setting and checking cookie) and hence could be considered acceptable considering today’s high Internet bandwidth.

Implementation of the proposed SSO model

Enough theories, and we should be prepared well enough now to get our hands dirty with some codes. Good that, I already have done it and going to share this In the next article very soon :). The following next article would present an actual implementation of the proposed SSO model for Cross-domain Asp.net sites and would point out some implementation challenges and their work around. 

Single Sign On (SSO) for cross-domain Asp.net applications, Part-II - The implementation.

Until then, stay tuned!