diff --git a/core/src/main/java/org/acegisecurity/config/AuthenticationMechanismBeanDefinitionParser.java b/core/src/main/java/org/acegisecurity/config/AuthenticationMechanismBeanDefinitionParser.java index af61ce778a..210c2d2f34 100644 --- a/core/src/main/java/org/acegisecurity/config/AuthenticationMechanismBeanDefinitionParser.java +++ b/core/src/main/java/org/acegisecurity/config/AuthenticationMechanismBeanDefinitionParser.java @@ -3,9 +3,6 @@ */ package org.acegisecurity.config; -import java.util.ArrayList; -import java.util.List; - import org.acegisecurity.providers.ProviderManager; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.RuntimeBeanReference; @@ -28,7 +25,7 @@ import org.w3c.dom.NodeList; public class AuthenticationMechanismBeanDefinitionParser extends AbstractBeanDefinitionParser implements BeanDefinitionParser { - private static final Object AUTHENTICATION_JDBC = "authentication-jdbc"; + private static final String AUTHENTICATION_JDBC = "authentication-jdbc"; private static final String REF = "ref"; diff --git a/core/src/main/java/org/acegisecurity/config/AuthenticationRepositoryBeanDefinitionParser.java b/core/src/main/java/org/acegisecurity/config/AuthenticationRepositoryBeanDefinitionParser.java index 57f2c79be7..86deccd8b8 100644 --- a/core/src/main/java/org/acegisecurity/config/AuthenticationRepositoryBeanDefinitionParser.java +++ b/core/src/main/java/org/acegisecurity/config/AuthenticationRepositoryBeanDefinitionParser.java @@ -25,7 +25,7 @@ import org.w3c.dom.NodeList; */ public class AuthenticationRepositoryBeanDefinitionParser extends AbstractBeanDefinitionParser { -// ~ Instance fields ================================================================================================ + // ~ Instance fields ================================================================================================ private static final String REPOSITORY_BEAN_REF = "repositoryBeanRef"; @@ -49,7 +49,7 @@ public class AuthenticationRepositoryBeanDefinitionParser extends AbstractBeanDe -// ~ Method ================================================================================================ + // ~ Method ================================================================================================ /** * TODO: Document Me !!! */ diff --git a/core/src/main/java/org/acegisecurity/config/PrincipalRepositoryBeanDefinitionParser.java b/core/src/main/java/org/acegisecurity/config/PrincipalRepositoryBeanDefinitionParser.java index 93e6395b37..b083352633 100644 --- a/core/src/main/java/org/acegisecurity/config/PrincipalRepositoryBeanDefinitionParser.java +++ b/core/src/main/java/org/acegisecurity/config/PrincipalRepositoryBeanDefinitionParser.java @@ -3,9 +3,22 @@ */ package org.acegisecurity.config; +import java.util.Properties; + +import org.acegisecurity.GrantedAuthorityImpl; +import org.acegisecurity.userdetails.User; +import org.acegisecurity.userdetails.UserDetails; import org.acegisecurity.userdetails.jdbc.JdbcDaoImpl; +import org.acegisecurity.userdetails.memory.InMemoryDaoImpl; +import org.acegisecurity.userdetails.memory.UserAttribute; +import org.acegisecurity.userdetails.memory.UserMap; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.config.PropertiesFactoryBean; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.BeanDefinitionParser; @@ -15,44 +28,128 @@ import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -/** +/** * @author vpuri * */ public class PrincipalRepositoryBeanDefinitionParser extends AbstractBeanDefinitionParser implements BeanDefinitionParser { - // ~ Instance fields ================================================================================================ + // ~ Static fields/initializers ===================================================================================== + + private static final Log logger = LogFactory.getLog(PrincipalRepositoryBeanDefinitionParser.class); + + // ~ Instance fields + // ================================================================================================ private static final String JDBC = "jdbc"; + private static final String DATASOURCE_REF = "dataSourceBeanRef"; + private static final String DATASOURCE = "dataSource"; + private static final String JDBCTEMPLATE_REF = "jdbcTemplateBeanRef"; + private static final String JDBCTEMPLATE = "jdbcTemplate"; + private static final String AUTHORITIES_BY_USERNAME_QUERY = "authoritiesByUsernameQuery"; + private static final String ROLE_PREFIX = "rolePrefix"; - private static final String USERNAME_BASED_PRIMARY_KEY="usernameBasedPrimaryKey"; + + private static final String USERNAME_BASED_PRIMARY_KEY = "usernameBasedPrimaryKey"; + + private static final String PROPERTIES = "properties"; + + private static final String RESOURCE = "resource"; + + private static final String USER_PROPERTIES = "userProperties"; + + private static final String USER_DEFINITION = "user-definition"; + + private static final Object GRANTED_AUTHORITY = "granted-authority"; + + private static final String USERNAME = "username"; + + private static final String PASSWORD = "password"; + + private static final String ENABLED = "enabled"; + + private static final String GRANTED_AUTHORITY_REF = "granted-authority-ref"; + + private static final String AUTHORITY = "authority"; - //authoritiesByUsernameQuery="" rolePrefix="" usernameBasedPrimaryKey="true" usersByUsernameQuery="" - - // ~ Method ================================================================================================ + private static final String AUTHORITY_BEAN_REF="authorityBeanRef"; + + // ~ Method + // ================================================================================================ + /** + * + */ protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { - NodeList userDetailsServiceChildren = element.getChildNodes(); - RootBeanDefinition userDetailsServiceJdbcDefinition = null; + RootBeanDefinition userDetailsServiceDefinition = null; for (int i = 0, n = userDetailsServiceChildren.getLength(); i < n; i++) { Node userDetailsService = userDetailsServiceChildren.item(i); if (JDBC.equals(userDetailsService.getLocalName()) && userDetailsService.getNodeType() == Node.ELEMENT_NODE) { Element ele = (Element) userDetailsService; - userDetailsServiceJdbcDefinition = parseUserDetailsServiceJdbcDefinition(ele); - userDetailsServiceJdbcDefinition.setSource(parserContext.extractSource(element)); - parserContext.getReaderContext().registerWithGeneratedName(userDetailsServiceJdbcDefinition); + userDetailsServiceDefinition = parseUserDetailsServiceJdbcDefinition(ele); + userDetailsServiceDefinition.setSource(parserContext.extractSource(element)); + parserContext.getReaderContext().registerWithGeneratedName(userDetailsServiceDefinition); + } + if (PROPERTIES.equals(userDetailsService.getLocalName()) + && userDetailsService.getNodeType() == Node.ELEMENT_NODE) { + Element ele = (Element) userDetailsService; + + userDetailsServiceDefinition = new RootBeanDefinition(InMemoryDaoImpl.class); + userDetailsServiceDefinition.getPropertyValues().addPropertyValue(USER_PROPERTIES, + new RuntimeBeanReference(createPropertiesBeanDefinition(ele, parserContext))); + userDetailsServiceDefinition.setSource(parserContext.extractSource(element)); + parserContext.getReaderContext().registerWithGeneratedName(userDetailsServiceDefinition); + } + if (USER_DEFINITION.equals(userDetailsService.getLocalName()) + && userDetailsService.getNodeType() == Node.ELEMENT_NODE) { + Element ele = (Element) userDetailsService; + + // create a UserMap which interns uses UserMapEditor + userDetailsServiceDefinition = createUserDefinition(ele, parserContext); } } - return userDetailsServiceJdbcDefinition; + return userDetailsServiceDefinition; } + private RootBeanDefinition createUserDefinition(Element ele, ParserContext parserContext) { + RootBeanDefinition definition = new RootBeanDefinition(InMemoryDaoImpl.class); + + UserAttribute userAttribute = new UserAttribute(); + UserMap userMap = new UserMap(); + + setPassword(ele, userAttribute); + setEnabled(ele, userAttribute); + setAuthorities(ele, userAttribute); + + UserDetails user = new User(ele.getAttribute(USERNAME), userAttribute.getPassword(), userAttribute.isEnabled(), + true, true, true, userAttribute.getAuthorities()); + userMap.addUser(user); + definition.getPropertyValues().addPropertyValue("userMap", userMap); + return definition; + + } + + private String createPropertiesBeanDefinition(Element ele, ParserContext parserContext) { + // properties element + RootBeanDefinition defintion = new RootBeanDefinition(PropertiesFactoryBean.class); + String propertyValue = ele.getAttribute(RESOURCE); + defintion.getPropertyValues().addPropertyValue(RESOURCE, propertyValue); + defintion.setSource(parserContext.extractSource(ele)); + return parserContext.getReaderContext().registerWithGeneratedName(defintion); + } + + /** + * + * @param elementToParse + * @return + */ private RootBeanDefinition parseUserDetailsServiceJdbcDefinition(Element elementToParse) { // parse attributes RootBeanDefinition definition = new RootBeanDefinition(JdbcDaoImpl.class); @@ -63,14 +160,76 @@ public class PrincipalRepositoryBeanDefinitionParser extends AbstractBeanDefinit setPropertyIfAvailable(elementToParse, USERNAME_BASED_PRIMARY_KEY, USERNAME_BASED_PRIMARY_KEY, definition); return definition; } - - private void setPropertyIfAvailable(Element el, String attribute, String property, RootBeanDefinition definition) { - String propertyValue = el.getAttribute(attribute); + + protected void doParseProperties(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + Properties parsedProps = parserContext.getDelegate().parsePropsElement(element); + builder.addPropertyValue(PROPERTIES, parsedProps); + } + + /** + * + * @param element + * @param attribute + * @param property + * @param definition + */ + private void setPropertyIfAvailable(Element element, String attribute, String property, + RootBeanDefinition definition) { + String propertyValue = element.getAttribute(attribute); if (StringUtils.hasText(propertyValue)) { - definition.getPropertyValues().addPropertyValue(property, new RuntimeBeanReference(propertyValue)); + if (propertyValue.equals(DATASOURCE_REF) || propertyValue.equals(JDBCTEMPLATE_REF)) { + definition.getPropertyValues().addPropertyValue(property, new RuntimeBeanReference(propertyValue)); + } + else { + definition.getPropertyValues().addPropertyValue(property, propertyValue); + } } } + private void setPassword(Element element, UserAttribute userAttribute) { + String propertyValue = element.getAttribute(PASSWORD); + if (StringUtils.hasText(propertyValue)) { + userAttribute.setPassword(propertyValue); + } + } + private void setEnabled(Element element, UserAttribute userAttribute) { + String propertyValue = element.getAttribute(ENABLED); + if (StringUtils.hasText(propertyValue)) { + if (propertyValue.equals("true")) { + userAttribute.setEnabled(Boolean.TRUE); + } + else { + userAttribute.setEnabled(Boolean.FALSE); + } + } + } + + private void setAuthorities(Element ele, UserAttribute userAttribute) { + // get authorities + NodeList childNodes = ele.getChildNodes(); + + ManagedList authorities = new ManagedList(); + + for (int i = 0, n = childNodes.getLength(); i < n; i++) { + Node authorityNode = childNodes.item(i); + + if (GRANTED_AUTHORITY.equals(authorityNode.getLocalName()) + && authorityNode.getNodeType() == Element.ELEMENT_NODE) { + Element propertyValue = (Element) authorityNode; + authorities.add(new GrantedAuthorityImpl(propertyValue.getAttribute(AUTHORITY))); + } + + if (GRANTED_AUTHORITY_REF.equals(authorityNode.getLocalName()) + && authorityNode.getNodeType() == Element.ELEMENT_NODE) { + Element propertyValue = (Element) authorityNode; + String attribute = propertyValue.getAttribute(AUTHORITY_BEAN_REF); + if (StringUtils.hasLength(attribute)) { + authorities.add(new RuntimeBeanReference(attribute)); + } + } + } + userAttribute.setAuthorities(authorities); + } } diff --git a/core/src/main/java/org/acegisecurity/config/SecurityNamespaceHandler.java b/core/src/main/java/org/acegisecurity/config/SecurityNamespaceHandler.java index 2b922f8a51..60868dba9e 100644 --- a/core/src/main/java/org/acegisecurity/config/SecurityNamespaceHandler.java +++ b/core/src/main/java/org/acegisecurity/config/SecurityNamespaceHandler.java @@ -25,6 +25,7 @@ public class SecurityNamespaceHandler extends NamespaceHandlerSupport { registerBeanDefinitionParser("authentication-mechanism", new AuthenticationMechanismBeanDefinitionParser()); registerBeanDefinitionParser("authentication-remember-me-services", new RememberMeServicesBeanDefinitionParser()); registerBeanDefinitionParser("authentication-remember-me-filter", new RememberMeFilterBeanDefinitionParser()); + registerBeanDefinitionParser("logout-support", new LogoutFilterBeanDefinitionParser()); } } diff --git a/core/src/main/java/org/acegisecurity/ui/logout/SecurityContextLogoutHandler.java b/core/src/main/java/org/acegisecurity/ui/logout/SecurityContextLogoutHandler.java index 2ae57494ea..d44398e2db 100644 --- a/core/src/main/java/org/acegisecurity/ui/logout/SecurityContextLogoutHandler.java +++ b/core/src/main/java/org/acegisecurity/ui/logout/SecurityContextLogoutHandler.java @@ -18,60 +18,74 @@ package org.acegisecurity.ui.logout; import org.acegisecurity.Authentication; import org.acegisecurity.context.SecurityContextHolder; +import org.springframework.core.Ordered; import org.springframework.util.Assert; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; - /** - * Performs a logout by modifying the {@link org.acegisecurity.context.SecurityContextHolder}. - * - *

Will also invalidate the {@link HttpSession} if {@link #isInvalidateHttpSession()} is - * true and the session is not null. - * + * Performs a logout by modifying the + * {@link org.acegisecurity.context.SecurityContextHolder}. + * + *

+ * Will also invalidate the {@link HttpSession} if + * {@link #isInvalidateHttpSession()} is true and the session is + * not null. + * * @author Ben Alex - * @version $Id$ + * @version $Id: SecurityContextLogoutHandler.java 1784 2007-02-24 21:00:24Z + * luke_t $ */ -public class SecurityContextLogoutHandler implements LogoutHandler { - //~ Methods ======================================================================================================== +public class SecurityContextLogoutHandler implements LogoutHandler, Ordered { + // ~ Methods + // ======================================================================================================== - private boolean invalidateHttpSession = true; + private boolean invalidateHttpSession = true; - /** - * Requires the request to be passed in. - * - * @param request from which to obtain a HTTP session (cannot be null) - * @param response not used (can be null) - * @param authentication not used (can be null) - */ - public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { - Assert.notNull(request, "HttpServletRequest required"); - if (invalidateHttpSession) { - HttpSession session = request.getSession(false); - if (session != null) { - session.invalidate(); - } - } + private int order = Integer.MAX_VALUE; //~ default - SecurityContextHolder.clearContext(); - } + /** + * Requires the request to be passed in. + * + * @param request from which to obtain a HTTP session (cannot be null) + * @param response not used (can be null) + * @param authentication not used (can be null) + */ + public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { + Assert.notNull(request, "HttpServletRequest required"); + if (invalidateHttpSession) { + HttpSession session = request.getSession(false); + if (session != null) { + session.invalidate(); + } + } - public boolean isInvalidateHttpSession() { - return invalidateHttpSession; - } + SecurityContextHolder.clearContext(); + } - /** - * Causes the {@link HttpSession} to be invalidated when this - * {@link LogoutHandler} is invoked. Defaults to true. - * - * @param invalidateHttpSession true if you wish the session to be - * invalidated (default) or false if it should not be - */ - public void setInvalidateHttpSession(boolean invalidateHttpSession) { - this.invalidateHttpSession = invalidateHttpSession; - } + public boolean isInvalidateHttpSession() { + return invalidateHttpSession; + } + /** + * Causes the {@link HttpSession} to be invalidated when this + * {@link LogoutHandler} is invoked. Defaults to true. + * + * @param invalidateHttpSession true if you wish the session to be + * invalidated (default) or false if it should not be + */ + public void setInvalidateHttpSession(boolean invalidateHttpSession) { + this.invalidateHttpSession = invalidateHttpSession; + } + + public int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } } diff --git a/core/src/main/java/org/acegisecurity/ui/rememberme/TokenBasedRememberMeServices.java b/core/src/main/java/org/acegisecurity/ui/rememberme/TokenBasedRememberMeServices.java index 4edabbad20..d9d5e5424a 100644 --- a/core/src/main/java/org/acegisecurity/ui/rememberme/TokenBasedRememberMeServices.java +++ b/core/src/main/java/org/acegisecurity/ui/rememberme/TokenBasedRememberMeServices.java @@ -15,36 +15,30 @@ package org.acegisecurity.ui.rememberme; -import org.acegisecurity.Authentication; - -import org.acegisecurity.providers.rememberme.RememberMeAuthenticationToken; - -import org.acegisecurity.ui.AuthenticationDetailsSource; -import org.acegisecurity.ui.AuthenticationDetailsSourceImpl; -import org.acegisecurity.ui.logout.LogoutHandler; - -import org.acegisecurity.userdetails.UserDetails; -import org.acegisecurity.userdetails.UserDetailsService; -import org.acegisecurity.userdetails.UsernameNotFoundException; - -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.beans.factory.InitializingBean; - -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -import org.springframework.web.bind.RequestUtils; - import java.util.Date; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.acegisecurity.Authentication; +import org.acegisecurity.providers.rememberme.RememberMeAuthenticationToken; +import org.acegisecurity.ui.AuthenticationDetailsSource; +import org.acegisecurity.ui.AuthenticationDetailsSourceImpl; +import org.acegisecurity.ui.logout.LogoutHandler; +import org.acegisecurity.userdetails.UserDetails; +import org.acegisecurity.userdetails.UserDetailsService; +import org.acegisecurity.userdetails.UsernameNotFoundException; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.Ordered; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.RequestUtils; + /** * Identifies previously remembered users by a Base-64 encoded cookie. @@ -88,7 +82,7 @@ import javax.servlet.http.HttpServletResponse; * @author Ben Alex * @version $Id$ */ -public class TokenBasedRememberMeServices implements RememberMeServices, InitializingBean, LogoutHandler { +public class TokenBasedRememberMeServices implements RememberMeServices, InitializingBean, LogoutHandler, Ordered { //~ Static fields/initializers ===================================================================================== public static final String ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY = "ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE"; @@ -103,6 +97,7 @@ public class TokenBasedRememberMeServices implements RememberMeServices, Initial private UserDetailsService userDetailsService; private long tokenValiditySeconds = 1209600; // 14 days private boolean alwaysRemember = false; + private int order = Integer.MAX_VALUE; //~ default //~ Methods ======================================================================================================== @@ -354,4 +349,13 @@ public class TokenBasedRememberMeServices implements RememberMeServices, Initial public void setAlwaysRemember(boolean alwaysRemember) { this.alwaysRemember = alwaysRemember; } + + public int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } + } diff --git a/core/src/main/resources/org/acegisecurity/config/spring-security-2.0.xsd b/core/src/main/resources/org/acegisecurity/config/spring-security-2.0.xsd index 13cd41f94f..23f7bbf986 100644 --- a/core/src/main/resources/org/acegisecurity/config/spring-security-2.0.xsd +++ b/core/src/main/resources/org/acegisecurity/config/spring-security-2.0.xsd @@ -3,9 +3,10 @@ - + @@ -157,17 +158,41 @@ + - + + + + + + + + + - - - - + + + + + + @@ -182,21 +207,58 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - +