Implementing Single Sign On…
So when I set out to rewrite our ASM system, I knew I had to find some selling points to the architecture I was pitching. One of them was the ability to write an SSO system that was easy and efficient and most of all did not require much code for implementing applications (JSSO and the like were out of the question).
So here’s what I came up with (everything is written in Grails)… I first created an AuthController which would handle the authentication and return back a user id for the person if they were a valid user (either in our custom user store or our AD system). This controller had a login action which displayed the login prompt and would return all the necessary error back to the user if something was wrong.
I then wrote another action whose corresponding GSP stored my javascript for creating the needed iframes on the page. This meant that when someone loaded the action I could access all of their cookies (which I needed for SSO) even if their application was on another domain. In the action I would process the cookies and either send them the login page or return the user id back to the browser which would then be processed by the application.
In the end the only code the implementing applications need to have is the follow:
1 2 3 4 5 6 7 8 9 10 11 12 | <script src="http://www.google.com/jsapi"></script> <script src="http://localhost:8080/AppHub/auth/script"></script> <script> // Load jQuery google.load("jquery", "1.3.2"); google.load("jqueryui", "1.7.2"); google.setOnLoadCallback(function() { loadModal('local', window.location.protocol+"//"+window.location.host+"/LoginApplication/login/show/", window.location.protocol+"//"+window.location.host+window.location.pathname); }); </script> |
And here is how I process the script action:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def script = { def cookie = request.cookies.find { it.name == 'session_id' } if (!cookie) { render(view: "script", contentType: "text/javascript", model: [flag: 'false']) } else { def id = Session.findBySessionIdAndKey(cookie.value, "id") if (id && cookie.value == id.sessionId) { render(view: "script", contentType: "text/javascript", model: [flag: 'true', id: id.value]) } else { cookie.maxAge = 0 response.addCookie(cookie) render(view: "script", contentType: "text/javascript", model: [flag: 'false']) } } } |
And here is the script.gsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | function loadModal(env, targetUrl, returnUrl) { var flag = ${flag}; $(window).load(function() { if(flag == false) { if(env == 'dev' || env == 'development') { $("head").append("<link rel=\"stylesheet\" href=\"http://162.143.99.200:8080/AppHub/css/ui-darkness/jquery-ui-1.7.2.custom.css\" type=\"text/css\" media=\"screen\" />"); $("head").append("<link rel=\"stylesheet\" href=\"http://162.143.99.200:8080/AppHub/css/login.css\" type=\"text/css\" media=\"screen\" />"); $("head").append("<link rel=\"stylesheet\" href=\"http://162.143.99.200:8080/AppHub/css/form.css\" type=\"text/css\" media=\"screen\" />"); $("body").append("<div id=\"modal\"></div>"); $("#modal").append("<div id=\"box\"></div>"); $("#box").append("<h2 style=\"color:#666666;\">AppHub:<span class=\"light\">Connect</span></h2>"); if(hasError('user.username.invalid')) { $("#box").append("<p class=\"class\" style=\"color:#f00;\"><strong>Error:</strong><g:message code="user.username.invalid" /></p>"); } if(hasError('user.username.blank')) { $("#box").append("<p class=\"class\" style=\"color:#f00;\"><strong>Error:</strong><g:message code="user.username.blank" /></p>"); } if(hasError('user.password.blank')) { $("#box").append("<p class=\"class\" style=\"color:#f00;\"><strong>Error:</strong><g:message code="user.password.blank" /></p>"); } if(hasError('user.password.invalid')) { $("#box").append("<p class=\"class\" style=\"color:#f00;\"><strong>Error:</strong><g:message code="user.password.invalid" /></p>"); } if(hasError('user.adproblem')) { $("#box").append("<p class=\"class\" style=\"color:#f00;\"><strong>Error:</strong><g:message code="user.adproblem" /></p>"); } if(hasError('user.kerberos.6')) { $("#box").append("<p class=\"class\" style=\"color:#f00;\"><strong>Error:</strong><g:message code="user.kerberos.6" /></p>"); } if(hasError('user.kerberos.18')) { $("#box").append("<p class=\"class\" style=\"color:#f00;\"><strong>Error:</strong><g:message code="user.kerberos.18" /></p>"); } if(hasError('user.kerberos.23')) { $("#box").append("<p class=\"class\" style=\"color:#f00;\"><strong>Error:</strong><g:message code="user.kerberos.23" /></p>"); } if(hasError('user.kerberos.24')) { $("#box").append("<p class=\"class\" style=\"color:#f00;\"><strong>Error:</strong><g:message code="user.kerberos.24" /></p>"); } $("#box").append("<form id=\"form\" method=\"POST\" action=\"http://162.143.99.200:8080/AppHub/auth/signIn\"></form>"); $("#form").append("<input type=\"hidden\" name=\"targetUrl\" value=\""+targetUrl+"\" />"); $("#form").append("<input type=\"hidden\" name=\"returnUrl\" value=\""+returnUrl+"\" />"); $("#form").append("<input type=\"hidden\" name=\"ip\" value=\"${request.getRemoteAddr()}\" />"); $("#form").append("<ul></ul>"); $("#form > ul").append("<li><label for=\"username\">Username</label><div><input type=\"text\" name=\"username\" class=\"max text\" /></div></li>"); $("#form > ul").append("<li><label for=\"password\">Password</label><div><input type=\"password\" name=\"password\" class=\"max text\" /></div></li>"); $("#form > ul").append("<li><input type=\"submit\" name=\"submit\" class=\"button\" value=\"Sign In\" /></li>"); $("#form > ul").append("<li><a style=\"color:#0088CC;\" href=\"#\">Forgot Password</a><span style=\"color:#0088CC;\"> | </span><a style=\"color:#0088CC;\" href=\"#\">Register</a><span style=\"color:#0088CC;\"> | </span><a style=\"color:#0088CC;\" href=\"#\">Unlock Account</a></li>"); } if(env == 'local') { $("head").append("<link rel=\"stylesheet\" href=\"http://localhost:8080/AppHub/css/ui-darkness/jquery-ui-1.7.2.custom.css\" type=\"text/css\" media=\"screen\" />"); $("head").append("<link rel=\"stylesheet\" href=\"http://localhost:8080/AppHub/css/login.css\" type=\"text/css\" media=\"screen\" />"); $("head").append("<link rel=\"stylesheet\" href=\"http://localhost:8080/AppHub/css/form.css\" type=\"text/css\" media=\"screen\" />"); $("body").append("<div id=\"modal\"></div>"); $("#modal").append("<div id=\"box\"></div>"); $("#box").append("<h2 style=\"color:#666666;\">AppHub:<span class=\"light\">Connect</span></h2>") if(hasError('user.username.invalid')) { $("#box").append("<p class=\"class\" style=\"color:#f00;\"><strong>Error:</strong><g:message code="user.username.invalid" /></p>"); } if(hasError('user.username.blank')) { $("#box").append("<p class=\"class\" style=\"color:#f00;\"><strong>Error:</strong><g:message code="user.username.blank" /></p>"); } if(hasError('user.password.blank')) { $("#box").append("<p class=\"class\" style=\"color:#f00;\"><strong>Error:</strong><g:message code="user.password.blank" /></p>"); } if(hasError('user.password.invalid')) { $("#box").append("<p class=\"class\" style=\"color:#f00;\"><strong>Error:</strong><g:message code="user.password.invalid" /></p>"); } if(hasError('user.adproblem')) { $("#box").append("<p class=\"class\" style=\"color:#f00;\"><strong>Error:</strong><g:message code="user.adproblem" /></p>"); } if(hasError('user.kerberos.6')) { $("#box").append("<p class=\"class\" style=\"color:#f00;\"><strong>Error:</strong><g:message code="user.kerberos.6" /></p>"); } if(hasError('user.kerberos.18')) { $("#box").append("<p class=\"class\" style=\"color:#f00;\"><strong>Error:</strong><g:message code="user.kerberos.18" /></p>"); } if(hasError('user.kerberos.23')) { $("#box").append("<p class=\"class\" style=\"color:#f00;\"><strong>Error:</strong><g:message code="user.kerberos.23" /></p>"); } if(hasError('user.kerberos.24')) { $("#box").append("<p class=\"class\" style=\"color:#f00;\"><strong>Error:</strong><g:message code="user.kerberos.24" /></p>"); } $("#box").append("<form id=\"form\" method=\"POST\" action=\"http://localhost:8080/AppHub/auth/signIn\"></form>"); $("#form").append("<input type=\"hidden\" name=\"targetUrl\" value=\""+targetUrl+"\" />"); $("#form").append("<input type=\"hidden\" name=\"returnUrl\" value=\""+returnUrl+"\" />"); $("#form").append("<input type=\"hidden\" name=\"ip\" value=\"${request.getRemoteAddr()}\" />"); $("#form").append("<ul></ul>"); $("#form > ul").append("<li><label for=\"username\">Username</label><div><input type=\"text\" name=\"username\" class=\"max text\" /></div></li>"); $("#form > ul").append("<li><label for=\"password\">Password</label><div><input type=\"password\" name=\"password\" class=\"max text\" /></div></li>"); $("#form > ul").append("<li><input type=\"submit\" name=\"submit\" class=\"button\" value=\"Sign In\" /></li>"); $("#form > ul").append("<li><a style=\"color:#0088CC;\" href=\"#\">Forgot Password</a><span style=\"color:#0088CC;\"> | </span><a style=\"color:#0088CC;\" href=\"#\">Register</a><span style=\"color:#0088CC;\"> | </span><a style=\"color:#0088CC;\" href=\"#\">Unlock Account</a></li>"); } //open dialog $("#modal").dialog({ autoOpen: true, height: 450, width: 500, modal: true, resizable: false, position: 'center', draggable: false, closeOnEscape: false }); //hide the title bar $(".ui-dialog-titlebar").hide(); } else { $("body").append("<form id=\"form\" method=\"POST\" action=\""+targetUrl+"\"></form>"); $("#form").append("<input type=\"hidden\" name=\"id\" value=\"${id}\" />"); $("#form").append("<input type=\"hidden\" name=\"ip\" value=\"${request.getRemoteAddr()}\" />"); $("#form").submit(); } }); } function getParameters() { var vars = [], hash; var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); for(var i = 0; i < hashes.length; i++) { hash = hashes[i].split('='); vars.push(hash[0]); vars[hash[0]] = hash[1]; } return vars; } function getParameter(name) { return getParameters()[name]; } function getErrors() { if(getParameter('error') != null) { return getParameter('error').split(';'); } else { return null } } function hasError(code) { var errors = getErrors(); if(getErrors() != null) { for(var i = 0; i < getErrors().length; i++) { if(errors[i] == code) { return true; } } } else { return false; } } |
Could it be cleaner? Sure and when I hone in my JQuery skills I will definitely clean it up, but for now it works. =)
Posted in: REST, grails, javascript
Leave a comment
You must be logged in to post a comment.

