SEC-1490: Code for GAE Sample webapp
This commit is contained in:
parent
c1c8fd1874
commit
5d35919ca3
|
@ -4,6 +4,7 @@ target/
|
|||
.project
|
||||
.DS_Store
|
||||
.settings/
|
||||
out/
|
||||
build/
|
||||
*.log
|
||||
*.iml
|
||||
|
@ -11,3 +12,4 @@ build/
|
|||
*.iws
|
||||
.gradle/
|
||||
gradle.properties
|
||||
atlassian-ide-plugin.xml
|
||||
|
|
|
@ -37,6 +37,9 @@ allprojects {
|
|||
if (!config) {
|
||||
return
|
||||
}
|
||||
ideaModule {
|
||||
gradleCacheVariable = 'GRADLE_CACHE'
|
||||
}
|
||||
}
|
||||
|
||||
ideaModule {
|
||||
|
|
|
@ -3,9 +3,11 @@ apply plugin: 'groovy'
|
|||
repositories {
|
||||
mavenRepo name:'localRepo', urls: "file://" + System.properties['user.home'] + "/.m2/repository"
|
||||
mavenCentral()
|
||||
mavenRepo name: 'GAE', urls:'http://maven-gae-plugin.googlecode.com/svn/repository'
|
||||
mavenRepo name:'Shibboleth Repo', urls:'http://shibboleth.internet2.edu/downloads/maven2'
|
||||
}
|
||||
|
||||
// Docbook Plugin
|
||||
dependencies {
|
||||
def fopDeps = [ 'org.apache.xmlgraphics:fop:0.95-1@jar',
|
||||
'org.apache.xmlgraphics:xmlgraphics-commons:1.3',
|
||||
|
@ -26,6 +28,11 @@ dependencies {
|
|||
'net.sf.docbook:docbook-xsl:1.75.2:ns-resources@zip'
|
||||
}
|
||||
|
||||
// GAE
|
||||
dependencies {
|
||||
compile 'com.google.appengine:appengine-tools-api:1.3.5'
|
||||
}
|
||||
|
||||
task ide(type: Copy) {
|
||||
from configurations.runtime
|
||||
into 'ide'
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package gae;
|
||||
|
||||
import com.google.appengine.tools.admin.AppCfg
|
||||
import org.gradle.api.*;
|
||||
|
||||
class GaePlugin implements Plugin<Project> {
|
||||
public void apply(Project project) {
|
||||
if (!project.hasProperty('appEngineSdkRoot')) {
|
||||
println "'appEngineSdkRoot' must be set in gradle.properties"
|
||||
}
|
||||
|
||||
System.setProperty('appengine.sdk.root', project.property('appEngineSdkRoot'))
|
||||
|
||||
File explodedWar = new File(project.buildDir, "gae-exploded")
|
||||
|
||||
project.task('gaeDeploy') << {
|
||||
AppCfg.main("update", explodedWar.toString())
|
||||
}
|
||||
|
||||
project.gaeDeploy.dependsOn project.war
|
||||
|
||||
project.war.doLast {
|
||||
ant.unzip(src: project.war.archivePath, dest: explodedWar)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
implementation-class=gae.GaePlugin
|
|
@ -0,0 +1,40 @@
|
|||
apply plugin: 'war'
|
||||
apply plugin: 'jetty'
|
||||
apply plugin: 'gae'
|
||||
|
||||
gaeVersion="1.3.5"
|
||||
|
||||
repositories {
|
||||
// Hibernate Validator
|
||||
mavenRepo name: 'JBoss', urls: 'https://repository.jboss.org/nexus/content/repositories/releases'
|
||||
// GAE Jars
|
||||
mavenRepo name: 'GAE', urls:'http://maven-gae-plugin.googlecode.com/svn/repository'
|
||||
}
|
||||
|
||||
// Remove logback as it causes security issues with GAE.
|
||||
configurations.runtime.exclude(group: 'ch.qos.logback')
|
||||
|
||||
dependencies {
|
||||
providedCompile 'javax.servlet:servlet-api:2.5@jar',
|
||||
"com.google.appengine:appengine-api-1.0-sdk:$gaeVersion"
|
||||
|
||||
compile project(':spring-security-core'),
|
||||
project(':spring-security-web'),
|
||||
"org.springframework:spring-beans:$springVersion",
|
||||
"org.springframework:spring-web:$springVersion",
|
||||
"org.springframework:spring-webmvc:$springVersion",
|
||||
"org.springframework:spring-context:$springVersion",
|
||||
"org.springframework:spring-context-support:$springVersion",
|
||||
'javax.validation:validation-api:1.0.0.GA',
|
||||
'org.hibernate:hibernate-validator:4.1.0.Final',
|
||||
"org.slf4j:slf4j-api:$slf4jVersion"
|
||||
|
||||
runtime project(':spring-security-config'),
|
||||
"org.slf4j:jcl-over-slf4j:$slf4jVersion",
|
||||
"org.slf4j:slf4j-jdk14:$slf4jVersion"
|
||||
testCompile "com.google.appengine:appengine-testing:$gaeVersion"
|
||||
|
||||
testRuntime "com.google.appengine:appengine-api-labs:$gaeVersion",
|
||||
"com.google.appengine:appengine-api-stubs:$gaeVersion"
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package samples.gae.security;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public enum AppRole implements GrantedAuthority {
|
||||
ADMIN (0),
|
||||
NEW_USER (1),
|
||||
USER (2);
|
||||
|
||||
private int bit;
|
||||
|
||||
/**
|
||||
* Creates an authority with a specific bit representation. It's important that this doesn't
|
||||
* change as it will be used in the database. The enum ordinal is less reliable as the enum may be
|
||||
* reordered or have new roles inserted which would change the ordinal values.
|
||||
*
|
||||
* @param bit the permission bit which will represent this authority in the datastore.
|
||||
*/
|
||||
AppRole(int bit) {
|
||||
this.bit = bit;
|
||||
}
|
||||
|
||||
public int getBit() {
|
||||
return bit;
|
||||
}
|
||||
|
||||
public String getAuthority() {
|
||||
return toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package samples.gae.security;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.google.appengine.api.users.User;
|
||||
import com.google.appengine.api.users.UserServiceFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.filter.GenericFilterBean;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class GaeAuthenticationFilter extends GenericFilterBean {
|
||||
private static final String REGISTRATION_URL = "/register.htm";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
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 googleUser = UserServiceFactory.getUserService().getCurrentUser();
|
||||
|
||||
if (googleUser != null) {
|
||||
logger.debug("Currently logged on to GAE as user " + googleUser);
|
||||
logger.debug("Authenticating to Spring Security");
|
||||
// User has returned after authenticating via GAE. Need to authenticate through Spring Security.
|
||||
PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(googleUser, null);
|
||||
token.setDetails(ads.buildDetails(request));
|
||||
|
||||
try {
|
||||
authentication = authenticationManager.authenticate(token);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
} catch (AuthenticationException e) {
|
||||
failureHandler.onAuthenticationFailure((HttpServletRequest)request, (HttpServletResponse)response, e);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A new user has to register with the app before doing anything else
|
||||
if (authentication != null && authentication.getAuthorities().contains(AppRole.NEW_USER)
|
||||
&& !((HttpServletRequest)request).getRequestURI().endsWith(REGISTRATION_URL)) {
|
||||
logger.debug("New user authenticated. Redirecting to registration page");
|
||||
|
||||
((HttpServletResponse) response).sendRedirect(REGISTRATION_URL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws ServletException {
|
||||
Assert.notNull(authenticationManager, "AuthenticationManager must be set");
|
||||
}
|
||||
|
||||
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
|
||||
this.authenticationManager = authenticationManager;
|
||||
}
|
||||
|
||||
public void setFailureHandler(AuthenticationFailureHandler failureHandler) {
|
||||
this.failureHandler = failureHandler;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package samples.gae.security;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import samples.gae.users.GaeUser;
|
||||
|
||||
/**
|
||||
* Authentication object representing a fully-authenticated user.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class GaeUserAuthentication implements Authentication {
|
||||
private final GaeUser principal;
|
||||
private final Object details;
|
||||
private boolean authenticated;
|
||||
|
||||
public GaeUserAuthentication(GaeUser principal, Object details) {
|
||||
this.principal = principal;
|
||||
this.details = details;
|
||||
authenticated = true;
|
||||
}
|
||||
|
||||
public Collection<GrantedAuthority> getAuthorities() {
|
||||
return new HashSet<GrantedAuthority>(principal.getAuthorities());
|
||||
}
|
||||
|
||||
public Object getCredentials() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Object getDetails() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getPrincipal() {
|
||||
return principal;
|
||||
}
|
||||
|
||||
public boolean isAuthenticated() {
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
public void setAuthenticated(boolean isAuthenticated) {
|
||||
authenticated = isAuthenticated;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return principal.getUserId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GaeUserAuthentication{" +
|
||||
"principal=" + principal +
|
||||
", details=" + details +
|
||||
", authenticated=" + authenticated +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package samples.gae.security;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.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()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package samples.gae.security;
|
||||
|
||||
import com.google.appengine.api.users.User;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceAware;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.DisabledException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
|
||||
import samples.gae.users.GaeUser;
|
||||
import samples.gae.users.UserRegistry;
|
||||
|
||||
/**
|
||||
* A simple authentication provider which interacts with {@code User} returned by the GAE {@code UserService},
|
||||
* and also the local persistent {@code UserRegistry} to build an application user principal.
|
||||
* <p>
|
||||
* If the user has been authenticated through google accounts, it will check if they are already registered
|
||||
* and either load the existing user information or assign them a temporary identity with limited access until they
|
||||
* have registered.
|
||||
* <p>
|
||||
* If the account has been disabled, a {@code DisabledException} will be raised.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class GoogleAccountsAuthenticationProvider implements AuthenticationProvider, MessageSourceAware {
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that this provider only supports PreAuthenticatedAuthenticationToken (sub)classes.
|
||||
*/
|
||||
public final boolean supports(Class<?> authentication) {
|
||||
return PreAuthenticatedAuthenticationToken.class.isAssignableFrom(authentication);
|
||||
}
|
||||
|
||||
public void setUserRegistry(UserRegistry userRegistry) {
|
||||
this.userRegistry = userRegistry;
|
||||
}
|
||||
|
||||
public void setMessageSource(MessageSource messageSource) {
|
||||
this.messages = new MessageSourceAccessor(messageSource);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package samples.gae.users;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.appengine.api.datastore.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import samples.gae.security.AppRole;
|
||||
|
||||
/**
|
||||
* UserRegistry implementation which uses GAE's low-level Datastore APIs.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class GaeDataStoreUserRegistry implements UserRegistry {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
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) {
|
||||
logger.debug("Attempting to create new user " + 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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package samples.gae.users;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import samples.gae.security.AppRole;
|
||||
|
||||
/**
|
||||
* Custom user object for the application.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Pre-registration constructor.
|
||||
*
|
||||
* Assigns the user the "NEW_USER" role only.
|
||||
*/
|
||||
public GaeUser(String userId, String nickname, String email) {
|
||||
this.userId = userId;
|
||||
this.nickname = nickname;
|
||||
this.authorities = EnumSet.of(AppRole.NEW_USER);
|
||||
this.forename = null;
|
||||
this.surname = null;
|
||||
this.email = email;
|
||||
this.enabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-registration constructor
|
||||
*/
|
||||
public GaeUser(String userId, String nickname, String email, String forename, String surname, Set<AppRole> authorities, boolean enabled) {
|
||||
this.userId = userId;
|
||||
this.nickname = nickname;
|
||||
this.email = email;
|
||||
this.authorities = authorities;
|
||||
this.forename = forename;
|
||||
this.surname = surname;
|
||||
this.enabled= enabled;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public String getNickname() {
|
||||
return nickname;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public String getForename() {
|
||||
return forename;
|
||||
}
|
||||
|
||||
public String getSurname() {
|
||||
return surname;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return authorities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GaeUser{" +
|
||||
"userId='" + userId + '\'' +
|
||||
", nickname='" + nickname + '\'' +
|
||||
", forename='" + forename + '\'' +
|
||||
", surname='" + surname + '\'' +
|
||||
", authorities=" + authorities +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package samples.gae.users;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class InMemoryUserRegistry implements UserRegistry {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private Map<String, GaeUser> users = Collections.synchronizedMap(new HashMap<String, GaeUser>());
|
||||
|
||||
public GaeUser findUser(String userId) {
|
||||
return users.get(userId);
|
||||
}
|
||||
|
||||
public void registerUser(GaeUser newUser) {
|
||||
logger.debug("Attempting to create new user " + newUser);
|
||||
|
||||
Assert.state(!users.containsKey(newUser.getUserId()));
|
||||
|
||||
users.put(newUser.getUserId(), newUser);
|
||||
}
|
||||
|
||||
public void removeUser(String userId) {
|
||||
users.remove(userId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package samples.gae.users;
|
||||
|
||||
import com.google.appengine.api.datastore.EntityNotFoundException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Service used to maintain a list of users who are registered with the application.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public interface UserRegistry {
|
||||
|
||||
GaeUser findUser(String userId);
|
||||
|
||||
void registerUser(GaeUser newUser);
|
||||
|
||||
void removeUser(String userId);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package samples.gae.validation;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
@Target( { METHOD, FIELD, ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Constraint(validatedBy = ForenameValidator.class)
|
||||
public @interface Forename {
|
||||
String message() default "{samples.gae.forename}";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package samples.gae.validation;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class ForenameValidator implements ConstraintValidator<Forename, String> {
|
||||
private static final Pattern VALID = Pattern.compile("[\\p{L}'\\-,.]+") ;
|
||||
|
||||
public void initialize(Forename constraintAnnotation) {}
|
||||
|
||||
public boolean isValid(String value, ConstraintValidatorContext context) {
|
||||
return VALID.matcher(value).matches();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package samples.gae.validation;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
@Target( { METHOD, FIELD, ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Constraint(validatedBy = SurnameValidator.class)
|
||||
public @interface Surname {
|
||||
String message() default "{samples.gae.surname}";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package samples.gae.validation;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class SurnameValidator implements ConstraintValidator<Surname, String> {
|
||||
private static final Pattern VALID = Pattern.compile("[\\p{L}'\\-,.]+") ;
|
||||
|
||||
public void initialize(Surname constraintAnnotation) {}
|
||||
|
||||
public boolean isValid(String value, ConstraintValidatorContext context) {
|
||||
return VALID.matcher(value).matches();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package samples.gae.web;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.google.appengine.api.users.UserServiceFactory;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*
|
||||
*/
|
||||
@Controller
|
||||
public class GaeAppController {
|
||||
|
||||
@RequestMapping(value = "/", method= RequestMethod.GET)
|
||||
public String landing() {
|
||||
return "landing";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/home.htm", method= RequestMethod.GET)
|
||||
public String home() {
|
||||
return "home";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/disabled.htm", method= RequestMethod.GET)
|
||||
public String disabled() {
|
||||
return "disabled";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/logout.htm", method= RequestMethod.GET)
|
||||
public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
request.getSession().invalidate();
|
||||
|
||||
String logoutUrl = UserServiceFactory.getUserService().createLogoutURL("/");
|
||||
|
||||
response.sendRedirect(logoutUrl);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/loggedout.htm", method= RequestMethod.GET)
|
||||
public String loggedOut() {
|
||||
return "loggedout";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package samples.gae.web;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.validation.Valid;
|
||||
|
||||
import com.google.appengine.api.users.UserServiceFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import samples.gae.security.AppRole;
|
||||
import samples.gae.security.GaeUserAuthentication;
|
||||
import samples.gae.users.GaeUser;
|
||||
import samples.gae.users.UserRegistry;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping(value="/register.htm")
|
||||
public class RegistrationController {
|
||||
|
||||
@Autowired
|
||||
private UserRegistry registry;
|
||||
|
||||
@RequestMapping(method= RequestMethod.GET)
|
||||
public RegistrationForm registrationForm() {
|
||||
return new RegistrationForm();
|
||||
}
|
||||
|
||||
@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";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package samples.gae.web;
|
||||
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
import samples.gae.validation.Forename;
|
||||
import samples.gae.validation.Surname;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class RegistrationForm {
|
||||
@Forename
|
||||
private String forename;
|
||||
@Surname
|
||||
private String surname;
|
||||
|
||||
public String getForename() {
|
||||
return forename;
|
||||
}
|
||||
|
||||
public void setForename(String forename) {
|
||||
this.forename = forename;
|
||||
}
|
||||
|
||||
public String getSurname() {
|
||||
return surname;
|
||||
}
|
||||
|
||||
public void setSurname(String surname) {
|
||||
this.surname = surname;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
|
||||
<application>gaespringsec</application>
|
||||
<version>1</version>
|
||||
<sessions-enabled>true</sessions-enabled>
|
||||
|
||||
<system-properties>
|
||||
<property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
|
||||
</system-properties>
|
||||
</appengine-web-app>
|
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<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 pattern="/static/**" security="none" />
|
||||
<http pattern="/favicon.ico" security="none" />
|
||||
<http pattern="/_ah/resources**" security="none" />
|
||||
|
||||
<http use-expressions="true" entry-point-ref="gaeEntryPoint">
|
||||
<intercept-url pattern="/" access="permitAll" />
|
||||
<intercept-url pattern="/_ah/login**" access="permitAll" />
|
||||
<intercept-url pattern="/_ah/admin**" access="permitAll" />
|
||||
<intercept-url pattern="/logout.htm" 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:property name="failureHandler">
|
||||
<b:bean class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler">
|
||||
<b:property name="exceptionMappings">
|
||||
<b:map>
|
||||
<b:entry key="org.springframework.security.authentication.DisabledException" value="/disabled.htm" />
|
||||
</b:map>
|
||||
</b:property>
|
||||
</b:bean>
|
||||
</b:property>
|
||||
</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" />
|
||||
|
||||
</b:beans>
|
|
@ -0,0 +1,2 @@
|
|||
samples.gae.forename=Must be a valid forename
|
||||
samples.gae.surname=Must be a valid surname
|
|
@ -0,0 +1,25 @@
|
|||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
|
||||
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
|
||||
|
||||
<!-- Enables JSR-303 -->
|
||||
<mvc:annotation-driven/>
|
||||
|
||||
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
|
||||
|
||||
<context:component-scan base-package="samples.gae"/>
|
||||
<context:annotation-config />
|
||||
|
||||
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
|
||||
<property name="basename" value="messages"/>
|
||||
</bean>
|
||||
|
||||
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
|
||||
<property name="prefix" value="/WEB-INF/jsp/"/>
|
||||
<property name="suffix" value=".jsp"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
|
@ -0,0 +1,16 @@
|
|||
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<%@page session="false" %>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<link rel="stylesheet" href="/static/css/gae.css" type="text/css" />
|
||||
<title>Disabled Account</title></head>
|
||||
<body>
|
||||
<div id="content">
|
||||
<p>Sorry, it looks like your account has been disabled for some reason...</p>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,26 @@
|
|||
<%@ page import="com.google.appengine.api.users.UserServiceFactory" %>
|
||||
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
|
||||
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<link rel="stylesheet" href="/static/css/gae.css" type="text/css" />
|
||||
<title>Home Page</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content">
|
||||
<h3>The Home Page</h3>
|
||||
<p>Welcome back <sec:authentication property="principal.nickname"/>.</p>
|
||||
<p>
|
||||
You can get to this page if you have authenticated and are a registered user.
|
||||
You are registered as
|
||||
<sec:authentication property="principal.forename"/> <sec:authentication property="principal.surname"/>.
|
||||
</p>
|
||||
<p>
|
||||
<a href="/logout.htm">Logout</a>.
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,33 @@
|
|||
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
|
||||
<%@page session="false" %>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<link rel="stylesheet" href="/static/css/gae.css" type="text/css" />
|
||||
<title>Spring Security GAE Sample</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="content">
|
||||
<h3>Spring Security GAE Application</h3>
|
||||
|
||||
<p>
|
||||
This application demonstrates the integration of Spring Security
|
||||
with the services provided by Google App Engine. It shows how to:
|
||||
<ul>
|
||||
<li>Authenticate using Google Accounts.</li>
|
||||
<li>Implement "on–demand" authentication when a user accesses a secured resource.</li>
|
||||
<li>Supplement the information from Google Accounts with application–specific roles.</li>
|
||||
<li>Store user account data in an App Engine datastore using the native API.</li>
|
||||
<li>Setup access-control restrictions based on the roles assigned to users.</li>
|
||||
<li>Disable the accounts of specfic users to prevent access.</li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
Go to the <a href="/home.htm">home page</a>.
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,17 @@
|
|||
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
|
||||
<%@page session="false" %>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<link rel="stylesheet" href="/static/css/gae.css" type="text/css" />
|
||||
<title>Spring Security GAE Sample</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="content">
|
||||
<p>You've been logged out of the application. <a href="/home.htm">Log back in</a>.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,40 @@
|
|||
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
|
||||
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
|
||||
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
|
||||
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<link rel="stylesheet" href="/static/css/gae.css" type="text/css" />
|
||||
<title>Registration</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content">
|
||||
<p>
|
||||
Welcome to the Spring Security GAE sample application, <sec:authentication property="principal.nickname" />.
|
||||
Please enter your registration details in order to use the application.
|
||||
</p>
|
||||
<p>
|
||||
The data you enter here will be registered in the application's GAE data store, keyed under your unique
|
||||
Google Accounts identifier. It doesn't have to be accurate. When you log in again, the information will be automatically
|
||||
retrieved.
|
||||
</p>
|
||||
|
||||
<form:form id="register" method="post" modelAttribute="registrationForm">
|
||||
<fieldset>
|
||||
<form:label path="forename">
|
||||
Forename:
|
||||
</form:label> <form:errors path="forename" cssClass="fieldError" /><br />
|
||||
<form:input path="forename" /> <br />
|
||||
|
||||
<form:label path="surname">
|
||||
Surname:
|
||||
</form:label><form:errors path="surname" cssClass="fieldError" /> <br />
|
||||
<form:input path="surname" /><br />
|
||||
</fieldset>
|
||||
<input type="submit" value="Register">
|
||||
</form:form>
|
||||
</body>
|
||||
</div>
|
||||
</html>
|
|
@ -0,0 +1,4 @@
|
|||
.level = INFO
|
||||
|
||||
org.springframework.level = FINE
|
||||
org.springframework.security.level = FINER
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
|
||||
|
||||
<context-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>
|
||||
/WEB-INF/applicationContext-security.xml
|
||||
</param-value>
|
||||
</context-param>
|
||||
|
||||
<filter>
|
||||
<filter-name>springSecurityFilterChain</filter-name>
|
||||
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>springSecurityFilterChain</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
||||
</listener>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>gae</servlet-name>
|
||||
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
|
||||
<init-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>/WEB-INF/gae-servlet.xml</param-value>
|
||||
</init-param>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>gae</servlet-name>
|
||||
<url-pattern>/</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>gae</servlet-name>
|
||||
<url-pattern>*.htm</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
</web-app>
|
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,26 @@
|
|||
|
||||
body {
|
||||
font-family:"Palatino Linotype","Book Antiqua",Palatino,serif;
|
||||
}
|
||||
|
||||
#content {
|
||||
margin: 5em auto;
|
||||
width: 40em;
|
||||
}
|
||||
|
||||
form {
|
||||
width: 25em;
|
||||
margin: 0 2em;
|
||||
}
|
||||
|
||||
form fieldset {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
fieldset input {
|
||||
margin: 0.6em 0;
|
||||
}
|
||||
|
||||
.fieldError {
|
||||
color: red;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package samples.gae.security;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static samples.gae.security.AppRole.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class AppRoleTests {
|
||||
|
||||
@Test
|
||||
public void getAuthorityReturnsRoleName() {
|
||||
GrantedAuthority admin = ADMIN;
|
||||
|
||||
assertEquals("ADMIN", admin.getAuthority());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package samples.gae.users;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
|
||||
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import samples.gae.security.AppRole;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class GaeDataStoreUserRegistryTests {
|
||||
private final LocalServiceTestHelper helper =
|
||||
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
helper.setUp();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
helper.tearDown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void correctDataIsRetrievedAfterInsert() {
|
||||
GaeDataStoreUserRegistry registry = new GaeDataStoreUserRegistry();
|
||||
|
||||
Set<AppRole> roles = EnumSet.of(AppRole.ADMIN, AppRole.USER);
|
||||
String userId = "someUserId";
|
||||
|
||||
GaeUser origUser = new GaeUser(userId, "nick", "nick@blah.com", "Forename", "Surname", roles, true);
|
||||
|
||||
registry.registerUser(origUser);
|
||||
|
||||
GaeUser loadedUser = registry.findUser(userId);
|
||||
|
||||
assertEquals(loadedUser.getUserId(), origUser.getUserId());
|
||||
assertEquals(true, loadedUser.isEnabled());
|
||||
assertEquals(roles, loadedUser.getAuthorities());
|
||||
assertEquals("nick", loadedUser.getNickname());
|
||||
assertEquals("nick@blah.com", loadedUser.getEmail());
|
||||
assertEquals("Forename", loadedUser.getForename());
|
||||
assertEquals("Surname", loadedUser.getSurname());
|
||||
}
|
||||
}
|
|
@ -14,7 +14,8 @@ def String[] samples = [
|
|||
'tutorial',
|
||||
'contacts',
|
||||
'openid',
|
||||
'aspectj'
|
||||
'aspectj',
|
||||
'gae'
|
||||
]
|
||||
|
||||
def String[] docs = [
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package org.springframework.security.web.authentication.preauth;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
|
@ -10,7 +9,6 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
|
@ -55,7 +53,7 @@ import org.springframework.web.filter.GenericFilterBean;
|
|||
* @since 2.0
|
||||
*/
|
||||
public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFilterBean implements
|
||||
InitializingBean, ApplicationEventPublisherAware {
|
||||
ApplicationEventPublisherAware {
|
||||
|
||||
private ApplicationEventPublisher eventPublisher = null;
|
||||
private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource();
|
||||
|
|
Loading…
Reference in New Issue