{"id":10835,"date":"2013-10-01T18:11:39","date_gmt":"2013-10-01T12:41:39","guid":{"rendered":"http:\/\/www.tothenew.com\/blog\/?p=10835"},"modified":"2017-04-24T16:06:12","modified_gmt":"2017-04-24T10:36:12","slug":"spring-security-cross-domain-authentication","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/spring-security-cross-domain-authentication\/","title":{"rendered":"Spring Security &#038; Grails: Cross domain authentication from HTTP to HTTPS"},"content":{"rendered":"<p style=\"text-align: justify;\"><a href=\"\/blog\/wp-ttn-blog\/uploads\/2013\/10\/spring_security_login.jpg\"><img decoding=\"async\" loading=\"lazy\" class=\" wp-image-10940 alignright\" title=\"spring_security_login\" src=\"\/blog\/wp-ttn-blog\/uploads\/2013\/10\/spring_security_login.jpg\" alt=\"spring_security_login\" width=\"252\" height=\"202\" \/><\/a>We were trying to implement SSL-based login and registration (i.e. HTTPS) in an e-commerce web application which was otherwise using the non-secure protocol (i.e. HTTP) for the entire website.<\/p>\n<p style=\"text-align: justify;\">Instead of moving the entire web application to SSL, which would have increased response times, we thought it would be best if only the authentication part of the web application could be moved to be SSL. However, this also posed an even bigger problem of cross-domain authentication since the protocol was shifting from non-secure (HTTP) to secure pages (HTTPS).<\/p>\n<p style=\"text-align: justify;\">As you all know, Spring Security uses an internal URL (\/j_spring_security_check) for authentication purposes that is provided out of the box. So our first attempt at cross-domain authentication was via AJAX. But we soon gave up that solution because of how cross-domain operates in the real world.<\/p>\n<h4 style=\"text-align: justify;\">How cross domain requests operate<\/h4>\n<p style=\"text-align: justify;\">Whenever you&#8217;re making a cross-domain AJAX call, the following happens:<\/p>\n<ol style=\"text-align: justify;\">\n<li>A pre-flight request is sent first (an OPTIONS request) to ensure that the domain making the request is allowed to make the request to the domain receiving the request.<\/li>\n<li>If the receiving domain sends back a response header containing the &#8220;Access-Control-Allow-Origin&#8221;, then the subsequent GET\/POST request is sent and the normal flow starts.<\/li>\n<\/ol>\n<p style=\"text-align: justify;\">Now Grails doesn&#8217;t support a CORS request out-of-the-box according to this issue. So we have a wonderful plugin to do just that. But it doesn&#8217;t seem to be able to add CORS headers to the Spring Security plugin. So I had to give up the AJAX-ified approach and started looking towards an iframe based approach.<\/p>\n<h4 style=\"text-align: justify;\">1. Change the login form<\/h4>\n<p>[code]<br \/>\n&amp;lt;form action=&amp;quot;https:\/\/localhost:8443\/j_spring_security_check&amp;quot; method=&amp;quot;POST&amp;quot; name=&amp;quot;loginForm&amp;quot; target=&amp;quot;hidden_iframe&amp;quot;&amp;gt;<br \/>\n  &amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;j_username&amp;quot; \/&amp;gt;<br \/>\n  &amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;j_password&amp;quot; \/&amp;gt;<br \/>\n&amp;lt;\/form&amp;gt;<\/p>\n<p>&amp;lt;iframe style=&amp;quot;display: none;&amp;quot; name=&amp;quot;hidden_iframe&amp;quot; width=&amp;quot;320&amp;quot; height=&amp;quot;240&amp;quot;&amp;gt;&amp;lt;\/iframe&amp;gt;<br \/>\n[\/code]<\/p>\n<p style=\"text-align: justify;\">What the above code does is that it sends a POST request to the requested URL and loads the response in the iframe instead of redirecting the page.<\/p>\n<h4 style=\"text-align: justify;\">2. Change the Spring Security plugin config<\/h4>\n<p style=\"text-align: justify;\">We were using the wonderful Spring Security plugin for authentication which is highly configurable. We changed the authentication success and failure URL&#8217;s to redirect to our custom GSP&#8217;s.<\/p>\n<p>[code]<br \/>\ngrails.plugins.springsecurity.failureHandler.ajaxAuthFailUrl = &#8216;\/login\/denied&#8217;<br \/>\ngrails.plugins.springsecurity.successHandler.defaultTargetUrl = &#8216;\/login\/authsuccess&#8217;<br \/>\n[\/code]<\/p>\n<h4 style=\"text-align: justify;\">3. Change content of required GSP&#8217;s<\/h4>\n<p style=\"text-align: justify;\"><code>denied.gsp<\/code><\/p>\n<p>[js]&amp;lt;script type=&amp;quot;text\/javascript&amp;quot;&amp;gt;\/\/ &amp;lt;![CDATA[<br \/>\n   window.top.postMessage( JSON.stringify({signin: &#8216;error&#8217;}), &amp;quot;*&amp;quot; );<br \/>\n\/\/ ]]&amp;gt;&amp;lt;\/script&amp;gt;<br \/>\n[\/js]<\/p>\n<p style=\"text-align: justify;\"><code>auth.gsp<\/code><\/p>\n<p>[js]&amp;lt;script type=&amp;quot;text\/javascript&amp;quot;&amp;gt;\/\/ &amp;lt;![CDATA[<br \/>\n   window.top.postMessage( JSON.stringify({signin: &#8216;success&#8217;}), &amp;quot;*&amp;quot; );<br \/>\n\/\/ ]]&amp;gt;&amp;lt;\/script&amp;gt;<br \/>\n[\/js]<\/p>\n<p style=\"text-align: justify;\">The postMessage method is a special Javascript method for cross-iframe communication. The first argument is the data that needs to be posted, and the second argument is the domain to which the data should be sent. When you specify &#8220;*&#8221;, it means it will be sent to all domains and can be caught by any event listener that can listen to the event generate.<\/p>\n<h4 style=\"text-align: justify;\">4. Modify page containing the login form<\/h4>\n<p style=\"text-align: justify;\">Add the following piece of javascript to catch the event that&#8217;s being generated by the hidden iframe.<\/p>\n<p style=\"text-align: justify;\">The code is being picked up from David Walsh&#8217;s blog to provide cross-browser event compatibility. Thanks David!<\/p>\n<p>[code]<br \/>\n\/\/ Create IE + others compatible event handler<br \/>\nvar eventMethod = window.addEventListener ? &amp;quot;addEventListener&amp;quot; : &amp;quot;attachEvent&amp;quot;;<br \/>\nvar eventer = window[eventMethod];<br \/>\nvar messageEvent = eventMethod == &amp;quot;attachEvent&amp;quot; ? &amp;quot;onmessage&amp;quot; : &amp;quot;message&amp;quot;;<\/p>\n<p>\/\/ Listen to message from child window<br \/>\neventer(messageEvent,function(e) {<br \/>\n   console.log(&#8216;parent received message!:  &#8216;, JSON.parse(e.data));<br \/>\n   \/\/ Do additional processing of data received<br \/>\n},false);<br \/>\n[\/code]<\/p>\n<p style=\"text-align: justify;\">And there you are. You have a perfectly working cross-domain authentication mechanism in place that&#8217;s integrated with Grails, Spring Security, and JavaScript.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>We were trying to implement SSL-based login and registration (i.e. HTTPS) in an e-commerce web application which was otherwise using the non-secure protocol (i.e. HTTP) for the entire website. Instead of moving the entire web application to SSL, which would have increased response times, we thought it would be best if only the authentication part [&hellip;]<\/p>\n","protected":false},"author":33,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":8},"categories":[2026,7],"tags":[1221,1222,227,1157,1220,4841,672,824],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/10835"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/33"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=10835"}],"version-history":[{"count":0,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/10835\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=10835"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=10835"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=10835"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}