addendum: my session expired whilst writing this! On Feb 19, 1:07 pm, Paul S <paulsschw...@gmail.com> wrote: > I would like to debate some ideas for how to secure GWT apps in > different ways and their pros and cons. It is important to remember > that there will be different needs and so different approaches will be > more suitable in certain cases, but I just want to be aware of what > people are doing. > > I am using Spring Security because it is excellent, and whilst I am > aware that there are many other solutions available this is not the > focus here, so I'll just call it Security from here on. > > Security offers protection of URLs and also some more fancy AOP style > protection like protection of specific functions. To keep things > simple here lets just look at protection of URLs. > > 1. Without Ajax - Protecting URLs that relate to pages > > Before the days of Ajax where a URL effectively corresponds to a state > you can see how the model becomes straight forward. Adam accesses / > home.html, it loads and Adam gets to read a bunch of content. At this > point Adam is considered to be a Guest. Adam is curious about a link > called "Administration", when he clicks it he is sending a Request. > That Request has some header info embedded in it (which the user never > sees but you can see if with Firebug or whatever). Sadly Adam is not > signed in so Security redirects him to a login page, but remembers > everything about that original Request. Adam suddenly remembers he > does have a user name and password so he logs in. Security processes > his login and then redirects him to the exact equivalent of what would > have been the original Request. Adam is happy because his work flow > continued seamlessly despite being asked to login. > > (Ok, Spring Security can be configured to replay the original Request > upon successful login (default), or it can be forced to send you to a > particular default login success page. If you use the latter then > Adam's work flow will not be seamless because his original request for > the "Administration" page has been forgotten. Though sometimes you > might need a set up like this?) > > Now Ajax comes along, and in particular I'm going to talk about GWT > here but the principles apply. > > 2.a. With Ajax - but still protecting URLs that relate to pages > > If we use Security to protect the URL of container page (in GWT that's > the page that hosts the bootstrap javascript code for your GWT app) > then, just like normal if Adam visits /home.html he will be able to > read the content on that page. The "Administration" link has been > modified to take you to /admin.html which is in fact the host page the > GWT administrator module. Adam clicks "Administration" which Security > knows requires the Admin role so he is redirected to the login page. > Adam logs in and whether Security is configured to play back the exact > Request or whether you specifically move the browser along to / > admin.html, at this point doesn't matter. Adam is now looking at a > fully loaded GWT application. Lets say also that Security is told to > protect every GWT RPC call. Well Adam is logged in so he is allowed > access to the server services via GWT RPC and all goes smoothly... > until Adam leaves his computer for an hour and comes back to continue > his work. When the next server call that occurs is met by Security who > says, since your session has expired you are not logged in, so I'm > going to redirect you to the login page. XmlHttpRequest obeys the 30x > response code which is telling it to actually load the resource at / > login.html. In GWT this amounts to an InvocationException where the > error message content is your /login.html page markup. That's no good! > The XHR cannot interpret this as your browser would, so what to do? > The answer is pretty straightforward here. Design your /login.html > page to contain a text token that you can search for. So for example > in my /login.html code I have places an html comment right at the top > like this > <!-- SECURITY-LOGIN-PAGE --> > so when the browser hits the /login.html page it just looks like a > regular login page. But when the RPC call encounters this > InvocationTarget exception I have an onFailure handler that looks like > this: > > public void onFailure(Throwable t) { > if (t instanceof InvocationException){ > if > (t.getMessage().split("<!--\\s*SECURITY-LOGIN-PAGE\\s*-->").length > 1){ > > onLoginRequested(); > } else {...} > } else {...} > } > > My onLoginRequested() method could be any of a few styles. The most > obvious is to have it call a native method that looks like this: > > private native void redirectToLogin() /*-{ > $wnd.location.replace("/login.html"); > }-*/; > > Now at this point we have to get clear on the behaviour of Security > with regard to where it redirects the browser after successful login. > In this case you would have to specify that it ALWAYS redirects you > to /admin.html so that when Adam signs in again he is taken back into > the Administration app. But sadly his page state (history tokens) is > lost and he's back on the front screen of your app and is now required > to put the app back into the state it was before (i.e. Adam may have > had some popup open, some menu item open, etc. Now he's back on the > clean front page). > If you're wondering what would have happen if we didn't tell Security > to force the successfully logged in user back to /admin.html, but > instead allowed Security to replay the orignal Request, wouldn't we > end up back in the app with page state preserved? No! Remember that > the Request that causes us to be taken to /login.html in the first > place was the RPC call. So if Security were to do Adam the favour of > redirecting his browser to reflect the original Request then the > browser would be attempting to display the contents of the RPC call's > response! eww... not what we wanted. That's why the solution here is > to force Security to redirect any and all successful logins to / > admin.html. Disadvantage is Adam's workflow is interrupted. > > 2.b. With Ajax - iframe style login (in place login rather than the > browser being redirected to /login.html) > > Ok, so how about this: When Adam first clicks "Administration" he is > taken to the /login.html page, upon successful login he is redirected > to /admin.html. Now, as above, if he waits an hour and the tries to > perform and RPC call he receives the /login.html page via the RPC > response, as above, but instead of doing $wnd.location.replace("/ > login.html"); and sending the browser off to the login page, we simply > show a nice, pretty, GWT popup that contains an iframe that points to / > login.html. In the background Adam is still looking at the GWT > Administration app and Adam's workflow (page state) is preserved but > he must answer the login iframe before he can continue. Implementation > is up to you but I would suggest that you would have the iframe load > up /login.html and then upon clicking login two things happen, the > iframe sends the login request to Security who authenticates, and at > the same time the popup containing the iframe is removed from the DOM. > Adam can then continue with what he was doing before. Still you can't > take advantage of asking Security to replay the original request > because that would be like telling the iframe to navigate to the page > that corresponds to the original RPC call (same problem as above, > makes no sense). Ok firstly I must say I can see some issues with this > approach, like telling the Login button to tell the GWT application in > the parent frame to close the popup?! Unwieldy in my opinion. Also > note that if login fails what should happen is that the popup iframe > shows up again to ask you to log in again. But does this happen upon > unsuccessful login, or does the popup silently disappear and then only > when Adam tries to execute an action that requires the RPC call again > then we get the popup iframe login once more? Seems like this approach > carries the advantage of preserving application state but still uses > the pre-Ajax still approach. > > 3. With Ajax - protecting only RPC calls, but not protecting host page > > So anyone can visit /admin.html and the GWT app will load (the GWT is > just Javascript so who cares if the app can load, it's the data/RPC > call that we want to protect, isn't it?). > Ok so the app loads and looks like it's ready to use, but as you > invoke an action that requires an RPC call Security says, Adam, you're > not logged in. Because this example is totally Ajaxified we will still > allow Security to redirect out requests to a login URL, but this time > our login page does not contain a valid HTML login form, it just > contains a token like PLEASE-LOGIN. To keep things clear lets say that > we save this file as /login.response. So Security redirects the RPC > call to /login.response. As before, GWT is unaware the redirect taking > place, but, as before, in our onFailure method we look for > InvocationExceptions and then check the exception's .getMessage() > string and test if equals PLEASE-LOGIN. If it does then we program a > function in GWT to show a nice, pretty, GWT popup that comprises a > form. The form elements are a username input box, password input box > and login submit button. The form action will be Security's access > check URL (by default in Spring Security this will be "/ > j_spring_security_check"). If login is successful then Security would > redirect the browser to /admin.html, oops! That's not what we wanted. > What we really wanted is a way for that popup form to be submitted, > hidden and Adam is able to seamlessly continue with his work flow. > I have used this approach in an large intranet application before and > here is the result. Adam hits the /admin.html URL and the GWT app > loads. He then clicks login and the popup form appears (ok, this is > Adam hitting login, but equally he could try an action and it would > fail and the login popup would show). Now, it was quite a nuisance for > Adam that when his session expires and he logs in using the popped up > form he is taken back to the apps front page. So, not to be put off by > the failure of this approach, I built in a ping system, so the GWT app > periodically (every 5 minutes) pings the server via a very simple RPC > call but to tell it "hey, still here, don't lose my session!". The > problem with this is that we are solving the problem by overcoming the > session time out problem. That's ok but not really what we want - not > to mention some purists would say that this is an abuse of the session > timeout function. I'm not sure where I sit on that argument, because > session timeout does two things - 1. ensure that if you walk away from > your computer and then later a rogue colleague sits are you computer, > the system protects itself by having timed out and requiring login > again, assuming an hour elapsed. 2. allows the server a way to garbage > collect old sessions so it's memory isn't taken up by session > information from last week/month/year. If 2. is all you care about > then the server ping approach works fine. > > 4. With Ajax - logging in using an RPC call > > This would be the silver bullet, wouldn't it? I doubt (though maybe I > am wrong) that you could employ the traditional style of protection/ > login as mentioned in 2. to protect your host page "/admin.html" and > then if successfully logged in you gain access to the host page and > all of the RPC calls as well, but when your session expires you get > the nice, pretty, GWT popup that then does its second login via an RPC > call?! This would require that the URL of your RPC login service would > have to have public access, but all your business services would need > Admin access. > The advantages here are > - admin app is protected > - RPC calls are protected > - if session times out and you attempt an RPC call then your > onFailure code would know to show you the login popup > - if you successfully login then the popup hides and you may continue > with your work. Page state/work flow was never interrupted. At worst > you'll need to repeat your last action, which may be clicking "Save" > again, or whatever, I don't know if we could get the RPC call Request > to replay automatically, your thoughts? > > If this is possible then please share. If it is not, then I would > still like to explore the authentication over RPC technique, and would > be happy to forego having the /admin.html page protected. Like I said, > in most apps it is the interaction with the server that must be > protected, it is not crucial to protect your Javascript application > code. (unless it is ;) ). > > I hope this helps someone, and in return I hope someone can help me > with approach number 4. Note that approach number 4 will require some > server side set up, so will require some Spring-specific modifications/ > changes of default behaviour. > > Happy coding, > Paul S
-- You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group. To post to this group, send email to google-web-tool...@googlegroups.com. To unsubscribe from this group, send email to google-web-toolkit+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.