Developer notes written down before they get lost.
Google AppEngine, Restlet & Security
I was wondering how to secure the resources in my current application. The application is deployed on the Google
AppEngine and uses Guice 2.0 and Restlet 2.0.
Inspired by the post from David M. Chandler I
decided to use the AppEngine cookie named “ACSID” as a token in each and every url to secure my resources. This way
the url to the “projects” resource becomes http://karaka-d8.appspot.com/rest/v1/<ACSID>/projects.
Technically I’m using an aspect together with a custom annotation to secure the resources. Here’s the Guice module for
the security stuff:
With the above setup all methodes in subclasses of ServerResource which are annotated with the custom @Secured
annotation are handled by the SecurityInterceptor. This class contains the logic to check whether there’s a
authenticated user and whether the session cookie is correct (that’s essentially the code from
David M. Chandlers post)
publicclassSecurityInterceptorimplementsMethodInterceptor{privatestaticfinalStringAPPENGINE_COOKIE="ACSID";@OverridepublicObjectinvoke(MethodInvocationinvocation)throwsThrowable{UserServiceuserService=UserServiceFactory.getUserService();Useruser=userService.getCurrentUser();if(user==null){thrownewSecurityException("No user");}ServerResourceresource=(ServerResource)invocation.getThis();Stringtoken=(String)resource.getRequest().getAttributes().get("token");if(token==null||token.length()==0){thrownewSecurityException("No security token");}// Skip check on localhost so we can test in AppEngine local dev envStringsessionId=findSessionId(resource);StringserverName=resource.getReference().getHostDomain();if(!("localhost".equals(serverName))&&!(token.equals(sessionId))){thrownewSecurityException("Security token invalid");}returninvocation.proceed();}privateStringfindSessionId(ServerResourceresource){Stringresult=null;Series<Cookie>cookies=resource.getCookies();for(Cookiecookie:cookies){if(APPENGINE_COOKIE.equals(cookie.getName())){result=cookie.getValue();break;}}returnresult;}}
To make this work the resource mappings have to include a {token} parameter. So inside your Router you should have
something like that
One last note: First I tried to use the @Get annotation from Restlet 2.0 instead of a custom annotation and configured
the SecurityInterceptor as follows:
Unfortunately that didn’t work because the @Get annotation is not available in the generated AOP proxy. So Restlet
has no way to figure out what method to call for a GET request. Instead you have to override the get method.