diff --git a/.gitignore b/.gitignore index 120746776..cb4a7bc89 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ stacktrace.log /grails-spring-security-core-*.zip /testapps.config.groovy /plugin.xml +.settings \ No newline at end of file diff --git a/application.properties b/application.properties index de5c4a561..e151936c6 100644 --- a/application.properties +++ b/application.properties @@ -1,4 +1 @@ -#Grails Metadata file -#Tue Jul 17 11:29:03 EDT 2012 app.grails.version=2.0.4 -plugins.hibernate=2.0.4 diff --git a/scripts/S2CreatePersistentToken.groovy b/scripts/S2CreatePersistentToken.groovy index 8b4176c63..c6766158b 100644 --- a/scripts/S2CreatePersistentToken.groovy +++ b/scripts/S2CreatePersistentToken.groovy @@ -13,7 +13,7 @@ * limitations under the License. */ -includeTargets << new File("$springSecurityCorePluginDir/scripts/_S2Common.groovy") +includeTargets << new File(springSecurityCorePluginDir, 'scripts/_S2Common.groovy') fullClassName = null @@ -61,16 +61,19 @@ private boolean configure() { private void createDomainClass() { String dir = packageToDir(templateAttributes.packageName) generateFile "$templateDir/PersistentLogin.groovy.template", - "$appDir/domain/${dir}${templateAttributes.className}.groovy" + "$appDir/domain/${dir}${templateAttributes.className}.groovy" } private void updateConfig() { def configFile = new File(appDir, 'conf/Config.groovy') - if (configFile.exists()) { - configFile.withWriterAppend { - it.writeLine "grails.plugins.springsecurity.rememberMe.persistent = true" - it.writeLine "grails.plugins.springsecurity.rememberMe.persistentToken.domainClassName = '$fullClassName'" - } + if (!configFile.exists()) { + return + } + + configFile.withWriterAppend { BufferedWriter writer -> + writer.writeLine "grails.plugin.springsecurity.rememberMe.persistent = true" + writer.writeLine "grails.plugin.springsecurity.rememberMe.persistentToken.domainClassName = '$fullClassName'" + writer.newLine() } } diff --git a/scripts/_S2Common.groovy b/scripts/_S2Common.groovy index 3e1ff533c..3163b7b94 100644 --- a/scripts/_S2Common.groovy +++ b/scripts/_S2Common.groovy @@ -33,7 +33,7 @@ packageToDir = { String packageName -> okToWrite = { String dest -> - def file = new File(dest) + File file = new File(dest) if (overwriteAll || !file.exists()) { return true } diff --git a/src/groovy/grails/plugin/springsecurity/web/authentication/rememberme/GormPersistentTokenRepository.groovy b/src/groovy/grails/plugin/springsecurity/web/authentication/rememberme/GormPersistentTokenRepository.groovy index 7585c306c..531893605 100644 --- a/src/groovy/grails/plugin/springsecurity/web/authentication/rememberme/GormPersistentTokenRepository.groovy +++ b/src/groovy/grails/plugin/springsecurity/web/authentication/rememberme/GormPersistentTokenRepository.groovy @@ -29,7 +29,7 @@ import org.springframework.security.web.authentication.rememberme.PersistentToke */ class GormPersistentTokenRepository implements PersistentTokenRepository { - private final Logger log = LoggerFactory.getLogger(getClass()) + protected final Logger log = LoggerFactory.getLogger(getClass()) /** Dependency injection for grailsApplication */ GrailsApplication grailsApplication @@ -40,13 +40,13 @@ class GormPersistentTokenRepository implements PersistentTokenRepository { * org.springframework.security.web.authentication.rememberme.PersistentRememberMeToken) */ void createNewToken(PersistentRememberMeToken token) { - // join an existing transaction if one is active def clazz = lookupDomainClass() if (!clazz) return + // join an existing transaction if one is active clazz.withTransaction { status -> clazz.newInstance(username: token.username, series: token.series, - token: token.tokenValue, lastUsed: token.date).save() + token: token.tokenValue, lastUsed: token.date).save() } } diff --git a/src/java/grails/plugin/springsecurity/SecurityEventListener.java b/src/java/grails/plugin/springsecurity/SecurityEventListener.java index 96c812487..b3f1878e3 100644 --- a/src/java/grails/plugin/springsecurity/SecurityEventListener.java +++ b/src/java/grails/plugin/springsecurity/SecurityEventListener.java @@ -42,7 +42,7 @@ * All callbacks are optional; you can implement just the ones you're interested in, e.g. *
* grails { - * plugins { + * plugin { * springsecurity { * ... * onAuthenticationSuccessEvent = { e, appCtx -> @@ -59,7 +59,7 @@ */ public class SecurityEventListener implements ApplicationListener, ApplicationContextAware { - private ApplicationContext _applicationContext; + protected ApplicationContext applicationContext; /** * {@inheritDoc} @@ -89,10 +89,10 @@ else if (e instanceof AbstractAuthorizationEvent) { } @SuppressWarnings("rawtypes") - private void call(final ApplicationEvent e, final String closureName) { + protected void call(final ApplicationEvent e, final String closureName) { Object closure = SpringSecurityUtils.getSecurityConfig().get(closureName); if (closure instanceof Closure) { - ((Closure)closure).call(new Object[] { e, _applicationContext }); + ((Closure)closure).call(new Object[] { e, applicationContext }); } } @@ -101,7 +101,7 @@ private void call(final ApplicationEvent e, final String closureName) { * @see org.springframework.context.ApplicationContextAware#setApplicationContext( * org.springframework.context.ApplicationContext) */ - public void setApplicationContext(final ApplicationContext applicationContext) { - _applicationContext = applicationContext; + public void setApplicationContext(final ApplicationContext ctx) { + applicationContext = ctx; } } diff --git a/src/java/grails/plugin/springsecurity/SecurityFilterPosition.java b/src/java/grails/plugin/springsecurity/SecurityFilterPosition.java index 611748ba9..d7866bf4d 100644 --- a/src/java/grails/plugin/springsecurity/SecurityFilterPosition.java +++ b/src/java/grails/plugin/springsecurity/SecurityFilterPosition.java @@ -69,14 +69,15 @@ public enum SecurityFilterPosition { LAST(Integer.MAX_VALUE); private static final int INTERVAL = 100; - private final int _order; + + private final int order; private SecurityFilterPosition() { - _order = ordinal() * INTERVAL; + order = ordinal() * INTERVAL; } - private SecurityFilterPosition(final int order) { - _order = order; + private SecurityFilterPosition(final int filterOrder) { + order = filterOrder; } /** @@ -84,6 +85,6 @@ private SecurityFilterPosition(final int order) { * @return the order */ public int getOrder() { - return _order; + return order; } } diff --git a/src/java/grails/plugin/springsecurity/SpringSecurityUtils.java b/src/java/grails/plugin/springsecurity/SpringSecurityUtils.java index 5a27bf716..a816e641d 100644 --- a/src/java/grails/plugin/springsecurity/SpringSecurityUtils.java +++ b/src/java/grails/plugin/springsecurity/SpringSecurityUtils.java @@ -21,9 +21,6 @@ import groovy.util.ConfigObject; import groovy.util.ConfigSlurper; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -40,12 +37,13 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; +import org.apache.commons.lang.StringEscapeUtils; import org.codehaus.groovy.grails.commons.GrailsApplication; import org.springframework.security.access.hierarchicalroles.RoleHierarchy; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.GrantedAuthorityImpl; +import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserCache; @@ -57,6 +55,8 @@ import org.springframework.security.web.authentication.switchuser.SwitchUserGrantedAuthority; import org.springframework.security.web.context.HttpSessionSecurityContextRepository; import org.springframework.security.web.savedrequest.SavedRequest; +import org.springframework.security.web.util.AnyRequestMatcher; +import org.springframework.security.web.util.RequestMatcher; import org.springframework.util.StringUtils; /** @@ -67,63 +67,27 @@ public final class SpringSecurityUtils { private static ConfigObject _securityConfig; - private static GrailsApplication _application; - private static final Map _context = new HashMap (); - private static final String VOTER_NAMES_KEY = "VOTER_NAMES"; - private static final String PROVIDER_NAMES_KEY = "PROVIDER_NAMES"; - private static final String LOGOUT_HANDLER_NAMES_KEY = "LOGOUT_HANDLER_NAMES"; - private static final String ORDERED_FILTERS_KEY = "ORDERED_FILTERS"; - private static final String CONFIGURED_ORDERED_FILTERS_KEY = "CONFIGURED_ORDERED_FILTERS"; + private static GrailsApplication application; - /** - * Default value for the name of the Ajax header. - */ - public static final String AJAX_HEADER = "X-Requested-With"; + private static List providerNames = new ArrayList (); + private static List logoutHandlerNames = new ArrayList (); + private static List voterNames = new ArrayList (); + private static Map orderedFilters = new HashMap (); + private static SortedMap configuredOrderedFilters = new TreeMap (); - /** - * @deprecated use {@link #getOrderedFilters()} - */ - @SuppressWarnings("unchecked") - @Deprecated - public static final Map ORDERED_FILTERS = - (Map )createDelegate( - ORDERED_FILTERS_KEY, Map.class, HashMap.class); + // HttpSessionRequestCache.SAVED_REQUEST is package-scope + public static final String SAVED_REQUEST = "SPRING_SECURITY_SAVED_REQUEST"; // TODO use requestCache - /** - * @deprecated use {@link #getConfiguredOrderedFilters()} - */ - @SuppressWarnings("unchecked") - @Deprecated - public static final SortedMap CONFIGURED_ORDERED_FILTERS = - (SortedMap )createDelegate( - CONFIGURED_ORDERED_FILTERS_KEY, SortedMap.class, TreeMap.class); + // UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY is deprecated + public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME"; - /** - * @deprecated use {@link #getVoterNames()} - */ - @SuppressWarnings("unchecked") - @Deprecated - public static final List VOTER_NAMES = - (List )createDelegate( - VOTER_NAMES_KEY, List.class, ArrayList.class); - - /** - * @deprecated use {@link #getProviderNames()} - */ - @SuppressWarnings("unchecked") - @Deprecated - public static final List PROVIDER_NAMES = - (List )createDelegate( - PROVIDER_NAMES_KEY, List.class, ArrayList.class); + // AbstractAuthenticationTargetUrlRequestHandler.DEFAULT_TARGET_PARAMETER was removed + public static final String DEFAULT_TARGET_PARAMETER = "spring-security-redirect"; /** - * @deprecated use {@link #getLogoutHandlerNames()} + * Default value for the name of the Ajax header. */ - @SuppressWarnings("unchecked") - @Deprecated - public static final List LOGOUT_HANDLER_NAMES = - (List )createDelegate( - LOGOUT_HANDLER_NAMES_KEY, List.class, ArrayList.class); + public static final String AJAX_HEADER = "X-Requested-With"; /** * Used to ensure that all authenticated users have at least one granted authority to work @@ -138,10 +102,10 @@ private SpringSecurityUtils() { /** * Set at startup by plugin. - * @param application the application + * @param app the application */ - public static void setApplication(GrailsApplication application) { - _application = application; + public static void setApplication(GrailsApplication app) { + application = app; initializeContext(); } @@ -156,8 +120,8 @@ public static Set authoritiesToRoles(final Object authorities) { String authorityName = ((GrantedAuthority)authority).getAuthority(); if (null == authorityName) { throw new IllegalArgumentException( - "Cannot process GrantedAuthority objects which return null from getAuthority() - attempting to process " - + authority); + "Cannot process GrantedAuthority objects which return null " + + "from getAuthority() - attempting to process " + authority); } roles.add(authorityName); } @@ -175,7 +139,7 @@ public static Collection getPrincipalAuthorities() { return Collections.emptyList(); } - Collection authorities = authentication.getAuthorities(); + Collection extends GrantedAuthority> authorities = authentication.getAuthorities(); if (authorities == null) { return Collections.emptyList(); } @@ -201,7 +165,7 @@ public static List parseAuthoritiesString(final String roleNam for (String auth : StringUtils.commaDelimitedListToStringArray(roleNames)) { auth = auth.trim(); if (auth.length() > 0) { - requiredAuthorities.add(new GrantedAuthorityImpl(auth)); + requiredAuthorities.add(new SimpleGrantedAuthority(auth)); } } @@ -227,7 +191,7 @@ public static Set retainAll(final Object granted, final Object required) * @return true
if the user is authenticated and has all the roles */ public static boolean ifAllGranted(final String roles) { - Collectioninferred = findInferredAuthorities(getPrincipalAuthorities()); + Collection extends GrantedAuthority> inferred = findInferredAuthorities(getPrincipalAuthorities()); return inferred.containsAll(parseAuthoritiesString(roles)); } @@ -237,7 +201,7 @@ public static boolean ifAllGranted(final String roles) { * @return true
if the user is authenticated and has none the roles */ public static boolean ifNotGranted(final String roles) { - Collectioninferred = findInferredAuthorities(getPrincipalAuthorities()); + Collection extends GrantedAuthority> inferred = findInferredAuthorities(getPrincipalAuthorities()); Set grantedCopy = retainAll(inferred, parseAuthoritiesString(roles)); return grantedCopy.isEmpty(); } @@ -248,7 +212,7 @@ public static boolean ifNotGranted(final String roles) { * @return true
if the user is authenticated and has any the roles */ public static boolean ifAnyGranted(final String roles) { - Collectioninferred = findInferredAuthorities(getPrincipalAuthorities()); + Collection extends GrantedAuthority> inferred = findInferredAuthorities(getPrincipalAuthorities()); Set grantedCopy = retainAll(inferred, parseAuthoritiesString(roles)); return !grantedCopy.isEmpty(); } @@ -315,9 +279,12 @@ public static boolean isAjax(final HttpServletRequest request) { } // check the SavedRequest's headers - SavedRequest savedRequest = (SavedRequest)request.getSession().getAttribute(WebAttributes.SAVED_REQUEST); - if (savedRequest != null) { - return !savedRequest.getHeaderValues(ajaxHeaderName).isEmpty(); + HttpSession httpSession = SecurityRequestHolder.getRequest().getSession(false); + if (httpSession != null) { + SavedRequest savedRequest = (SavedRequest)httpSession.getAttribute(SAVED_REQUEST); + if (savedRequest != null) { + return !savedRequest.getHeaderValues(ajaxHeaderName).isEmpty(); + } } return false; @@ -331,16 +298,15 @@ public static boolean isAjax(final HttpServletRequest request) { * @param beanName the Spring bean name of the provider */ public static void registerProvider(final String beanName) { - getProviderNames().add(0, beanName); + providerNames.add(0, beanName); } /** * Authentication provider names. Plugins add or remove them, and can be overridden by config. * @return the names */ - @SuppressWarnings("unchecked") - public static synchronized List getProviderNames() { - return (List )getFromContext(PROVIDER_NAMES_KEY); + public static List getProviderNames() { + return providerNames; } /** @@ -351,16 +317,15 @@ public static synchronized List getProviderNames() { * @param beanName the Spring bean name of the handler */ public static void registerLogoutHandler(final String beanName) { - getLogoutHandlerNames().add(0, beanName); + logoutHandlerNames.add(0, beanName); } /** * Logout handler names. Plugins add or remove them, and can be overridden by config. * @return the names */ - @SuppressWarnings("unchecked") - public static synchronized List getLogoutHandlerNames() { - return (List )getFromContext(LOGOUT_HANDLER_NAMES_KEY); + public static List getLogoutHandlerNames() { + return logoutHandlerNames; } /** @@ -371,16 +336,15 @@ public static synchronized List getLogoutHandlerNames() { * @param beanName the Spring bean name of the voter */ public static void registerVoter(final String beanName) { - getVoterNames().add(0, beanName); + voterNames.add(0, beanName); } /** * Voter names. Plugins add or remove them and can be overridden by config. * @return the names */ - @SuppressWarnings("unchecked") public static List getVoterNames() { - return (List )getFromContext(VOTER_NAMES_KEY); + return voterNames; } /** @@ -419,9 +383,8 @@ public static void registerFilter(final String beanName, final int order) { * Ordered filter names. Plugins add or remove them, and can be overridden by config. * @return the names */ - @SuppressWarnings("unchecked") public static Map getOrderedFilters() { - return (Map )getFromContext(ORDERED_FILTERS_KEY); + return orderedFilters; } /** @@ -448,6 +411,7 @@ public static void clientRegisterFilter(final String beanName, final SecurityFil * @param beanName the Spring bean name of the filter * @param order the position (see {@link SecurityFilterPosition}) */ + @SuppressWarnings("deprecation") public static void clientRegisterFilter(final String beanName, final int order) { Filter oldFilter = getConfiguredOrderedFilters().get(order); @@ -460,18 +424,17 @@ public static void clientRegisterFilter(final String beanName, final int order) Filter filter = getBean(beanName); getConfiguredOrderedFilters().put(order, filter); FilterChainProxy filterChain = getBean("springSecurityFilterChain"); - filterChain.setFilterChainMap(Collections.singletonMap( - filterChain.getMatcher().getUniversalMatchPattern(), - new ArrayList (getConfiguredOrderedFilters().values()))); + RequestMatcher rm = new AnyRequestMatcher(); + List filters = new ArrayList (getConfiguredOrderedFilters().values()); + filterChain.setFilterChainMap(Collections.singletonMap(rm, filters)); } /** * Set by SpringSecurityCoreGrailsPlugin; contains the actual filter beans in order. * @return the filters */ - @SuppressWarnings("unchecked") public static SortedMap getConfiguredOrderedFilters() { - return (SortedMap )getFromContext(CONFIGURED_ORDERED_FILTERS_KEY); + return configuredOrderedFilters; } /** @@ -479,7 +442,16 @@ public static SortedMap getConfiguredOrderedFilters() { * @return true
if logged in and switched */ public static boolean isSwitched() { - return ifAllGranted(SwitchUserFilter.ROLE_PREVIOUS_ADMINISTRATOR); + Collection extends GrantedAuthority> inferred = findInferredAuthorities(getPrincipalAuthorities()); + for (GrantedAuthority authority : inferred) { + if (authority instanceof SwitchUserGrantedAuthority) { + return true; + } + if (SwitchUserFilter.ROLE_PREVIOUS_ADMINISTRATOR.equals(authority.getAuthority())) { + return true; + } + } + return false; } /** @@ -537,11 +509,12 @@ public static Object doWithAuth(@SuppressWarnings("rawtypes") final Closure clos boolean set = false; if (SecurityContextHolder.getContext().getAuthentication() == null) { HttpSession httpSession = SecurityRequestHolder.getRequest().getSession(false); - SecurityContext context = null; + SecurityContext securityContext = null; if (httpSession != null) { - context = (SecurityContext)httpSession.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY); - if (context != null) { - SecurityContextHolder.setContext(context); + securityContext = (SecurityContext)httpSession.getAttribute( + HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY); + if (securityContext != null) { + SecurityContextHolder.setContext(securityContext); set = true; } } @@ -584,6 +557,45 @@ public static Object doWithAuth(final String username, @SuppressWarnings("rawtyp } } + public static SecurityContext getSecurityContext(final HttpSession session) { + Object securityContext = session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY); + if (securityContext instanceof SecurityContext) { + return (SecurityContext)securityContext; + } + return null; + } + + /** + * Get the last auth exception. + * @param session the session + * @return the exception + */ + public static Throwable getLastException(final HttpSession session) { + return (Throwable)session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION); + } + + /** + * Get the last attempted username. + * @param session the session + * @return the username + */ + public static String getLastUsername(final HttpSession session) { + String username = (String)session.getAttribute(SPRING_SECURITY_LAST_USERNAME_KEY); + if (username != null) { + username = StringEscapeUtils.unescapeHtml(username); + } + return username; + } + + /** + * Get the saved request from the session. + * @param session the session + * @return the saved request + */ + public static SavedRequest getSavedRequest(final HttpSession session) { + return (SavedRequest)session.getAttribute(SAVED_REQUEST); + } + /** * Merge in a secondary config (provided by a plugin as defaults) into the main config. * @param currentConfig the current configuration @@ -597,7 +609,6 @@ private static void mergeConfig(final ConfigObject currentConfig, final String c secondaryConfig = slurper.parse(classLoader.loadClass(className)); } catch (ClassNotFoundException e) { - // TODO fix this throw new RuntimeException(e); } @@ -626,10 +637,10 @@ private static ConfigObject mergeConfig(final ConfigObject currentConfig, final return config; } - private static CollectionfindInferredAuthorities( + private static Collection extends GrantedAuthority> findInferredAuthorities( final Collection granted) { RoleHierarchy roleHierarchy = getBean("roleHierarchy"); - Collection reachable = roleHierarchy.getReachableGrantedAuthorities(granted); + Collection extends GrantedAuthority> reachable = roleHierarchy.getReachableGrantedAuthorities(granted); if (reachable == null) { return Collections.emptyList(); } @@ -638,28 +649,7 @@ private static Collection findInferredAuthorities( @SuppressWarnings("unchecked") private static T getBean(final String name) { - return (T)_application.getMainContext().getBean(name); - } - - private static Object createDelegate(final String configKey, - Class> interfaceClass, Class> implClass) { - - try { - storeInContext(configKey, implClass.newInstance()); - } - catch (InstantiationException impossible) { - // impossible with regular java.util classes - } - catch (IllegalAccessException impossible) { - // impossible with regular java.util classes - } - - return Proxy.newProxyInstance(implClass.getClassLoader(), - new Class[] { interfaceClass }, new InvocationHandler() { - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - return method.invoke(getFromContext(configKey), args); - } - }); + return (T)application.getMainContext().getBean(name); } /** @@ -667,30 +657,23 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl * to default values when running integration and functional tests together. */ private static void initializeContext() { - getVoterNames().clear(); - getVoterNames().add("authenticatedVoter"); - getVoterNames().add("roleVoter"); - getVoterNames().add("webExpressionVoter"); - - getLogoutHandlerNames().clear(); - getLogoutHandlerNames().add("rememberMeServices"); - getLogoutHandlerNames().add("securityContextLogoutHandler"); + voterNames.clear(); + voterNames.add("authenticatedVoter"); + voterNames.add("roleVoter"); + voterNames.add("webExpressionVoter"); + voterNames.add("closureVoter"); - getProviderNames().clear(); - getProviderNames().add("daoAuthenticationProvider"); - getProviderNames().add("anonymousAuthenticationProvider"); - getProviderNames().add("rememberMeAuthenticationProvider"); + logoutHandlerNames.clear(); + logoutHandlerNames.add("rememberMeServices"); + logoutHandlerNames.add("securityContextLogoutHandler"); - getOrderedFilters().clear(); + providerNames.clear(); + providerNames.add("daoAuthenticationProvider"); + providerNames.add("anonymousAuthenticationProvider"); + providerNames.add("rememberMeAuthenticationProvider"); - getConfiguredOrderedFilters().clear(); - } - - private static Object getFromContext(String key) { - return _context.get(key); - } + orderedFilters.clear(); - private static void storeInContext(String key, Object value) { - _context.put(key, value); + configuredOrderedFilters.clear(); } } diff --git a/src/java/grails/plugin/springsecurity/access/vote/AuthenticatedVetoableDecisionManager.java b/src/java/grails/plugin/springsecurity/access/vote/AuthenticatedVetoableDecisionManager.java index 799a9c473..e50a094a5 100644 --- a/src/java/grails/plugin/springsecurity/access/vote/AuthenticatedVetoableDecisionManager.java +++ b/src/java/grails/plugin/springsecurity/access/vote/AuthenticatedVetoableDecisionManager.java @@ -25,12 +25,12 @@ import org.springframework.security.core.Authentication; /** -* Uses the affirmative-based logic for roles, i.e. any in the list will grant access, but allows -* an authenticated voter to 'veto' access. This allows specification of roles and -* IS_AUTHENTICATED_FULLY
on one line in SecurityConfig.groovy. -* + * Uses the affirmative-based logic for roles, i.e. any in the list will grant access, but allows + * an authenticated voter to 'veto' access. This allows specification of roles and + *IS_AUTHENTICATED_FULLY
on one line in SecurityConfig.groovy. + * * @author Burt Beckwith -*/ + */ public class AuthenticatedVetoableDecisionManager extends AbstractAccessDecisionManager { /** @@ -53,7 +53,8 @@ public void decide(final Authentication authentication, final Object object, fin * throw an exception; if any grant, returntrue
; * otherwise returnfalse
if all abstain. */ - private boolean checkAuthenticatedVoters(final Authentication authentication, final Object object, + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected boolean checkAuthenticatedVoters(final Authentication authentication, final Object object, final CollectionconfigAttributes) { boolean grant = false; @@ -80,7 +81,8 @@ private boolean checkAuthenticatedVoters(final Authentication authentication, fi * return true. If any voter denies, throw exception. Otherwise return false
* to indicate that all abstained. */ - private boolean checkOtherVoters(Authentication authentication, Object object, CollectionconfigAttributes) { + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected boolean checkOtherVoters(Authentication authentication, Object object, Collection configAttributes) { int denyCount = 0; for (AccessDecisionVoter voter : getDecisionVoters()) { if (voter instanceof AuthenticatedVoter) { @@ -107,7 +109,7 @@ private boolean checkOtherVoters(Authentication authentication, Object object, C return false; } - private void deny() { + protected void deny() { throw new AccessDeniedException(messages.getMessage( "AbstractAccessDecisionManager.accessDenied", "Access is denied")); diff --git a/src/java/grails/plugin/springsecurity/authentication/encoding/DigestAuthPasswordEncoder.java b/src/java/grails/plugin/springsecurity/authentication/encoding/DigestAuthPasswordEncoder.java index dfe771d93..405c1f807 100644 --- a/src/java/grails/plugin/springsecurity/authentication/encoding/DigestAuthPasswordEncoder.java +++ b/src/java/grails/plugin/springsecurity/authentication/encoding/DigestAuthPasswordEncoder.java @@ -18,8 +18,7 @@ import java.security.NoSuchAlgorithmException; import org.springframework.beans.factory.InitializingBean; -import org.springframework.security.authentication.encoding.PasswordEncoder; -import org.springframework.security.core.codec.Hex; +import org.springframework.security.crypto.codec.Hex; import org.springframework.util.Assert; /** @@ -34,9 +33,10 @@ * * @author Burt Beckwith */ -public class DigestAuthPasswordEncoder implements PasswordEncoder, InitializingBean { +@SuppressWarnings("deprecation") +public class DigestAuthPasswordEncoder implements org.springframework.security.authentication.encoding.PasswordEncoder, InitializingBean { - private String _realm; + protected String realm; /** * {@inheritDoc} @@ -46,7 +46,7 @@ public class DigestAuthPasswordEncoder implements PasswordEncoder, InitializingB public String encodePassword(final String rawPass, final Object salt) { Assert.notNull(salt, "Salt is required and must be the username"); String username = salt.toString(); - return md5Hex(username + ":" + _realm + ":" + rawPass); + return md5Hex(username + ":" + realm + ":" + rawPass); } /** @@ -62,10 +62,10 @@ public boolean isPasswordValid(final String encPass, final String rawPass, final /** * Dependency injection for the realm name. * - * @param realm the name + * @param name the name */ - public void setRealm(final String realm) { - _realm = realm; + public void setRealm(final String name) { + realm = name; } /** @@ -73,10 +73,10 @@ public void setRealm(final String realm) { * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ public void afterPropertiesSet() { - Assert.hasLength(_realm, "realm is required"); + Assert.hasLength(realm, "realm is required"); } - private String md5Hex(final String s) { + protected String md5Hex(final String s) { MessageDigest digest; try { digest = MessageDigest.getInstance("MD5"); diff --git a/src/java/grails/plugin/springsecurity/userdetails/DefaultPostAuthenticationChecks.java b/src/java/grails/plugin/springsecurity/userdetails/DefaultPostAuthenticationChecks.java index ac83bc189..8c911350c 100644 --- a/src/java/grails/plugin/springsecurity/userdetails/DefaultPostAuthenticationChecks.java +++ b/src/java/grails/plugin/springsecurity/userdetails/DefaultPostAuthenticationChecks.java @@ -39,7 +39,7 @@ public void check(UserDetails user) { throw new CredentialsExpiredException(messages.getMessage( "AbstractUserDetailsAuthenticationProvider.credentialsExpired", - "User credentials have expired"), user); + "User credentials have expired")); } } } diff --git a/src/java/grails/plugin/springsecurity/userdetails/DefaultPreAuthenticationChecks.java b/src/java/grails/plugin/springsecurity/userdetails/DefaultPreAuthenticationChecks.java index 8f8bcd787..20a5e97bd 100644 --- a/src/java/grails/plugin/springsecurity/userdetails/DefaultPreAuthenticationChecks.java +++ b/src/java/grails/plugin/springsecurity/userdetails/DefaultPreAuthenticationChecks.java @@ -40,21 +40,21 @@ public void check(UserDetails user) { log.debug("User account is locked"); throw new LockedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked", - "User account is locked"), user); + "User account is locked")); } if (!user.isEnabled()) { log.debug("User account is disabled"); throw new DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled", - "User is disabled"), user); + "User is disabled")); } if (!user.isAccountNonExpired()) { log.debug("User account is expired"); throw new AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired", - "User account has expired"), user); + "User account has expired")); } } } diff --git a/src/java/grails/plugin/springsecurity/web/access/AjaxAwareAccessDeniedHandler.java b/src/java/grails/plugin/springsecurity/web/access/AjaxAwareAccessDeniedHandler.java index a9e246d4d..00c14231b 100644 --- a/src/java/grails/plugin/springsecurity/web/access/AjaxAwareAccessDeniedHandler.java +++ b/src/java/grails/plugin/springsecurity/web/access/AjaxAwareAccessDeniedHandler.java @@ -30,7 +30,7 @@ import org.springframework.security.web.PortResolver; import org.springframework.security.web.WebAttributes; import org.springframework.security.web.access.AccessDeniedHandler; -import org.springframework.security.web.savedrequest.DefaultSavedRequest; +import org.springframework.security.web.savedrequest.RequestCache; import org.springframework.util.Assert; /** @@ -38,10 +38,11 @@ */ public class AjaxAwareAccessDeniedHandler implements AccessDeniedHandler, InitializingBean { - private String errorPage; - private String ajaxErrorPage; - private PortResolver portResolver; - private AuthenticationTrustResolver authenticationTrustResolver; + protected String errorPage; + protected String ajaxErrorPage; + protected PortResolver portResolver; + protected AuthenticationTrustResolver authenticationTrustResolver; + protected RequestCache requestCache; /** * {@inheritDoc} @@ -54,8 +55,8 @@ public void handle(final HttpServletRequest request, final HttpServletResponse r if (e != null && isLoggedIn() && authenticationTrustResolver.isRememberMe(getAuthentication())) { // user has a cookie but is getting bounced because of IS_AUTHENTICATED_FULLY, - // so Acegi won't save the original request - request.getSession().setAttribute(WebAttributes.SAVED_REQUEST, new DefaultSavedRequest(request, portResolver)); + // so Spring Security won't save the original request + requestCache.saveRequest(request, response); } if (response.isCommitted()) { @@ -93,12 +94,12 @@ else if (errorPage != null) { response.sendRedirect(response.encodeRedirectURL(redirectUrl)); } - private Authentication getAuthentication() { + protected Authentication getAuthentication() { return SecurityContextHolder.getContext() == null ? null : SecurityContextHolder.getContext().getAuthentication(); } - private boolean isLoggedIn() { + protected boolean isLoggedIn() { Authentication authentication = getAuthentication(); if (authentication == null) { return false; @@ -140,6 +141,14 @@ public void setAuthenticationTrustResolver(final AuthenticationTrustResolver res authenticationTrustResolver = resolver; } + /** + * Dependency injection for the request cache. + * @param cache the cache + */ + public void setRequestCache(RequestCache cache) { + requestCache = cache; + } + /** * {@inheritDoc} * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() @@ -147,5 +156,6 @@ public void setAuthenticationTrustResolver(final AuthenticationTrustResolver res public void afterPropertiesSet() { Assert.notNull(portResolver, "portResolver is required"); Assert.notNull(authenticationTrustResolver, "authenticationTrustResolver is required"); + Assert.notNull(requestCache, "requestCache is required"); } } diff --git a/src/java/grails/plugin/springsecurity/web/access/GrailsWebInvocationPrivilegeEvaluator.java b/src/java/grails/plugin/springsecurity/web/access/GrailsWebInvocationPrivilegeEvaluator.java index 86e7e3e08..40a3113c1 100644 --- a/src/java/grails/plugin/springsecurity/web/access/GrailsWebInvocationPrivilegeEvaluator.java +++ b/src/java/grails/plugin/springsecurity/web/access/GrailsWebInvocationPrivilegeEvaluator.java @@ -32,6 +32,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.intercept.AbstractSecurityInterceptor; @@ -49,23 +51,25 @@ */ public class GrailsWebInvocationPrivilegeEvaluator extends DefaultWebInvocationPrivilegeEvaluator { - private static final FilterChain DUMMY_CHAIN = new FilterChain() { + protected static final FilterChain DUMMY_CHAIN = new FilterChain() { public void doFilter(ServletRequest req, ServletResponse res) throws IOException, ServletException { throw new UnsupportedOperationException("GrailsWebInvocationPrivilegeEvaluator does not support filter chains"); } }; - private static final HttpServletResponse DUMMY_RESPONSE = DummyResponseCreator.createInstance(); + protected static final HttpServletResponse DUMMY_RESPONSE = DummyResponseCreator.createInstance(); - private AbstractSecurityInterceptor _interceptor; + protected final Logger log = LoggerFactory.getLogger(getClass()); + + protected AbstractSecurityInterceptor interceptor; /** * Constructor. - * @param interceptor the security interceptor + * @param securityInterceptor the security interceptor */ - public GrailsWebInvocationPrivilegeEvaluator(final AbstractSecurityInterceptor interceptor) { - super(interceptor); - _interceptor = interceptor; + public GrailsWebInvocationPrivilegeEvaluator(final AbstractSecurityInterceptor securityInterceptor) { + super(securityInterceptor); + interceptor = securityInterceptor; } @Override @@ -78,9 +82,9 @@ public boolean isAllowed(String contextPath, final String uri, final String meth FilterInvocation fi = createFilterInvocation(contextPath, uri, method); - Collection attrs = _interceptor.obtainSecurityMetadataSource().getAttributes(fi); + Collection attrs = interceptor.obtainSecurityMetadataSource().getAttributes(fi); if (attrs == null) { - return !_interceptor.isRejectPublicInvocations(); + return !interceptor.isRejectPublicInvocations(); } if (authentication == null) { @@ -88,13 +92,13 @@ public boolean isAllowed(String contextPath, final String uri, final String meth } try { - _interceptor.getAccessDecisionManager().decide(authentication, fi, attrs); + interceptor.getAccessDecisionManager().decide(authentication, fi, attrs); return true; } catch (AccessDeniedException unauthorized) { - if (logger.isDebugEnabled()) { + if (log.isDebugEnabled()) { GrailsUtil.deepSanitize(unauthorized); - logger.debug(fi + " denied for " + authentication, unauthorized); + log.debug(fi + " denied for " + authentication, unauthorized); } return false; } @@ -107,7 +111,7 @@ protected FilterInvocation createFilterInvocation(final String contextPath, fina } } -class DummyRequestCreator { //implements HttpServletRequest { +class DummyRequestCreator { static HttpServletRequest createInstance(final String contextPath, final String httpMethod, final String requestURI) { final Map attributes = new HashMap (); diff --git a/src/java/grails/plugin/springsecurity/web/access/channel/HeaderCheckInsecureChannelProcessor.java b/src/java/grails/plugin/springsecurity/web/access/channel/HeaderCheckInsecureChannelProcessor.java index f058bdb58..565239591 100644 --- a/src/java/grails/plugin/springsecurity/web/access/channel/HeaderCheckInsecureChannelProcessor.java +++ b/src/java/grails/plugin/springsecurity/web/access/channel/HeaderCheckInsecureChannelProcessor.java @@ -29,8 +29,8 @@ */ public class HeaderCheckInsecureChannelProcessor extends InsecureChannelProcessor { - private String headerName; - private String headerValue; + protected String headerName; + protected String headerValue; @Override public void decide(FilterInvocation invocation, Collection config) diff --git a/src/java/grails/plugin/springsecurity/web/access/channel/HeaderCheckSecureChannelProcessor.java b/src/java/grails/plugin/springsecurity/web/access/channel/HeaderCheckSecureChannelProcessor.java index d9aa6ac06..acc191f16 100644 --- a/src/java/grails/plugin/springsecurity/web/access/channel/HeaderCheckSecureChannelProcessor.java +++ b/src/java/grails/plugin/springsecurity/web/access/channel/HeaderCheckSecureChannelProcessor.java @@ -29,8 +29,8 @@ */ public class HeaderCheckSecureChannelProcessor extends SecureChannelProcessor { - private String headerName; - private String headerValue; + protected String headerName; + protected String headerValue; @Override public void decide(FilterInvocation invocation, Collection config) diff --git a/src/java/grails/plugin/springsecurity/web/access/expression/WebExpressionConfigAttribute.java b/src/java/grails/plugin/springsecurity/web/access/expression/WebExpressionConfigAttribute.java index ee6b82596..75df7c0a1 100644 --- a/src/java/grails/plugin/springsecurity/web/access/expression/WebExpressionConfigAttribute.java +++ b/src/java/grails/plugin/springsecurity/web/access/expression/WebExpressionConfigAttribute.java @@ -26,16 +26,16 @@ */ public class WebExpressionConfigAttribute implements ConfigAttribute { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1; - private final Expression _authorizeExpression; + protected final Expression expression; /** * Constructor. * @param authorizeExpression the expression */ public WebExpressionConfigAttribute(final Expression authorizeExpression) { - _authorizeExpression = authorizeExpression; + expression = authorizeExpression; } /** @@ -43,7 +43,7 @@ public WebExpressionConfigAttribute(final Expression authorizeExpression) { * @return the expression */ public Expression getAuthorizeExpression() { - return _authorizeExpression; + return expression; } /** @@ -56,6 +56,6 @@ public String getAttribute() { @Override public String toString() { - return _authorizeExpression.getExpressionString(); + return expression.getExpressionString(); } } diff --git a/src/java/grails/plugin/springsecurity/web/access/expression/WebExpressionVoter.java b/src/java/grails/plugin/springsecurity/web/access/expression/WebExpressionVoter.java index a88fb8afb..7724503f8 100644 --- a/src/java/grails/plugin/springsecurity/web/access/expression/WebExpressionVoter.java +++ b/src/java/grails/plugin/springsecurity/web/access/expression/WebExpressionVoter.java @@ -20,31 +20,25 @@ import org.springframework.security.access.AccessDecisionVoter; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.expression.ExpressionUtils; +import org.springframework.security.access.expression.SecurityExpressionHandler; import org.springframework.security.core.Authentication; import org.springframework.security.web.FilterInvocation; -import org.springframework.security.web.access.expression.WebSecurityExpressionHandler; import org.springframework.util.Assert; /** * Based on the class of the same name in Spring Security which uses the * package-default WebExpressionConfigAttribute. * + * @author Luke Taylor * @author Burt Beckwith */ -public class WebExpressionVoter implements AccessDecisionVoter { +public class WebExpressionVoter implements AccessDecisionVoter { - private WebSecurityExpressionHandler _expressionHandler; - - /** - * {@inheritDoc} - * @see org.springframework.security.access.AccessDecisionVoter#vote( - * org.springframework.security.core.Authentication, java.lang.Object, java.util.Collection) - */ - public int vote(final Authentication authentication, final Object object, - final Collection attributes) { + protected SecurityExpressionHandler expressionHandler; + public int vote(Authentication authentication, FilterInvocation fi, Collection attributes) { Assert.notNull(authentication, "authentication cannot be null"); - Assert.notNull(object, "object cannot be null"); + Assert.notNull(fi, "object cannot be null"); Assert.notNull(attributes, "attributes cannot be null"); WebExpressionConfigAttribute weca = findConfigAttribute(attributes); @@ -52,14 +46,12 @@ public int vote(final Authentication authentication, final Object object, return ACCESS_ABSTAIN; } - FilterInvocation fi = (FilterInvocation)object; - EvaluationContext ctx = _expressionHandler.createEvaluationContext(authentication, fi); + EvaluationContext ctx = expressionHandler.createEvaluationContext(authentication, fi); - return ExpressionUtils.evaluateAsBoolean(weca.getAuthorizeExpression(), ctx) ? - ACCESS_GRANTED : ACCESS_DENIED; + return ExpressionUtils.evaluateAsBoolean(weca.getAuthorizeExpression(), ctx) ? ACCESS_GRANTED : ACCESS_DENIED; } - private WebExpressionConfigAttribute findConfigAttribute(final Collection attributes) { + protected WebExpressionConfigAttribute findConfigAttribute(Collection attributes) { for (ConfigAttribute attribute : attributes) { if (attribute instanceof WebExpressionConfigAttribute) { return (WebExpressionConfigAttribute)attribute; @@ -68,28 +60,19 @@ private WebExpressionConfigAttribute findConfigAttribute(final Collection clazz) { return clazz.isAssignableFrom(FilterInvocation.class); } /** * Dependency injection for the expression handler. - * @param expressionHandler the handler + * @param handler the handler */ - public void setExpressionHandler(final WebSecurityExpressionHandler expressionHandler) { - _expressionHandler = expressionHandler; + public void setExpressionHandler(SecurityExpressionHandler handler) { + expressionHandler = handler; } } diff --git a/src/java/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationEntryPoint.java b/src/java/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationEntryPoint.java index 1eba72cec..33ec8c141 100644 --- a/src/java/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationEntryPoint.java +++ b/src/java/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationEntryPoint.java @@ -28,7 +28,15 @@ */ public class AjaxAwareAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint { - private String ajaxLoginFormUrl; + protected String ajaxLoginFormUrl; + + /** + * @param loginFormUrl URL where the login page can be found. Should either be relative to the web-app context path + * (include a leading {@code /}) or an absolute URL. + */ + public AjaxAwareAuthenticationEntryPoint(String loginFormUrl) { + super(loginFormUrl); + } @Override protected String determineUrlToUseForThisRequest(final HttpServletRequest request, diff --git a/src/java/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationFailureHandler.java b/src/java/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationFailureHandler.java index 414e1280e..a5d4df84f 100644 --- a/src/java/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationFailureHandler.java +++ b/src/java/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationFailureHandler.java @@ -34,7 +34,7 @@ */ public class AjaxAwareAuthenticationFailureHandler extends ExceptionMappingAuthenticationFailureHandler implements InitializingBean { - private String _ajaxAuthenticationFailureUrl; + protected String ajaxAuthenticationFailureUrl; /** * {@inheritDoc} @@ -48,7 +48,7 @@ public void onAuthenticationFailure(final HttpServletRequest request, final Http if (SpringSecurityUtils.isAjax(request)) { saveException(request, exception); - getRedirectStrategy().sendRedirect(request, response, _ajaxAuthenticationFailureUrl); + getRedirectStrategy().sendRedirect(request, response, ajaxAuthenticationFailureUrl); } else { super.onAuthenticationFailure(request, response, exception); @@ -60,7 +60,7 @@ public void onAuthenticationFailure(final HttpServletRequest request, final Http * @param url the url */ public void setAjaxAuthenticationFailureUrl(final String url) { - _ajaxAuthenticationFailureUrl = url; + ajaxAuthenticationFailureUrl = url; } /** @@ -68,6 +68,6 @@ public void setAjaxAuthenticationFailureUrl(final String url) { * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ public void afterPropertiesSet() { - Assert.notNull(_ajaxAuthenticationFailureUrl, "ajaxAuthenticationFailureUrl is required"); + Assert.notNull(ajaxAuthenticationFailureUrl, "ajaxAuthenticationFailureUrl is required"); } } diff --git a/src/java/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationSuccessHandler.java b/src/java/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationSuccessHandler.java index 6b8d202f9..c9a91a9b6 100644 --- a/src/java/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationSuccessHandler.java +++ b/src/java/grails/plugin/springsecurity/web/authentication/AjaxAwareAuthenticationSuccessHandler.java @@ -31,8 +31,8 @@ */ public class AjaxAwareAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { - private String _ajaxSuccessUrl; - private RequestCache _requestCache; + protected String ajaxSuccessUrl; + protected RequestCache requestCache; /** * {@inheritDoc} @@ -42,17 +42,17 @@ public class AjaxAwareAuthenticationSuccessHandler extends SavedRequestAwareAuth @Override protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response) { if (SpringSecurityUtils.isAjax(request)) { - return _ajaxSuccessUrl; + return ajaxSuccessUrl; } return super.determineTargetUrl(request, response); } /** * Dependency injection for the Ajax success url, e.g. '/login/ajaxSuccess' - * @param ajaxSuccessUrl the url + * @param url the url */ - public void setAjaxSuccessUrl(final String ajaxSuccessUrl) { - _ajaxSuccessUrl = ajaxSuccessUrl; + public void setAjaxSuccessUrl(final String url) { + ajaxSuccessUrl = url; } /** @@ -64,9 +64,13 @@ public void setAjaxSuccessUrl(final String ajaxSuccessUrl) { @Override public void onAuthenticationSuccess(final HttpServletRequest request, final HttpServletResponse response, final Authentication authentication) throws ServletException, IOException { - super.onAuthenticationSuccess(request, response, authentication); - // always remove the saved request - _requestCache.removeRequest(request, response); + try { + super.onAuthenticationSuccess(request, response, authentication); + } + finally { + // always remove the saved request + requestCache.removeRequest(request, response); + } } /** @@ -75,8 +79,8 @@ public void onAuthenticationSuccess(final HttpServletRequest request, final Http * org.springframework.security.web.savedrequest.RequestCache) */ @Override - public void setRequestCache(RequestCache requestCache) { - super.setRequestCache(requestCache); - _requestCache = requestCache; + public void setRequestCache(RequestCache cache) { + super.setRequestCache(cache); + requestCache = cache; } } diff --git a/src/java/grails/plugin/springsecurity/web/authentication/NullLogoutHandlerRememberMeServices.java b/src/java/grails/plugin/springsecurity/web/authentication/NullLogoutHandlerRememberMeServices.java index 6b591bb01..386262dff 100644 --- a/src/java/grails/plugin/springsecurity/web/authentication/NullLogoutHandlerRememberMeServices.java +++ b/src/java/grails/plugin/springsecurity/web/authentication/NullLogoutHandlerRememberMeServices.java @@ -28,10 +28,10 @@ public class NullLogoutHandlerRememberMeServices extends NullRememberMeServices /** * {@inheritDoc} - * @see org.springframework.security.web.authentication.logout.LogoutHandler#logout(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.core.Authentication) + * @see org.springframework.security.web.authentication.logout.LogoutHandler#logout( + * javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.core.Authentication) */ - public void logout(final HttpServletRequest request, final HttpServletResponse response, - final Authentication authentication) { + public void logout(final HttpServletRequest req, final HttpServletResponse res, final Authentication a) { // no-op } } diff --git a/src/java/grails/plugin/springsecurity/web/authentication/RequestHolderAuthenticationFilter.java b/src/java/grails/plugin/springsecurity/web/authentication/RequestHolderAuthenticationFilter.java index ebd292ec7..0a34ea833 100644 --- a/src/java/grails/plugin/springsecurity/web/authentication/RequestHolderAuthenticationFilter.java +++ b/src/java/grails/plugin/springsecurity/web/authentication/RequestHolderAuthenticationFilter.java @@ -14,6 +14,7 @@ */ package grails.plugin.springsecurity.web.authentication; +import grails.plugin.springsecurity.SpringSecurityUtils; import grails.plugin.springsecurity.web.SecurityRequestHolder; import java.io.IOException; @@ -24,8 +25,12 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.util.Assert; /** * Extends the default {@link UsernamePasswordAuthenticationFilter} to store the request @@ -35,6 +40,8 @@ */ public class RequestHolderAuthenticationFilter extends UsernamePasswordAuthenticationFilter { + protected Boolean storeLastUsername; + @Override public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { SecurityRequestHolder.set((HttpServletRequest)request, (HttpServletResponse)response); @@ -45,4 +52,37 @@ public void doFilter(final ServletRequest request, final ServletResponse respons SecurityRequestHolder.reset(); } } + + @Override + public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { + + if (storeLastUsername) { + // Place the last username attempted into HttpSession for views + HttpSession session = request.getSession(false); + if (session != null || getAllowSessionCreation()) { + String username = obtainUsername(request); + if (username == null) { + username = ""; + } + username = username.trim(); + session.setAttribute(SpringSecurityUtils.SPRING_SECURITY_LAST_USERNAME_KEY, username); // TODO doc that not escaped now + } + } + + return super.attemptAuthentication(request, response); + } + + /** + * Whether to store the last attempted username in the session. + * @param storeLastUsername store if true + */ + public void setStoreLastUsername(Boolean storeLastUsername) { + this.storeLastUsername = storeLastUsername; + } + + @Override + public void afterPropertiesSet() { + super.afterPropertiesSet(); + Assert.notNull(storeLastUsername, "storeLastUsername must be set"); + } } diff --git a/src/java/grails/plugin/springsecurity/web/authentication/logout/MutableLogoutFilter.java b/src/java/grails/plugin/springsecurity/web/authentication/logout/MutableLogoutFilter.java index 2ca7cc04e..cc1c8541b 100644 --- a/src/java/grails/plugin/springsecurity/web/authentication/logout/MutableLogoutFilter.java +++ b/src/java/grails/plugin/springsecurity/web/authentication/logout/MutableLogoutFilter.java @@ -24,6 +24,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.logout.LogoutFilter; @@ -35,17 +37,18 @@ */ public class MutableLogoutFilter extends LogoutFilter { - private final LogoutSuccessHandler _logoutSuccessHandler; + protected final LogoutSuccessHandler logoutSuccessHandler; + protected final Logger log = LoggerFactory.getLogger(getClass()); - private List _handlers; + protected List handlers; /** * Constructor. - * @param logoutSuccessHandler the logout success handler + * @param successHandler the logout success handler */ - public MutableLogoutFilter(LogoutSuccessHandler logoutSuccessHandler) { - super(logoutSuccessHandler, new DummyLogoutHandler()); - _logoutSuccessHandler = logoutSuccessHandler; + public MutableLogoutFilter(LogoutSuccessHandler successHandler) { + super(successHandler, new DummyLogoutHandler()); + logoutSuccessHandler = successHandler; } /** @@ -63,15 +66,15 @@ public void doFilter(final ServletRequest req, final ServletResponse res, final if (requiresLogout(request, response)) { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); - if (logger.isDebugEnabled()) { - logger.debug("Logging out user '" + auth + "' and transferring to logout destination"); + if (log.isDebugEnabled()) { + log.debug("Logging out user '{0}' and transferring to logout destination", auth); } - for (LogoutHandler handler : _handlers) { + for (LogoutHandler handler : handlers) { handler.logout(request, response, auth); } - _logoutSuccessHandler.onLogoutSuccess(request, response, auth); + logoutSuccessHandler.onLogoutSuccess(request, response, auth); return; } @@ -81,17 +84,17 @@ public void doFilter(final ServletRequest req, final ServletResponse res, final /** * Dependency injection for the logout handlers. - * @param handlers the handlers + * @param l the handlers */ - public void setHandlers(final List handlers) { - _handlers = handlers; + public void setHandlers(final List l) { + handlers = l; } /** * Null logout handler that's used to provide a non-empty list of handlers to the base class. * The real handlers will be after construction. */ - private static class DummyLogoutHandler implements LogoutHandler { + protected static class DummyLogoutHandler implements LogoutHandler { public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { // do nothing } diff --git a/src/templates/Person.groovy.template b/src/templates/Person.groovy.template index 2ca64a9aa..c11e76133 100644 --- a/src/templates/Person.groovy.template +++ b/src/templates/Person.groovy.template @@ -2,7 +2,8 @@ package ${packageName} class ${userClassName} { -${dependencyInjections} + transient springSecurityService + String username String password boolean enabled @@ -10,6 +11,8 @@ ${dependencyInjections} boolean accountLocked boolean passwordExpired + static transients = ['springSecurityService'] + static constraints = { username blank: false, unique: true password blank: false @@ -35,5 +38,5 @@ ${dependencyInjections} protected void encodePassword() { password = springSecurityService.encodePassword(password) - }${dirtyMethods} + } }