Spring Security in Google App Engine |
|

Spring Security is well-known for being highly customizable, so for my first attempt at working with Google App Engine, I decided to create a simple application which would explore the use of GAE features by implementing some core Spring Security interfaces. In this article we'll see how to:
- Authenticate using Google Accounts.
- Implement "on-demand" authentication when a user accesses a secured resource.
- Supplement the information from Google Accounts with application-specific roles.
- Store user account data in an App Engine datastore using the native API.
- Setup access-control restrictions based on the roles assigned to users.
- Disable the accounts of specific users to prevent access.
You should already be familiar with deploying applications to GAE. It doesn't take long to get a basic application up and running and you'll find lots of guidance on this on the GAE website.
Sample Application
The application is very simple and is built using Spring MVC. There is a welcome page deployed at the application root, and you can progress to a "home page", but only after authenticating and registering with the application. You can try out a version deployed in GAE here.
The registered users are stored as GAE datastore entities. On first authenticating, new users are redirected to a registration page where they can enter their name. Once registered, user accounts can be flagged as "disabled" in the datastore and the user won't be allowed to use the app, even though they have authenticated through GAE.
Spring Security Background
We're assuming that you're already familiar with Spring Security's namespace configuration and ideally have some knowledge of the core interfaces and how they interact. The basics are covered in the Technical Overview chapter of the reference manual. If you're also familiar with the internals of Spring Security, you'll know that web authentication mechanisms such as form-based login are implemented using a servlet Filter and an AuthenticationEntryPoint. The AuthenticationEntryPoint drives the authentication process when an anonymous user tries to access a secured resource and the filter extracts authentication information from a subsequent request (such as the submission of a login form), authenticates the user and builds a security context for the user's session.
The filter delegates the authentication decision to the AuthenticationManager which is configured with a list of AuthenticationProvider beans, any one of which may authenticate the user, or raise an exception if the authentication fails.
In the case of a form-based login, the AuthenticationEntryPoint simply redirects the user to the login page. The authentication filter (UsernamePasswordAuthenticationFilter in this case) extracts the username and password from the submitted POST request. They are stored in an Authentication object and passed to an AuthenticationProvider which will typically compare the user's password with one stored in a database or LDAP server.
That's the basic interaction between the components. How might this apply to a GAE application?
Google Accounts Authentication
Of course, there's nothing to stop you deploying a standard Spring Security application in GAE (without JDBC support, of course), but what if you want to make use of the API which GAE provides to allow users to authenticate via their usual Google login? This is actually very simple and most of the work is handled by GAE's UserService, which has a method for generating an external login URL. You provide a destination which the user will be returned to once they've authenticated, allowing them to continue using the application. We could use this to render a login link in a web page, but we can also redirect directly to it in a custom AuthenticationEntryPoint:
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
public class GoogleAccountsAuthenticationEntryPoint implements AuthenticationEntryPoint {
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
UserService userService = UserServiceFactory.getUserService();
response.sendRedirect(userService.createLoginURL(request.getRequestURI()));
}
}
If we add this to our configuration, using the specific hook that the Spring Security namespace provides for this purpose, we have something like this:
<b:beans xmlns="http://www.springframework.org/schema/security"
xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http use-expressions="true" entry-point-ref="gaeEntryPoint">
<intercept-url pattern="/" access="permitAll" />
<intercept-url pattern="/**" access="hasRole('USER')" />
</http>
<b:bean id="gaeEntryPoint" class="samples.gae.security.GoogleAccountsAuthenticationEntryPoint" />
...
</b:beans>
Here we've configured all URLs to require the "USER" role, except for the webapp root. The user will be redirected to the Google Accounts login screen when they first attempt to access any other page:

