SEC-271: Added more BeanDefinitionParsers and extend spring-security.xsd to have more elements

This commit is contained in:
Vishal Puri 2007-05-15 13:26:05 +00:00
parent ced5cb4f85
commit 51f306a19a
9 changed files with 340 additions and 103 deletions

View File

@ -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";

View File

@ -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 !!!
*/

View File

@ -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;
@ -22,37 +35,121 @@ import org.w3c.dom.NodeList;
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";
//authoritiesByUsernameQuery="" rolePrefix="" usernameBasedPrimaryKey="true" usersByUsernameQuery=""
private static final String USERNAME_BASED_PRIMARY_KEY = "usernameBasedPrimaryKey";
// ~ Method ================================================================================================
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";
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);
@ -64,13 +161,75 @@ public class PrincipalRepositoryBeanDefinitionParser extends AbstractBeanDefinit
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);
}
}

View File

@ -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());
}
}

View File

@ -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}.
* Performs a logout by modifying the
* {@link org.acegisecurity.context.SecurityContextHolder}.
*
* <p>Will also invalidate the {@link HttpSession} if {@link #isInvalidateHttpSession()} is
* <code>true</code> and the session is not <code>null</code>.
* <p>
* Will also invalidate the {@link HttpSession} if
* {@link #isInvalidateHttpSession()} is <code>true</code> and the session is
* not <code>null</code>.
*
* @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 <code>null</code>)
* @param authentication not used (can be <code>null</code>)
*/
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 <code>null</code>)
* @param authentication not used (can be <code>null</code>)
*/
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;
}
}

View File

@ -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;
}
}

View File

@ -3,9 +3,10 @@
<xsd:schema xmlns="http://www.springframework.org/schema/security"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.springframework.org/schema/security"
xmlns:util="http://www.springframework.org/schema/util"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/util" />
<xsd:element name="session-context-integration">
<xsd:complexType>
@ -157,17 +158,41 @@
</xsd:complexType>
</xsd:element>
<xsd:element name="logout-support" type="LogoutFilter" />
<xsd:element name="principal-repository"
type="PrincipalRepository" />
<xsd:complexType name="LogoutFilter">
<!-- <xsd:all>
<xsd:element name="clear-context" minOccurs="0" maxOccurs="1">
<xsd:complexType>
<xsd:attribute name="invalidateHttpSession"
type="xsd:boolean" default="true" use="optional" />
</xsd:complexType>
</xsd:element>
<xsd:element name="clear-remember-me" minOccurs="0" maxOccurs="1">>
<xsd:complexType>
<xsd:attribute name="rememberMeServicesBeanRef"
type="xsd:string" use="optional" />
</xsd:complexType>
</xsd:element>
</xsd:all> -->
<!-- Write other attributes -->
<xsd:attribute name="id" type="xsd:ID" />
<xsd:attribute name="redirectAfterLogoutUrl" type="xsd:string"
default="/" />
<xsd:attribute name="logoutUrl" type="xsd:string"
default="/logout" />
</xsd:complexType>
<xsd:element name="principal-repository" type="PrincipalRepository" />
<xsd:complexType name="PrincipalRepository">
<xsd:sequence>
<xsd:element ref="jdbc" minOccurs="0"
maxOccurs="1" />
<xsd:element ref="ldap" minOccurs="0"
maxOccurs="1" />
</xsd:sequence>
<xsd:choice>
<xsd:element ref="jdbc" minOccurs="0" maxOccurs="1" />
<xsd:element ref="ldap" minOccurs="0" maxOccurs="1" />
<xsd:element ref="properties" minOccurs="0" maxOccurs="1" />
<xsd:element ref="user-definition" minOccurs="0"
maxOccurs="unbounded" />
</xsd:choice>
<xsd:attribute name="id" type="xsd:ID">
<xsd:annotation>
<xsd:documentation>
@ -182,21 +207,58 @@
<xsd:element name="jdbc">
<xsd:complexType>
<xsd:attribute name="dataSourceBeanRef" type="xsd:string" />
<xsd:attribute name="authoritiesByUsernameQuery" type="xsd:string" use="optional"/>
<xsd:attribute name="jdbcTemplateBeanRef" type="xsd:string" use="optional"/>
<xsd:attribute name="rolePrefix" type="xsd:string" use="optional"/>
<xsd:attribute name="usernameBasedPrimaryKey" type="xsd:boolean" use="optional"/>
<xsd:attribute name="usersByUsernameQuery" type="xsd:string" use="optional"/>
<xsd:attribute name="authoritiesByUsernameQuery"
type="xsd:string" use="optional" />
<xsd:attribute name="jdbcTemplateBeanRef" type="xsd:string"
use="optional" />
<xsd:attribute name="rolePrefix" type="xsd:string"
use="optional" />
<xsd:attribute name="usernameBasedPrimaryKey"
type="xsd:boolean" use="optional" />
<xsd:attribute name="usersByUsernameQuery" type="xsd:string"
use="optional" />
</xsd:complexType>
</xsd:element>
<xsd:element name="ldap">
<xsd:complexType>
<xsd:attribute name="not-yet-defined" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="properties">
<xsd:complexType>
<xsd:attribute name="resource" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="user-definition">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="granted-authority" minOccurs="0"
maxOccurs="unbounded">
<xsd:complexType>
<xsd:attribute name="authority"
type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
<xsd:element name="granted-authority-ref" minOccurs="0"
maxOccurs="unbounded">
<xsd:complexType>
<xsd:attribute name="authorityBeanRef"
type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="username" type="xsd:string"
use="required" />
<xsd:attribute name="password" type="xsd:string" />
<xsd:attribute name="enabled" type="xsd:boolean" />
<xsd:anyAttribute namespace="##local"
processContents="strict" />
</xsd:complexType>
</xsd:element>
<xsd:element name="authentication-repository"

View File

@ -8,7 +8,7 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
public class RememberMeBeanDefinitionParserTest extends TestCase {
public void testRememberMeDefaults() {
ApplicationContext context = new ClassPathXmlApplicationContext("org/acegisecurity/config/remember-me-defaults.xml");
ApplicationContext context = new ClassPathXmlApplicationContext("org/acegisecurity/config/principal-repository-properties.xml");
}

View File

@ -72,7 +72,7 @@
<security:principal-repository id="id">
<security:ldap x="you can do the attributes and suitable nested elements"/>
<security:jdbc x="you can do the attributes and suitable nested elements"/>
<security:properties resource="resourceStringToPropertiesFile"> <!-- if they specify a resource attrib, that means throw exception if they nest some user-definition data) -->
<security:properties location="resourceStringToPropertiesFile"> <!-- if they specify a resource attrib, that means throw exception if they nest some user-definition data) -->
<security:user-definition username="ben" password="nottellingYou" enabled="true" it="more stuff if you want">
<security:granted-authority authority="ROLE_ANONYMOUS"/>
<ref bean="fooBarAuthority"/>