SEC-271: Added BeanDefitnitionParser for principal-repository, extended security schema and added unit tests
This commit is contained in:
parent
51f306a19a
commit
1203e9858a
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package org.acegisecurity.config;
|
||||
|
||||
import org.acegisecurity.ui.logout.LogoutFilter;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author vpuri
|
||||
* @since
|
||||
*/
|
||||
public class LogoutFilterBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
private static final String REDIRECT_AFTER_LOGOUT_URL = "redirectAfterLogoutUrl";
|
||||
|
||||
private static final String LOGOUT_URL = "logoutUrl";
|
||||
|
||||
// ~ Methods
|
||||
// ================================================================================================
|
||||
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
|
||||
// add the properties
|
||||
RootBeanDefinition definition = new RootBeanDefinition(LogoutFilter.class);
|
||||
setConstructorArgumentIfAvailable(0, element, REDIRECT_AFTER_LOGOUT_URL, "logoutSuccessUrl", definition);
|
||||
// setPropertyIfAvailable(element,
|
||||
// element.getAttribute(REDIRECT_AFTER_LOGOUT_URL), "logoutSuccessUrl",
|
||||
// definition);
|
||||
setPropertyIfAvailable(element, LOGOUT_URL, "filterProcessesUrl", definition);
|
||||
|
||||
// register BFPP to check if LogoutFilter does not have setHandlers
|
||||
// populated, introspect app ctx for LogoutHandlers, using Ordered (if
|
||||
// present, otherwise assume Integer.MAX_VALUE)
|
||||
RootBeanDefinition bfpp = new RootBeanDefinition(LogoutHandlerOrderResolver.class);
|
||||
parserContext.getReaderContext().registerWithGeneratedName(bfpp);
|
||||
|
||||
return definition;
|
||||
}
|
||||
|
||||
private void setConstructorArgumentIfAvailable(int index, Element element, String attribute, String property,
|
||||
RootBeanDefinition definition) {
|
||||
String propertyValue = element.getAttribute(attribute);
|
||||
if (StringUtils.hasText(propertyValue)) {
|
||||
definition.getConstructorArgumentValues().addIndexedArgumentValue(index, propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
private void setPropertyIfAvailable(Element element, String attribute, String property,
|
||||
RootBeanDefinition definition) {
|
||||
String propertyValue = element.getAttribute(attribute);
|
||||
if (StringUtils.hasText(propertyValue)) {
|
||||
definition.getPropertyValues().addPropertyValue(property, propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package org.acegisecurity.config;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.acegisecurity.ui.logout.LogoutFilter;
|
||||
import org.acegisecurity.ui.logout.LogoutHandler;
|
||||
import org.acegisecurity.ui.logout.SecurityContextLogoutHandler;
|
||||
import org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
/**
|
||||
* @author vpuri
|
||||
* @since
|
||||
*/
|
||||
public class LogoutHandlerOrderResolver implements BeanFactoryPostProcessor {
|
||||
|
||||
// ~ Methods
|
||||
// ================================================================================================
|
||||
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
// If LogoutFilter does not have setHandlers populated, introspect app
|
||||
// ctx for LogoutHandlers, using Ordered (if present, otherwise assume
|
||||
// Integer.MAX_VALUE)
|
||||
String[] names = beanFactory.getBeanNamesForType(LogoutFilter.class);
|
||||
RootBeanDefinition definition = (RootBeanDefinition) beanFactory.getBeanDefinition(names[0]);
|
||||
ValueHolder holder = getHandlersIfConfigured(beanFactory, definition);
|
||||
if (holder == null) {
|
||||
// intropect the appcontext for registerd LogoutHandler
|
||||
List logoutHandlers = retrieveAllLogoutHandlers(beanFactory);
|
||||
definition.getConstructorArgumentValues().addIndexedArgumentValue(1, logoutHandlers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param beanFactory
|
||||
* @param definition
|
||||
* @return
|
||||
*/
|
||||
private ValueHolder getHandlersIfConfigured(ConfigurableListableBeanFactory beanFactory,
|
||||
RootBeanDefinition definition) {
|
||||
// there should be only one LogoutFilter
|
||||
return definition.getConstructorArgumentValues().getArgumentValue(1, null);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param beanFactory
|
||||
* @return
|
||||
*/
|
||||
private List retrieveAllLogoutHandlers(ConfigurableListableBeanFactory beanFactory) {
|
||||
String[] names = beanFactory.getBeanNamesForType(LogoutHandler.class);
|
||||
ManagedList list = new ManagedList();
|
||||
|
||||
for (int i = 0, n = names.length; i < n; i++) {
|
||||
RootBeanDefinition definition = (RootBeanDefinition) beanFactory.getBeanDefinition(names[i]);
|
||||
|
||||
if (Ordered.class.isAssignableFrom(definition.getBeanClass())) {
|
||||
definition.getPropertyValues().addPropertyValue("order", getOrder(definition.getBeanClass()));
|
||||
list.add(definition);
|
||||
}
|
||||
}
|
||||
Collections.sort(list, new OrderComparator());
|
||||
return list;
|
||||
}
|
||||
|
||||
private int getOrder(Class clazz) {
|
||||
if (clazz.getName().equals(TokenBasedRememberMeServices.class.getName())) {
|
||||
return 0;
|
||||
}
|
||||
if (clazz.getName().equals(SecurityContextLogoutHandler.class.getName())) {
|
||||
return 1;
|
||||
}
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package org.acegisecurity.config;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.acegisecurity.GrantedAuthority;
|
||||
import org.acegisecurity.GrantedAuthorityImpl;
|
||||
import org.acegisecurity.userdetails.User;
|
||||
import org.acegisecurity.userdetails.UserDetailsService;
|
||||
import org.acegisecurity.userdetails.memory.InMemoryDaoImpl;
|
||||
import org.acegisecurity.userdetails.memory.UserMap;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* @author vpuri
|
||||
*
|
||||
*/
|
||||
public class PrincipalRepositoryNamespaceTests extends TestCase {
|
||||
|
||||
public void testParserWithUserDefinition() {
|
||||
ApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"org/acegisecurity/config/principal-repository-user-map.xml");
|
||||
|
||||
ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory) context
|
||||
.getAutowireCapableBeanFactory();
|
||||
|
||||
String[] names = clbf.getBeanNamesForType(UserDetailsService.class);
|
||||
assertEquals(1, names.length);
|
||||
|
||||
RootBeanDefinition definition = (RootBeanDefinition) clbf.getBeanDefinition(names[0]);
|
||||
assertEquals(InMemoryDaoImpl.class, definition.getBeanClass());
|
||||
|
||||
UserMap map = new UserMap();
|
||||
|
||||
GrantedAuthority[] authotities = { new GrantedAuthorityImpl("ROLE_YO"), new GrantedAuthorityImpl("ROLE_YOYO") };
|
||||
|
||||
User user = new User("vishal", "nottellingya", true, true, true, true, authotities);
|
||||
|
||||
map.addUser(user);
|
||||
|
||||
assertPropertyValues(map, definition, "userMap");
|
||||
|
||||
}
|
||||
|
||||
private void assertPropertyValues(UserMap assertionValue, RootBeanDefinition definition, String property) {
|
||||
PropertyValue propertyValue = definition.getPropertyValues().getPropertyValue(property);
|
||||
assertNotNull(propertyValue);
|
||||
assertTrue(propertyValue.getValue() instanceof UserMap);
|
||||
UserMap users = (UserMap) propertyValue.getValue();
|
||||
assertTrue(assertionValue.getUserCount() == users.getUserCount());
|
||||
assertEquals(assertionValue.getUser("vishal"), users.getUser("vishal"));
|
||||
assertTrue(users.getUser("vishal").isEnabled());
|
||||
assertTrue(users.getUser("vishal").isAccountNonExpired());
|
||||
assertTrue(users.getUser("vishal").isAccountNonLocked());
|
||||
assertTrue(users.getUser("vishal").isCredentialsNonExpired());
|
||||
assertEquals(2, users.getUser("vishal").getAuthorities().length);
|
||||
assertEquals(new GrantedAuthorityImpl("ROLE_YO"), users.getUser("vishal").getAuthorities()[0]);
|
||||
assertEquals(new GrantedAuthorityImpl("ROLE_YOYO"), users.getUser("vishal").getAuthorities()[1]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:security="http://www.springframework.org/schema/security"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/beans/spring-util-2.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
|
||||
|
||||
<!-- http://www.springframework.org/schema/security file:/Users/vpuri/interface21/acegisecurity/trunk/acegisecurity/core/src/main/resources/org/acegisecurity/config/spring-security-2.0.xsd -->
|
||||
<!-- http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd" -->
|
||||
|
||||
<!-- If LogoutFilter does not have setHandlers populated, introspect app ctx for LogoutHandlers, using Ordered (if present, otherwise assume Integer.MAX_VALUE) -->
|
||||
<!-- The logoutUrl and redirectAfterLogout are both optional and default to that shown -->
|
||||
<security:logout-support id="logoutFilter"
|
||||
redirectAfterLogoutUrl="/" logoutUrl="/logout" />
|
||||
|
||||
<security:authentication-remember-me-services
|
||||
id="rememberMeServices" key="someValue" />
|
||||
|
||||
<security:principal-repository id="userDetailsService">
|
||||
<security:user-definition username="vishal"
|
||||
password="nottellingya" enabled="true">
|
||||
<security:granted-authority authority="ROLE_YO" />
|
||||
<security:granted-authority authority="ROLE_YOYO" />
|
||||
<!-- TODO: <security:granted-authority-ref authorityBeanRef="fooBarAuthority"/>-->
|
||||
</security:user-definition>
|
||||
</security:principal-repository>
|
||||
</beans>
|
|
@ -14,8 +14,11 @@ http://www.springframework.org/schema/security file:/Users/vpuri/interface21/ace
|
|||
<!-- userDetailsService, This is used if they want an out-of-the-bx UserDetailsService; if they write their own, this goes away and they wire a legacy bean definition and then the various
|
||||
beans depending on a UserDetailsService will auto-detect it at runtime OR provide a way of setUserDetailsService(UserDetailsService) if to specified explicitly.
|
||||
If they fail to provide a repository, the security-autodetect will set one up for them with a few basic in-memory users and pwds -->
|
||||
|
||||
<!--<security:security-autoconfig/> -->
|
||||
|
||||
<security:principal-repository id="userDetailsService">
|
||||
<security:jdbc dataSourceBeanRef="dataSource" jdbcTemplateBeanRef="jdbcTemplate" authoritiesByUsernameQuery="" rolePrefix="" usernameBasedPrimaryKey="true" usersByUsernameQuery=""/>
|
||||
<security:jdbc dataSourceBeanRef="dataSource"/>
|
||||
</security:principal-repository>
|
||||
|
||||
<bean id="dataSource"
|
||||
|
@ -35,8 +38,7 @@ http://www.springframework.org/schema/security file:/Users/vpuri/interface21/ace
|
|||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
|
||||
<!--<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
|
||||
<property name="dataSource" ref="dataSource"></property>
|
||||
</bean>
|
||||
|
||||
</bean>-->
|
||||
</beans>
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:security="http://www.springframework.org/schema/security"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/beans/spring-util-2.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
|
||||
|
||||
<!-- http://www.springframework.org/schema/security file:/Users/vpuri/interface21/acegisecurity/trunk/acegisecurity/core/src/main/resources/org/acegisecurity/config/spring-security-2.0.xsd -->
|
||||
<!-- http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd" -->
|
||||
|
||||
<!-- userDetailsService, This is used if they want an out-of-the-bx UserDetailsService; if they write their own, this goes away and they wire a legacy bean definition and then the various
|
||||
beans depending on a UserDetailsService will auto-detect it at runtime OR provide a way of setUserDetailsService(UserDetailsService) if to specified explicitly.
|
||||
If they fail to provide a repository, the security-autodetect will set one up for them with a few basic in-memory users and pwds -->
|
||||
|
||||
<security:principal-repository id="userDetailsService">
|
||||
<security:properties resource="classpath:org/acegisecurity/config/user.properties"/>
|
||||
</security:principal-repository>
|
||||
|
||||
</beans>
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:security="http://www.springframework.org/schema/security"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/beans/spring-util-2.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
|
||||
|
||||
<!-- http://www.springframework.org/schema/security file:/Users/vpuri/interface21/acegisecurity/trunk/acegisecurity/core/src/main/resources/org/acegisecurity/config/spring-security-2.0.xsd -->
|
||||
<!-- http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd" -->
|
||||
|
||||
<!-- userDetailsService, This is used if they want an out-of-the-bx UserDetailsService; if they write their own, this goes away and they wire a legacy bean definition and then the various
|
||||
beans depending on a UserDetailsService will auto-detect it at runtime OR provide a way of setUserDetailsService(UserDetailsService) if to specified explicitly.
|
||||
If they fail to provide a repository, the security-autodetect will set one up for them with a few basic in-memory users and pwds -->
|
||||
|
||||
<security:principal-repository id="userDetailsService">
|
||||
<security:user-definition username="vishal" password="nottellingya" enabled="true">
|
||||
<security:granted-authority authority="ROLE_YO"/>
|
||||
<security:granted-authority authority="ROLE_YOYO"/>
|
||||
<!-- TODO: <security:granted-authority-ref authorityBeanRef="fooBarAuthority"/>-->
|
||||
</security:user-definition>
|
||||
</security:principal-repository>
|
||||
|
||||
<!-- TODO: <security:granted-authority id="fooBarAuthority" authority="ROLE_FOOBAR"/> -->
|
||||
|
||||
</beans>
|
|
@ -0,0 +1,2 @@
|
|||
vishal=ity,ROLE_ADMIN
|
||||
ity=vishal,ROLE_TELLER
|
Loading…
Reference in New Issue