We now need to add the filter bean which will set up the security context when the user is redirected back to our site by GAE logging in to Google Accounts. Here's the authentication filter code:
public class GaeAuthenticationFilter extends GenericFilterBean {
private static final String REGISTRATION_URL = "/register.htm";
private AuthenticationDetailsSource ads = new WebAuthenticationDetailsSource();
private AuthenticationManager authenticationManager;
private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
// User isn't authenticated. Check if there is a Google Accounts user
User googleUser = UserServiceFactory.getUserService().getCurrentUser();
if (googleUser != null) {
// User has returned after authenticating through GAE. Need to authenticate to Spring Security.
PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(googleUser, null);
token.setDetails(ads.buildDetails(request));
try {
authentication = authenticationManager.authenticate(token);
// Setup the security context
SecurityContextHolder.getContext().setAuthentication(authentication);
// Send new users to the registration page.
if (authentication.getAuthorities().contains(AppRole.NEW_USER)) {
((HttpServletResponse) response).sendRedirect(REGISTRATION_URL);
return;
}
} catch (AuthenticationException e) {
// Authentication information was rejected by the authentication manager
failureHandler.onAuthenticationFailure((HttpServletRequest)request, (HttpServletResponse)response, e);
return;
}
}
}
chain.doFilter(request, response);
}
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
public void setFailureHandler(AuthenticationFailureHandler failureHandler) {
this.failureHandler = failureHandler;
}
}
We've implemented the filter from scratch, making it simpler to understand and avoiding the complication of inheriting from existing classes. If a user is currently unauthenticated (from Spring Security's perspective), the filter checks for the existence of a GAE user (again making use of the GAE UserService). If one is found, then it packages it up in a suitable authentication token object (Spring Security's PreAuthenticatedAuthenticationToken is used here for convenience) and passes it to the AuthenticationManager to be authenticated by Spring Security. New users are redirected to the registration page at this point.
Custom Authentication Provider
In this scenario, we are not authenticating the user in the traditional sense of determining whether they are who they claim to be. Google accounts has already taken care of that. We are only interested in checking whether the user is a valid user from the application's perspective. The situation is similar to using Spring Security with a single sign-on system such as CAS or OpenID. The authentication provider needs to check the user's account status and load any other information (such as application-specific roles). In our sample, we also have the concept of an "unregistered" user who hasn't used the application before. If the user is unknown to the application, they will be assigned a temporary "NEW_USER" role, which will only allow them access to the registration URL. Once registered, they are assigned the "USER" role.
The AuthenticationProvider implementation interacts with a UserRegistry to store and retrieve GaeUser objects (both specific to this sample):
public interface UserRegistry {
GaeUser findUser(String userId);
void registerUser(GaeUser newUser);
void removeUser(String userId);
}
public class GaeUser implements Serializable {
private final String userId;
private final String email;
private final String nickname;
private final String forename;
private final String surname;
private final Set<AppRole> authorities;
private final boolean enabled;
// Constructors and accessors omitted
...
The userId is the unique ID assigned by Google Accounts. Email and nickname are also obtained from the GAE user. Forename and surname are entered in the registration form. The enabled flag is set to "true" unless it is modified directly through the GAE datastore administration console. AppRole is an implementation of Spring Security's GrantedAuthority as an enum:
public enum AppRole implements GrantedAuthority {
ADMIN (0),
NEW_USER (1),
USER (2);
private int bit;
AppRole(int bit) {
this.bit = bit;
}
public String getAuthority() {
return toString();
}
}
The roles are assigned as described above. The AuthenticationProvider then looks like this:
public class GoogleAccountsAuthenticationProvider implements AuthenticationProvider {
private UserRegistry userRegistry;
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
User googleUser = (User) authentication.getPrincipal();
GaeUser user = userRegistry.findUser(googleUser.getUserId());
if (user == null) {
// User not in registry. Needs to register
user = new GaeUser(googleUser.getUserId(), googleUser.getNickname(), googleUser.getEmail());
}
if (!user.isEnabled()) {
throw new DisabledException("Account is disabled");
}
return new GaeUserAuthentication(user, authentication.getDetails());
}
public final boolean supports(Class<?> authentication) {
return PreAuthenticatedAuthenticationToken.class.isAssignableFrom(authentication);
}
public void setUserRegistry(UserRegistry userRegistry) {
this.userRegistry = userRegistry;
}
}
The GaeUserAuthentication class is a very simple implementation of Spring Security's Authentication interface, which takes the GaeUser object as the principal.
If you've customized Spring Security a bit before, you might be wondering why we haven't implemented a UserDetailsService at any point here and why the principal isn't a UserDetails instance. The simple answer is that you don't have to — Spring Security doesn't generally mind what the type of the object is and here we've chosen to implement the AuthenticationProvider interface directly as the simplest option.
GAE Datasource User Registry
We now need an implementation of the UserRegistry which uses GAE's datastore.
import com.google.appengine.api.datastore.*;
import org.springframework.security.core.GrantedAuthority;
import samples.gae.security.AppRole;
import java.util.*;
public class GaeDatastoreUserRegistry implements UserRegistry {
private static final String USER_TYPE = "GaeUser";
private static final String USER_FORENAME = "forename";
private static final String USER_SURNAME = "surname";
private static final String USER_NICKNAME = "nickname";
private static final String USER_EMAIL = "email";
private static final String USER_ENABLED = "enabled";
private static final String USER_AUTHORITIES = "authorities";
public GaeUser findUser(String userId) {
Key key = KeyFactory.createKey(USER_TYPE, userId);
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
try {
Entity user = datastore.get(key);
long binaryAuthorities = (Long)user.getProperty(USER_AUTHORITIES);
Set<AppRole> roles = EnumSet.noneOf(AppRole.class);
for (AppRole r : AppRole.values()) {
if ((binaryAuthorities & (1 << r.getBit())) != 0) {
roles.add(r);
}
}
GaeUser gaeUser = new GaeUser(
user.getKey().getName(),
(String)user.getProperty(USER_NICKNAME),
(String)user.getProperty(USER_EMAIL),
(String)user.getProperty(USER_FORENAME),
(String)user.getProperty(USER_SURNAME),
roles,
(Boolean)user.getProperty(USER_ENABLED));
return gaeUser;
} catch (EntityNotFoundException e) {
logger.debug(userId + " not found in datastore");
return null;
}
}
public void registerUser(GaeUser newUser) {
Key key = KeyFactory.createKey(USER_TYPE, newUser.getUserId());
Entity user = new Entity(key);
user.setProperty(USER_EMAIL, newUser.getEmail());
user.setProperty(USER_NICKNAME, newUser.getNickname());
user.setProperty(USER_FORENAME, newUser.getForename());
user.setProperty(USER_SURNAME, newUser.getSurname());
user.setUnindexedProperty(USER_ENABLED, newUser.isEnabled());
Collection<? extends GrantedAuthority> roles = newUser.getAuthorities();
long binaryAuthorities = 0;
for (GrantedAuthority r : roles) {
binaryAuthorities |= 1 << ((AppRole)r).getBit();
}
user.setUnindexedProperty(USER_AUTHORITIES, binaryAuthorities);
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
datastore.put(user);
}
public void removeUser(String userId) {
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Key key = KeyFactory.createKey(USER_TYPE, userId);
datastore.delete(key);
}
}
As, we've already mentioned, the sample uses an enum for the application roles. The roles (authorities) assigned to a user are stored as an EnumSet. EnumSets are very resource efficient and a user's roles can be stored as a single long value, allowing for a simpler interaction with the datastore API. We've assigned a separate "bit" property to each role for this purpose.
User Registration
The user registration controller contains the following method which handles the submission of the registration form.
@Autowired
private UserRegistry registry;
@RequestMapping(method = RequestMethod.POST)
public String register(@Valid RegistrationForm form, BindingResult result) {
if (result.hasErrors()) {
return null;
}
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
GaeUser currentUser = (GaeUser)authentication.getPrincipal();
Set<AppRole> roles = EnumSet.of(AppRole.USER);
if (UserServiceFactory.getUserService().isUserAdmin()) {
roles.add(AppRole.ADMIN);
}
GaeUser user = new GaeUser(currentUser.getUserId(), currentUser.getNickname(), currentUser.getEmail(),
form.getForename(), form.getSurname(), roles, true);
registry.registerUser(user);
// Update the context with the full authentication
SecurityContextHolder.getContext().setAuthentication(new GaeUserAuthentication(user, authentication.getDetails()));
return "redirect:/home.htm";
}
The user is created with the supplied forename and surname and a new set of roles is created. This may also include the "ADMIN" role if GAE indicates that the current user is an administrator for the application. This is then stored in the user registry and the security context is populated with an updated Authentication object to make sure that Spring Security is aware of the new role information and applies its access-control constrainst accordingly.
Final Application Configuration
The security application context now looks like this:
<http use-expressions="true" entry-point-ref="gaeEntryPoint">
<intercept-url pattern="/" access="permitAll" />
<intercept-url pattern="/register.htm*" access="hasRole('NEW_USER')" />
<intercept-url pattern="/**" access="hasRole('USER')" />
<custom-filter position="PRE_AUTH_FILTER" ref="gaeFilter" />
</http>
<b:bean id="gaeEntryPoint" class="samples.gae.security.GoogleAccountsAuthenticationEntryPoint" />
<b:bean id="gaeFilter" class="samples.gae.security.GaeAuthenticationFilter">
<b:property name="authenticationManager" ref="authenticationManager"/>
</b:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="gaeAuthenticationProvider"/>
</authentication-manager>
<b:bean id="gaeAuthenticationProvider" class="samples.gae.security.GoogleAccountsAuthenticationProvider">
<b:property name="userRegistry" ref="userRegistry" />
</b:bean>
<b:bean id="userRegistry" class="samples.gae.users.GaeDatastoreUserRegistry" />
You can see we've inserted our filter using the custom-filter namespace element, declared the provider and user registry and wired them all up. We've also added a URL for the registration controller, which is accessible to new users.
Conclusion
Spring Security has shown over the years that it is flexible enough to add value in many different scenarios and deployment within Google App Engine is no exception. It's also worth remembering that implementing some of the interfaces yourself (as we've done here) is often a better approach than trying to use an existing class that doesn't quite fit. You may end up with a cleaner solution which better matches your requirements.
The focus here has been on how to use the Google App Engine APIs from within a Spring Security-enabled application. We haven't covered all the other details of how the application works, but I'd encourage you to have a look at the code and see for yourself. If you're a GAE expert then suggestions for improvement are always welcome!
The sample code is already in the 3.1 codebase, so you can check it out from our git repository. A first milestone of Spring Security 3.1 should also be released later this month.
Similar Posts
- Spring Security customization (Part 1 – Customizing UserDetails or extending GrantedAuthority)
- Spring Security Kerberos/SPNEGO Extension
- Grails 1.1.1 released with Google AppEngine support
- What's New in Spring Security 2?
- Spring Security Configuration with Scala





