{"id":273,"date":"2013-09-06T19:23:11","date_gmt":"2013-09-06T19:23:11","guid":{"rendered":"http:\/\/www.silverclaw.net\/?p=273"},"modified":"2013-09-06T19:26:21","modified_gmt":"2013-09-06T19:26:21","slug":"single-sign-on-sso-from-asp-net-to-php","status":"publish","type":"post","link":"https:\/\/www.silverclaw.net\/?p=273","title":{"rendered":"Single Sign-On (SSO) from ASP.NET to PHP"},"content":{"rendered":"<p>I recently implemented the new <a href=\"http:\/\/forums.excelcentral.com\/\"> ExcelCentral forums<\/a>, and was faced with the challenge of integrating the login from our main ASP.NET site with the PHP-based Invision forum software.<\/p>\n<p>To make this possible, I modified the forum software to retrieve ASP.NET&#8217;s login cookie and send a request back to the ASP.NET site to validate it and return the details of the logged-in user.<\/p>\n<p>On the PHP side, the code to check whether a user is logged into the main site looks something like:<\/p>\n<pre><strong>\/* Get the ASP.NET Login cookie (ASPXAUTH) *\/<\/strong>\r\n$sessioncookie = $_COOKIE['_ASPXAUTH'];\r\n\r\nif ( !$sessioncookie )\r\n{\r\n    <strong>\/* If we have no cookie, user is not logged in *\/<\/strong>\r\n    <strong>\/* Code for anonymous users here *\/<\/strong>\r\n}\r\nelse\r\n{\r\n    <strong>\/* Send the key from the ASPXAUTH cookie to a page within the ASP.NET application that will return the user's details *\/<\/strong>\r\n    $userdata = file_get_contents('http:\/\/www.yourdomain.com\/getloggedinuser.aspx?key='.$sessioncookie);\r\n\r\n    if ($userdata == \"\")\r\n    {\r\n        <strong>\/* The ASP.NET site did not consider the login cookie to be valid (possibly the session has expired) *\/<\/strong>\r\n        <strong>\/* Code for anonymous users here *\/<\/strong>\r\n    }\r\n    else\r\n    {\r\n        <strong>\/* Parse the data that was returned from the ASP.NET system *\/<\/strong>\r\n        $parseduserdata = json_decode($data, true);\r\n        $userid = $parseduserdata['id'];\r\n        $username = $parseduserdata['username'];\r\n        <strong>\/* Code for logged-in users here *\/<\/strong>\r\n    }\r\n}<\/pre>\n<p>Now we need to write the code for the <em>getloggedinuser.aspx<\/em> page within the ASP.NET system:<\/p>\n<pre>protected void Page_Load(object sender, EventArgs e)\r\n{\r\n\u00a0\u00a0\u00a0 try\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (Request.QueryString[\"key\"] != null)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>\/\/ Retrieve the login key value from the querystring (this is the code from the ASPXAUTH cookie)<\/strong>\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 string AuthKey = Request.QueryString[\"key\"];\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>\/\/ Decrypt the key and get the associated Forms Authentication ticket<\/strong>\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 FormsAuthenticationTicket Ticket = FormsAuthentication.Decrypt(AuthKey);\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>\/\/ Retrieve the user's details from the ticket<\/strong>\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 string UserName = Ticket.Name;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 MembershipUser LoggedInUser = Membership.GetUser(UserName);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 string UserID = LoggedInUser.ProviderUserKey.ToString();\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>\/\/ Output the user details in JSON format<\/strong>\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Response.ContentType = \"application\/json\";\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Response.Write(\"{\\\"id\\\": \\\"\" + UserID + \"\\\",\\\"username\\\": \\\"\" + UserName + \"\\\"}\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Response.Flush();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Response.SuppressContent = true;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 HttpContext.Current.ApplicationInstance.CompleteRequest();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 else\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <strong>\/\/ Return a blank page if there is no key provided<\/strong>\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Response.Write(\"\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Response.Flush();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Response.SuppressContent = true;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 HttpContext.Current.ApplicationInstance.CompleteRequest();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 catch(Exception Ex)\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0<strong>\/\/ Return a blank page if an exception occurs<\/strong>\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Response.Write(\"\");\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Response.Flush();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Response.SuppressContent = true;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 HttpContext.Current.ApplicationInstance.CompleteRequest();\r\n\u00a0\u00a0\u00a0 }\r\n}<\/pre>\n<p>By using <em>FormsAuthentication.Decrypt<\/em> as shown above, we can easily get the user details as long as we can provide the value of the user&#8217;s ASPXAUTH cookie. Remember that cookies are only shared across a single domain, so you won&#8217;t be able to implement single-sign-on across domains.<\/p>\n<p>In my system, the login cookie is available on both <em>excelcentral.com<\/em> and on <em>forums.excelcentral.com<\/em>, so login can be shared between the two.\u00a0 However, my <em>aspnetcentral.com<\/em> site wouldn&#8217;t be able to get the login cookie from <em>excelcentral.com<\/em>.<\/p>\n<p>ASP.NET&#8217;s default behaviour can cause problems here, because it doesn&#8217;t mark cookies with a domain by default.\u00a0 To change this, you need to edit <em>Web.config<\/em> with the following (within the <em>system.web<\/em> tag):<\/p>\n<pre>&lt;httpCookies domain=\"yourdomain.com\" \/&gt;<\/pre>\n<p>This setting will mark ASP.NET&#8217;s login cookies with your domain, allowing them to be retrieved by any subdomains (eg forums.yourdomain.com).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I recently implemented the new ExcelCentral forums, and was faced with the challenge of integrating the login from our main ASP.NET site with the PHP-based Invision forum software. To make this possible, I modified the forum software to retrieve ASP.NET&#8217;s &hellip; <a href=\"https:\/\/www.silverclaw.net\/?p=273\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[12,1],"tags":[],"_links":{"self":[{"href":"https:\/\/www.silverclaw.net\/index.php?rest_route=\/wp\/v2\/posts\/273"}],"collection":[{"href":"https:\/\/www.silverclaw.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.silverclaw.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.silverclaw.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.silverclaw.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=273"}],"version-history":[{"count":5,"href":"https:\/\/www.silverclaw.net\/index.php?rest_route=\/wp\/v2\/posts\/273\/revisions"}],"predecessor-version":[{"id":278,"href":"https:\/\/www.silverclaw.net\/index.php?rest_route=\/wp\/v2\/posts\/273\/revisions\/278"}],"wp:attachment":[{"href":"https:\/\/www.silverclaw.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=273"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.silverclaw.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=273"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.silverclaw.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=273"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}