Alexey Kakunin says:
Added on August 2nd, 2010 at 8:32 amIt may be interesting Spring-Security-OpenId replacement I've implemented with using Google's step2 library: http://www.emforge.net/web/spring-security-step2
It allowed to use openId registration on GAE (fixing some issues in working with http) as well as use Google Apps accounts for login.
Peter Mularien says:
Added on August 2nd, 2010 at 10:14 pmExcellent article, Luke! I will definitely check it out (as well as taking this subtle reminder to see what you're up to in Spr Sec 3.1). Thanks!
martiner says:
Added on August 6th, 2010 at 1:37 pmThanks for a great article! Could you please provide a guidline how to add a log-out?
Luke Taylor (blog author) says:
Added on August 6th, 2010 at 4:38 pm@martiner There's already logout functionality built into the sample code. One of the controllers provides the logout URL, allowing the app to do anything it wants there, then it redirects to the logout URL generated by the GAE UserService.
Look at the logout method of the GaeAppController class:
@RequestMapping(value = "/logout.htm", method= RequestMethod.GET)
public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException {
request.getSession().invalidate();
String logoutUrl = UserServiceFactory.getUserService().createLogoutURL("/loggedout.htm");
response.sendRedirect(logoutUrl);
}
And the "loggedout" page just displays a message (as you'll see if you try the sample that's running in GAE).
martiner says:
Added on August 7th, 2010 at 8:07 amThanks, I overlooked the logout controller in your sample. Nevertheless logout haven't worked until I excluded /_ah URLs from Spring Security (at least on development server).
Luke Taylor (blog author) says:
Added on August 7th, 2010 at 11:48 amYes, I think that's a slight inconsistency with the development server. Ideally those "ah_" URLs would be handled by the dev server without invoking the filter chain, since in the real app engine the URLs are separate from your application.
Nigel Thomas says:
Added on August 10th, 2010 at 1:22 pmThanks for this and contributing to spring forums, could you please take a look at my security question on spring forums, http://is.gd/ebMqm? Thank you.
Charles Falconer says:
Added on August 17th, 2010 at 5:08 pmThis article was exactly what I was looking for. Only problem is, I was trying to build and run the gae sample in the spring-security git repository but it doesn't contain a pom file – only a gradle file that does not come with a build task.
Would be grateful for any advice on how to build and run the project.
Abu al-Sous says:
Added on August 23rd, 2010 at 9:05 amHi Luke,
This is really a great pattern; nicely done.
As I was testing it I noticed that this approach does not take into account cached principles or authentication objects. For example, try to disable a person by going to the admin section and change the the enabled field to false and the same users continues to log in. I fixed this by retrieving again the GaeUser from the UserRegistry service in GaeAuthenticationFilter.java just before chain.doFilter(request, response) and if the user is not enabled, the code redirects to the friendly disabled page.
Also if you try to login with a valid email, then logoff, and try to login again with a NEW USER; the Authentication object for the previous person still there and the system DOES NOT forwards you to the registration page, this is a major securit. To correct this, In GaeAuthenticationFilter.doFilter() you have to check not only if the authentication object is null but also if gaeUser != googleUser; I've changed the code to look as follows:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
GaeUser gaeUser = authentication!=null?(GaeUser)authentication.getPrincipal():null;
User googleUser = UserServiceFactory.getUserService().getCurrentUser();
if ( (authentication == null || (googleUser != null && gaeUser != null && !gaeUser.getEmail().equals(googleUser.getEmail())) ) && googleUser != null) {
…..
}
}
I hope this helps other.
Luke Taylor (blog author) says:
Added on August 23rd, 2010 at 1:00 pm@Charles The easiest way to work with GAE is through your IDE. So I'd recommend setting up a GAE app directly in Eclipse (or IDEA etc) and adding the code to that directly. That's what I ended up doing for most of the development, though the gradle script should build a war file and an exploded war (run "./gradlew build" from the project root directory).
@Abu Yes, the account disabling isn't intented to work in real-time for logged-in users. You'll find a previous blogarticle by Oleg Zhurakousky on how you can achieve this. Re-loading the user data on every request is probably a bit inefficient.
I can't reproduce the second issue you mention. If you click on the logout link, the first thing that should happen is that the current session is invalidated, so it shouldn't be possible to re-access the same session as a different user. Was this in the deployed app or in the development server?
Luke Taylor (blog author) says:
Added on August 23rd, 2010 at 1:34 pm@Abu Are you talking about the situation where you log out of google apps separately but leave the sample app logged in? In that case you're right that you would still have an active session with the application and your fix is a good idea. I'll add it to the sample code.
marianbonczek says:
Added on September 9th, 2010 at 3:52 pmI've tried to use the \spring-security\samples\gae\ with spring-security 3.1.0.M1 version.
Unfortunatelly, I've got the "This web page has a redirect loop." exception after deploying at gae and clicking Gae servlet link.
Any suggestions? Is the \spring-security\samples\gae\ code working for you with 3.1?
marianbonczek says:
Added on September 10th, 2010 at 4:08 pmYupi, I've removed jstl-1.2.jar from the lib and it is working
, so my last comment is out-of-date.
sai says:
Added on October 23rd, 2010 at 6:28 pmhow to run this application in tomcat?
Chris Hodges says:
Added on October 25th, 2010 at 2:12 amForgive the simplistic question, but after the initial redirect (via the AuthenticationEntryPoint), how will the resulting redirect back from the GAE make it to the GaeAuthenticationFilter? It appears it would again be caught in the AuthenticationEntryPoint ending up in an endless redirect loop…
Luke Taylor (blog author) says:
Added on November 8th, 2010 at 11:00 am@sai
This article is about Google App Engine. The application requires GAE infrastructure, so can't be run in Tomcat.
@Chris
The AuthenticationEntryPoint is injected into Spring Security's ExceptionTranslationFilter and is called when an unauthenticated user attempts to access a protected resource. ExceptionTranslationFilter comes after the authentication filter(s) in the stack, so the request will always enter the GaeAuthenticationFilter first.
l.denardo says:
Added on November 9th, 2010 at 10:41 amI tried the example from the page, and it was a great help.
I think it's worth mentioning that to make it work (Spring Security 3.0.4) GaeUserAuthentication must extend PreAuthenticatedAuthenticationToken, or either AuthenticationProvider must accept also GaeUserAuthentication in its supports(Class ) method.
Otherwise the newly set authentication will be rejected from the provider, and users will be redirected again to the login page (even if they're correctly authenticated from GAE's perspective).
Thank you very much for this sample. I'll ask to link it in the "will it play in AppEngine" page.
Regards
Lorenzo
Juan Carlos González says:
Added on January 14th, 2011 at 7:44 amHi Luke,
Thanks for this post.
I'm a newbie to Spring Security but your post has helped me a lot. I'm trying to implement something like this, but I'd like to include the rememberme functionality. I've been reading reference manual but I can't figure out how I could implement this functionality with the approach in your post. Please, could you give me any hint?.
Please, assume that the user could select a remember me option in the app before being redirected for GAE login.
Best regards,
Juan Carlos
Pankaj says:
Added on January 31st, 2011 at 1:22 pmHi,
I was just trying this example but got the "This webpage has a redirect loop" on chrome. Basically its going in a infinite loop. Any suggestions? I don't have jstl-1.2.jar also to remove as suggested by @marianbonczek.
I am using spring 3.0.2 and spring security 3.0.5. I also had to change to spring-security-3.0.xsd from spring-security-3.1.xsd as it gave me configuration exception as "Configuration problem: You must use a 3.0 schema with Spring Security 3.0.(2.0 or 3.1 versions are not valid) Please update your schema declarations to the 3.0.3 schema (spring-security-3.0.3.xsd)"
can this cause the issue?
Thanks
Pankaj
Pankaj says:
Added on January 31st, 2011 at 2:00 pmHi,
The problem mentioned (infinite loop) happens only in development environment. I uploaded the test app on Google app engine and it seems to be working fine there.
If I exclude the _ah url by adding , development environment also behaves correctly. Got this idea only after uploading it to production environment.
Thanks
Pankaj
Mohit says:
Added on February 7th, 2011 at 11:34 pmHi
I am using the same example. Everything works fine and starts fine but URL is not getting protected. Here is the xml. Am i missing anything.
web.xml
contextConfigLocation
/WEB-INF/security-config.xml
org.springframework.web.context.ContextLoaderListener
authenticationFilter
org.springframework.web.filter.DelegatingFilterProxy
authenticationFilter
/*
security-config.xml
Terran says:
Added on February 17th, 2011 at 11:49 amHow does Google App Engine do with domain object instance level security?
Matias says:
Added on March 21st, 2011 at 2:06 pmGreat post! Thank you.
I just have one question:
Shouldn't the GoogleAccountsAuthenticationProvider add the NEW_USER role to the GaeUser where "// User not in registry. Needs to register" ?
Luke Taylor (blog author) says:
Added on March 21st, 2011 at 5:32 pm@Matias
Glad you liked the article. And yes, you're right that the NEW_USER role is required. However it's added in the constructor for GaeUser. I'd recommend you checkout the code and take a look at it in your IDE.
Matias says:
Added on March 22nd, 2011 at 11:05 am@Luke
Thanks a lot! This makes more sense now.
I'm having one problem in implementing your example, and I've tried for hours to solve it but couldn't find the cause…
My filterchain works as expected, and the GaeAuthenticationFilter gets invoked properly. When I login via GAE, I get redirected to the /register page, and when the filter is invoked then, the Authentication object holds my GaeUser (which in return has the NEW_USER authority properly set).
Still, it ends up in the GoogleAccountsAuthenticationEntryPoint, and gets redirected to the GAE login page.
I have this line in my applicationContext (which is the first line in the http tag):
Any ideas on why this could be?
Thanks in advance!
Matias says:
Added on March 22nd, 2011 at 11:07 amI was afraid this might happen (it would be nice to have some information on if characters get encoded or not).
So here my line in applicationContext:
<intercept-url pattern="/register" access="hasRole('NEW_USER')" />
Luke Taylor (blog author) says:
Added on March 22nd, 2011 at 1:00 pmI'd recommend you start by building and deploying the existing sample code. It is already deployed on GAE and working there. It's difficult to say what is wrong otherwise. If you have problems then please post more information to the Spring Security forum.
Matias says:
Added on March 22nd, 2011 at 1:13 pmI solved the problem. My GaeUserAuthentication had authenticated set to false as default…
Everything works like a charm now.
Thank you so much for this tutorial!
Pascal says:
Added on June 14th, 2011 at 5:33 pmGreate post! Can you maybe give a hint how a GWT-RPC service would be integrated with Spring Security?
Hiren says:
Added on September 3rd, 2011 at 8:32 amHello Luke,
I am trying to run this example but having really hard time with Gradelew.
I was able to manage downloading things using STS Eclipse git repo for 3.1.
But struggle started after that. How to checkout project from GIT. I try to install Gradelew Plugin from STS Deskbord. and try to import sample GAE sample folder by clicking Build Mode. But that tooks anonymous time and keep trying to download things from maven repo. I kept things for whole one day but did not got success. Is there any information any one can share which explain after cloning git repo specific to STS Eclipse.
http://static.springsource.org/spring-security/site/build.html
I have gone through above url but it's hardly help when try to fetch things from maven repo.
I try to download things manually from maven and download speed was 1Mbps. but with this i did not get any success yet. Any one expert can give a little help would be appreciate his/her time.
Thank you,
Hiren
Hiren says:
Added on September 3rd, 2011 at 8:16 pmPlease Avoid above question i found the video guide. Sorry to bother you guys.
http://www.youtube.com/watch?v=lx23i2a5o88
Thank you for distributing knowledge.
Hiren
Hiren says:
Added on September 5th, 2011 at 12:31 pmIf you are facing issue with STS Eclipse not able to update and fail many times while getting extension update. Not opening deskbord extension tab. not able to get data from git repository. not able to build samples with gradles than. You have to check your operating system. If you use any pirated os it will create this many issues. try to run with any free linux os ex. Ubuntu. every thing will work fine.
Hiren
Eduard says:
Added on May 3rd, 2012 at 4:26 pmI too ran into the infinite loop / redirect loop problem when trying out this sample on GAE's Development Server. I have written up what has to be changed to the sources at http://gedankenverlust.blogspot.de/2012/04/getting-spring-security-samples-gae-to.html .
chanu says:
Added on January 17th, 2013 at 7:54 amExcellent article Luke
This is what I was looking for. In addition can u guide me how to configure for only some specific domain services which are offered by google itself (ie abc@xyz.com instead of @gmail.com) which is supported by gmail itself.