I'm trying to inject Ehcache (v3.9) javax.cache.CacheManager (JSR-107 JCache API) using Spring XML context.
Initial attempt:
<bean id="cacheManager" factory-bean="cachingManagerProvider" factory-method="getCacheManager">
<constructor-arg name="uri" type="java.net.URI" value="classpath:/WEB-INF/ehcache.xml" />
<constructor-arg name="classLoader" type="java.lang.ClassLoader" ><null /></constructor-arg>
</bean>
<bean id="cachingManagerProvider" class="org.ehcache.jsr107.EhcacheCachingProvider" />
fails with java.lang.IllegalArgumentException: Could not retrieve URI for class path resource [WEB-INF/ehcache.xml]: class path resource [WEB-INF/ehcache.xml] cannot be resolved to URL because it does not exist
I managed to do it only using adapter class:
import java.io.IOException;
import javax.cache.CacheManager;
import javax.cache.spi.CachingProvider;
import org.springframework.core.io.Resource;
public class CacheManagerFactory {
private final Resource configurationLocation;
private final CachingProvider cachingProvider;
public CacheManagerFactory(CachingProvider cachingProvider, Resource configurationLocation) {
this.configurationLocation = configurationLocation;
this.cachingProvider = cachingProvider;
}
public CacheManager getCacheManager() {
try {
return this.cachingProvider.getCacheManager(this.configurationLocation.getURI(), this.getClass().getClassLoader());
} catch (IOException ex) {
throw new RuntimeException("Missing configuration", ex);
}
}
}
and in Spring context:
<bean id="cacheManager" factory-bean="cacheManagerFactory" factory-method="getCacheManager" />
<bean id="cacheManagerFactory" class="com.test.CacheManagerFactory">
<constructor-arg name="cachingProvider" ref="cachingManagerProvider" />
<constructor-arg name="configurationLocation" value="/WEB-INF/ehcache.xml" />
</bean>
<bean id="cachingManagerProvider" class="org.ehcache.jsr107.EhcacheCachingProvider" />
The problem was specifying "/WEB-INF/ehcache.xml" as URI relative to webapp root as argument to org.ehcache.jsr107.EhcacheCachingProvider#getCacheManager() method.
Is it possible to inject without wrapper class?
Related
I'm new to Spring and trying to get a example to work. But my application loads twice each time it starts. I think it could be a context problem because of my internet research and I have just one context.xml.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:environment.properties</value>
</list>
</property>
<property name="ignoreUnresolvablePlaceholders" value="false"/>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:environment.properties</value>
</list>
</property>
<property name="ignoreUnresolvablePlaceholders" value="false"/>
</bean>
<bean name="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper" />
<bean name="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="requestFactory" ref="requestFactory" />
</bean>
<bean name="requestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<property name="connectTimeout" value="10000" />
<property name="readTimeout" value="10000" />
</bean>
<bean name="httpClient" class="org.apache.http.client.HttpClient" factory-bean="requestFactory" factory-method="getHttpClient"/>
<bean name="TraderApplication" class="net.mrmoor.TraderApplication"/>
<bean name="API" class="com.iggroup.api.API"/>
<bean name="LightStreamerComponent" class="com.iggroup.api.streaming.LightStreamerComponent"/>
</beans>
My code of the TraderApplication Class is:
... skipped imports ....
#SpringBootApplication
public class TraderApplication implements CommandLineRunner{
private static final Logger log = LoggerFactory.getLogger(TraderApplication.class);
#Autowired
protected ObjectMapper objectMapper;
#Autowired
private API api;
#Autowired
private LightStreamerComponent lightStreamerComponent = new LightStreamerComponent();
private AuthenticationResponseAndConversationContext authenticationContext = null;
private ArrayList<HandyTableListenerAdapter> listeners = new ArrayList<HandyTableListenerAdapter>();
public static void main(String args[]) {
SpringApplication.run(TraderApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
try {
if (args.length < 2) {
log.error("Usage:- Application identifier password apikey");
System.exit(-1);
}
String identifier = args[0];
String password = args[1];
String apiKey = args[2];
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/public-api-client-spring-context.xml");
TraderApplication app = (TraderApplication) applicationContext.getBean("TraderApplication");
app.run(identifier, password, apiKey);
} catch (Exception e) {
log.error("Unexpected error:", e);
}
}
You mention in your comments above you got this working by removing SpringApplication.run(TraderApplication.class, args); but this would be removing spring-boot from your application so I'm going to assume since your question has a tag of [spring-boot] that this is not what you wanted. So here is an alternative way that you can configure beans using your xml.
#ImportResource({"classpath*:public-api-client-spring-context.xml"}) //Proper way to import xml in Spring Boot
#SpringBootApplication
public class TraderApplication implements CommandLineRunner {
...code you had before goes here
#Autowired
TraderApplication app;
#Override
public void run(String... args) throws Exception {
.. your parsing logic here
app.run(identifier, password, apiKey); //Now uses the autowired instance
}
}
You didn't list your pom.xml or build.gradle but it's important to remember that components you have registered in your context xml may be automatically configured in Spring Boot and you may not need to register them yourself in your xml.(Depending on which items you have starters for in your build file)
I created dynamic web project in eclipse(Kepler).In my application, I used Spring,JMS,ActiveMQ & JSF. In my java class use following code to get defaultdestination define in bean xml.
import javax.jms.Message;
import javax.jms.TextMessage;
import org.springframework.jms.core.JmsTemplate;
public class JmsReceiver {
private JmsTemplate jmsTemplate;
public JmsTemplate getjmsTemplate() {
return jmsTemplate;
}
public void setjmsTemplate(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
public void processMessage() {
System.out.println("DefaultDestination :"+jmsTemplate.getDefaultDestination());
}
}
My bean definition is :
<bean id="defaultDestination" class="org.apache.activemq.command.ActiveMQQueue"></bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"></property>
<property name="defaultDestination"><ref bean="defaultDestination"/></property>
<property name="defaultDestinationName" value="myqueue"></property>
</bean>
But when running 'DefaultDestination: null' .
Pls guide me to solve this issue
<bean id="demoQueueDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg><!-- 设置消息队列的名字 -->
<value>Jaycekon</value>
</constructor-arg>
</bean>
ActiveMQDestination destination = (ActiveMQDestination) jmsTemplate.getDefaultDestination();
System.out.println(Thread.currentThread().getName() + " 向队列" + destination.getPhysicalName() + "发送消息---------------------->" + msg);
I have following xml configuration in my spring context xml, I have used annotation based approach very less and unable to figure out how to represent following using annotation, need help.
<bean id="myPolicyAdmin" class="org.springframework.security.oauth2.client.OAuth2RestTemplate">
<constructor-arg>
<bean class="org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails">
<property name="accessTokenUri" value="${accessTokenEndpointUrl}" />
<property name="clientId" value="${clientId}" />
<property name="clientSecret" value="${clientSecret}" />
<property name="username" value="${policyAdminUserName}" />
<property name="password" value="${policyAdminUserPassword}" />
</bean>
</constructor-arg>
</bean>
In my java class(Policy manager) it is referred as following, I am actually referring a sample and trying to convert it all annotation baesed.
#Autowired
#Qualifier("myPolicyAdmin")
private OAuth2RestTemplate myPolicyAdminTemplate;
EDIT:
I tried creating a bean for org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails but not sure how to set its properties and how to access it as constructor args to myPolicyAdminTemplate
You can configure the same beans using JavaConfig as follows:
#Component
#Configuration
public class AppConfig
{
#Value("${accessTokenEndpointUrl}") String accessTokenUri;
#Value("${clientId}") String clientId;
#Value("${clientSecret}") String clientSecret;
#Value("${policyAdminUserName}") String username;
#Value("${policyAdminUserPassword}") String password;
#Bean
public OAuth2RestTemplate myPolicyAdmin(ResourceOwnerPasswordResourceDetails details)
{
return new OAuth2RestTemplate(details);
}
#Bean
public ResourceOwnerPasswordResourceDetails resourceOwnerPasswordResourceDetails()
{
ResourceOwnerPasswordResourceDetails bean = new ResourceOwnerPasswordResourceDetails();
bean.setAccessTokenUri(accessTokenUri);
bean.setClientId(clientId);
bean.setClientSecret(clientSecret);
bean.setUsername(username);
bean.setPassword(password);
return bean;
}
}
To set the props of a bean you can either use #Value during construction:
How to inject a value to bean constructor using annotations
and this one:
Spring: constructor injection of primitive values (properties) with annotation based configuration
Or #Value in the variables. You could also actually use #Resource, but I wouldn't recommend it.
In your case, the constructor for the
org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails
Would be kinda like
#Autowired
public ResourceOwnerPasswordResourceDetails(
#Value("${accessTokenEndpointUrl}") String accessTokenUri,
#Value("${clientId}") String clientId,
#Value("${clientSecret}") String clientSecret,
#Value("${policyAdminUserName}") String username,
#Value("${policyAdminUserPassword}") String password
)
I shall give you a XML configuration with it anotation based config equivalent respectively, so that you will easily see how to change your bean from xml to java and vice-versa
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<context:component-scan base-package="com.mycompany.backendhibernatejpa.controller" />
<mvc:annotation-driven />
<bean id="iAbonneDao" class="com.mycompany.backendhibernatejpa.daoImpl.AbonneDaoImpl"/>
<bean id="iAbonneService" class="com.mycompany.backendhibernatejpa.serviceImpl.AbonneServiceImpl"/>
<!-- couche de persistance JPA -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
</bean>
</property>
<property name="loadTimeWeaver">
<bean
class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:bd.properties"/>
</bean>
<!-- la source de donnéees DBCP -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" >
<property name="driverClassName" value="${bd.driver}" />
<property name="url" value="${bd.url}" />
<property name="username" value="${bd.username}" />
<property name="password" value="${bd.password}" />
</bean>
<!-- le gestionnaire de transactions -->
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- traduction des exceptions -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<!-- annotations de persistance -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
</beans>
this file is named springrest-sevlet. actually you can give the name you want followed by "-servlet" and mention that name in the file web.xml
<web-app>
<display-name>Gescable</display-name>
<servlet>
<servlet-name>springrest</servlet-name>
<servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springrest</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
the two files should be place in the folder "WEB-INF".
Now the equivalent with anotation based config
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.mycompany.backendhibernatejpaannotation.configuration;
import com.mycompany.backendhibernatejpaannotation.daoImpl.AbonneDaoImpl;
import com.mycompany.backendhibernatejpaannotation.daoInterface.IAbonneDao;
import com.mycompany.backendhibernatejpaannotation.serviceImpl.AbonneServiceImpl;
import com.mycompany.backendhibernatejpaannotation.serviceInterface.IAbonneService;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
/**
*
* #author vivien saa
*/
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.mycompany.backendhibernatejpaannotation")
public class RestConfiguration {
#Bean
public IAbonneDao iAbonneDao() {
return new AbonneDaoImpl();
}
#Bean
public IAbonneService iAbonneService() {
return new AbonneServiceImpl();
}
// #Bean
// public PropertyPlaceholderConfigurer placeholderConfigurer() {
// PropertyPlaceholderConfigurer placeholderConfigurer = new PropertyPlaceholderConfigurer();
// placeholderConfigurer.setLocations("classpath:bd.properties");
// return placeholderConfigurer;
// }
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/gescable");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
#Bean
public HibernateJpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect");
jpaVendorAdapter.setGenerateDdl(true);
jpaVendorAdapter.setShowSql(true);
return jpaVendorAdapter;
}
#Bean
public InstrumentationLoadTimeWeaver loadTimeWeaver() {
InstrumentationLoadTimeWeaver loadTimeWeaver = new InstrumentationLoadTimeWeaver();
return loadTimeWeaver;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(dataSource());
entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter());
entityManagerFactory.setLoadTimeWeaver(loadTimeWeaver());
return entityManagerFactory;
}
#Bean
public JpaTransactionManager jpaTransactionManager() {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return jpaTransactionManager;
}
#Bean
public PersistenceExceptionTranslationPostPro`enter code here`cessor persistenceExceptionTranslationPostProcessor() {
return new PersistenceExceptionTranslationPostProcessor();
}
#Bean
public PersistenceAnnotationBeanPostProcessor persistenceAnnotationBeanPostProcessor() {
return new PersistenceAnnotationBeanPostProcessor();
}
}
this file must be accompanied by this one
package com.mycompany.backendhibernatejpaannotation.configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
*
* #author vivien saa
*/
public class Initializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{RestConfiguration.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
I have weird situation.
I tried to create new bean while using the #Configuration an #Bean this way:
package com.spring.beans.ParkingCar;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class CarMaker
{
#Bean
public CarBean createNewCar()
{
CarBean carBean=new CarBean();
return carBean;
}
}
package com.spring.beans.ParkingCar;
import org.apache.log4j.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class CarBean
{
private int x = 3;
static Logger logger = Logger.getLogger(CarBean.class);
public void driveCar()
{
logger.debug("I am driving my car" + x);
}
}
and then my test class looks like this:
public static void execute()
{
try
{
PropertyConfigurator.configure("log4j.properties");
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
CarMaker carMaker = (CarMaker) context.getBean("carMaker");
CarBean carBean = carMaker.createNewCar();
carBean.driveCar();
}
catch (Throwable e)
{
logger.error(e);
}
}
my applicationContext.xml looks like this:
<?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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- Must for auto wiring
<context:annotation-config />
-->
<context:component-scan
base-package="com.spring.beans.ParkingCar">
</context:component-scan>
<aop:aspectj-autoproxy />
<bean id="Spring3HelloWorldBean" class="com.spring.aspect.Spring3HelloWorld">
<property name="myname" value="idan" />
</bean>
<bean id="SecurityAspect" class="com.spring.aspect.SecurityAspect">
</bean>
<bean id="CalculateStrategyBean" class="com.spring.beans.calculator.CalculateStrategyBean">
<constructor-arg value="plus" />
</bean>
<bean id="CalculatorBean" class="com.spring.beans.calculator.CalculatorBean">
<constructor-arg ref="CalculateStrategyBean" />
<constructor-arg ref="CalculateNumbersHolderBean" />
</bean>
<bean id="CalculateNumbersHolderBean" class="com.spring.beans.calculator.CalculateNumbersHolderBean">
<constructor-arg value="10" />
<constructor-arg value="20" />
</bean>
<bean id="lisenceDrive" class="com.spring.beans.ParkingCar.LisenceDrive"
p:carLisenceNum="333" p:isValidateCar="true" />
<bean id="AmbulancelisenceDrive" class="com.spring.beans.ParkingCar.LisenceDrive"
p:carLisenceNum="999" p:isValidateCar="false" />
<bean id="TransitlisenceDrive" class="com.spring.beans.ParkingCar.LisenceDrive"
p:carLisenceNum="111" p:isValidateCar="false" />
<bean id="TransitVechileDetails" class="com.spring.beans.ParkingCar.VechileDetails"
p:modelName="Transit-AS" p:numOfWheels="4" p:year="1992" />
<!-- Wiring without annotations-->
<!--
<bean id="Ambulance"
class="com.spring.beans.ParkingCar.FourWheelsVechile"
p:modelName="GMC" p:numOfWheels="4" p:year="1997"
p:lisenceDrive-ref="AmbulancelisenceDrive" /> <bean id="Bike"
class="com.spring.beans.ParkingCar.TwoWheelsVechile" autowire="byName"
p:modelName="T-BIRD" p:numOfWheels="2" p:year="2012" /> <bean
id="Transit" class="com.spring.beans.ParkingCar.FourWheelsVechile"
p:lisenceDrive-ref="TransitlisenceDrive" autowire="constructor">
-->
<bean id="Ambulance" class="com.spring.beans.ParkingCar.FourWheelsVechile"
p:modelName="GMC" p:numOfWheels="4" p:year="1997" p:lisenceDrive-ref="AmbulancelisenceDrive" />
<!-- Wiring with annotations
<bean id="Bike" class="com.spring.beans.ParkingCar.TwoWheelsVechile"
autowire="byName" p:modelName="T-BIRD" p:numOfWheels="2" p:year="2012" />
<bean id="Transit" class="com.spring.beans.ParkingCar.FourWheelsVechile"
p:lisenceDrive-ref="TransitlisenceDrive">
</bean>
-->
</beans>
Now when I ran it on MyEclipse thru main it worked just fine. but when I uploaded it to my stand alone application which is running on Linux I got:
2012-07-01 14:11:21,152 com.spring.test.Spring3HelloWorldTest [ERROR] org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'carMaker' is defined
Any idea why it didn't work there?
Thanks.
#Configuration indicates that a class declares one or more #Bean methods while #Bean creates a new bean which have same name as the name of the method annotated with #Bean .
In your code sample bean with name createNewCar will be created as method createNewCar() method is annotated by #Bean.
Try this
CarBean carBean = (CarBean) context.getBean("createNewCar");
carBean.driveCar();
Few things to look at
Why to annotate class CarBean as #Configuration? It dont contain any bean defination ie. method with #Bean annotation.
Why to invoke createNewCar() method as it is already annotated with #Bean? (Let Spring do its work)
Check this link it will help you to get familiar with #Configuration and #Bean annotation.
I currently have my ldap authentication context set up like this:
<ldap-server url="ldap://host/dn"
manager-dn="cn=someuser"
manager-password="somepass" />
<authentication-manager>
<ldap-authentication-provider user-search-filter="(samaccountname={0})"/>
</authentication-manager>
Now, I need to be able to set up a custom authorities mapper (it uses a different ldap server) - so I am assuming I need to set up my ldap-server similar to (http://static.springsource.org/spring-security/site/docs/2.0.x/reference/ldap.html):
<bean id="ldapAuthProvider"
class="org.springframework.security.providers.ldap.LdapAuthenticationProvider">
<constructor-arg>
<bean class="org.springframework.security.providers.ldap.authenticator.BindAuthenticator">
<constructor-arg ref="contextSource"/>
<property name="userDnPatterns">
<list><value>uid={0},ou=people</value></list>
</property>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator">
<constructor-arg ref="contextSource"/>
<constructor-arg value="ou=groups"/>
<property name="groupRoleAttribute" value="ou"/>
</bean>
</constructor-arg>
</bean>
But, how do I reference that 'ldapAuthProvider' to the ldap-server in the security context?
I am also using spring-security 3, so '' does not exist...
What I have done to make it work was simply to add this into the security context:
<authentication-manager>
<authentication-provider ref='ldapAuthProvider'/>
</authentication-manager>
And then, configuring the 'ldapAuthProvider' bean like this:
<bean id="contextSource"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="ldaps://url/dc=mock,dc=com" />
<property name="userDn" value="cn=username,ou=People,dc=mock,dc=com" />
<property name="password" value="password" />
</bean>
<bean id="ldapAuthProvider"
class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<constructor-arg>
<bean
class="org.springframework.security.ldap.authentication.BindAuthenticator">
<constructor-arg ref="contextSource" />
<property name="userDnPatterns">
<list>
<value>uid={0},ou=People</value>
</list>
</property>
</bean>
</constructor-arg>
<constructor-arg>
<bean
class="com.mock.MyCustomAuthoritiesPopulator">
</bean>
</constructor-arg>
</bean>
With the implementation of MyCustomAuthoritiesPopulator as follows:
public class MyCustomAuthoritiesPopulator implements LdapAuthoritiesPopulator {
public Collection<GrantedAuthority> getGrantedAuthorities(
DirContextOperations arg0, String arg1) {
ArrayList<GrantedAuthority> list = new ArrayList<GrantedAuthority>();
list.add((new SimpleGrantedAuthority("ROLE_USER"));
return list;
}
}
For the record spring configuration is simpler if you use a custom LdapUserDetailsMapper as there's a dedicated parameter user-context-mapper-ref exposed on <ldap-authentication-provider/> which allows you to use the short config style:
<authentication-manager>
<ldap-authentication-provider
user-search-filter="sAMAccountName={0}"
user-search-base="OU=Users"
group-search-filter="(&(objectclass=group)(member={0}))"
group-search-base="OU=Groups"
user-context-mapper-ref="customUserContextMapper" />
</authentication-manager>
<ldap-server url="ldap://url:389/DC=mock,DC=com"
manager-dn="manager"
manager-password="pass" />
Source: http://forum.springsource.org/showthread.php?118845-How-to-modify-Authority-after-loading-it-from-LDAP
On a side note, going the LdapAuthoritiesPopulator route you can also extend DeafultLdapAuthoritiesPopulator and override getAdditionalRoles() rather than implementing the interface directly.
public class MyCustomAuthoritiesPopulator extends
DefaultLdapAuthoritiesPopulator {
#Override
protected Set<GrantedAuthority> getAdditionalRoles(
DirContextOperations user, String username) {
Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
authorities.add((new SimpleGrantedAuthority("ROLE_USER"));
return authorities;
}
If you want to avoid ugly bean definitions (DefaultSpringSecurityContextSource, LdapAuthenticationProvider, BindAuthenticator,...+100) and use "cool" xml definitions like
<authentication-manager>
<ldap-authentication-provider... />
</authentication-manager>
You can use a BeanPostProcessor. The following example is a costumization of the GrantedAuthoritiesMapper in the AuthenticationProvider:
[context.xml]
<ldap-server id="ldapServer" url="${ldap.url}" manager-dn="${ldap.manager.dn}" manager-password="${ldap.manager.password}"/>
<authentication-manager>
<ldap-authentication-provider user-search-filter="${ldap.userSearch.filter}" user-search-base="${ldap.searchBase}"
group-search-base="${ldap.groupSearchBase}"/>
</authentication-manager>
[UserGrantedAuthoritiesMapper.java]
package com.example.access.ldap;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.stereotype.Component;
#Component
public class UserGrantedAuthoritiesMapper implements GrantedAuthoritiesMapper{
public Collection<? extends GrantedAuthority> mapAuthorities(final Collection<? extends GrantedAuthority> authorities) {
...
return roles;
}
}
[AuthenticationProviderPostProcessor.java]
package com.example.access.ldap;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider;
import org.springframework.stereotype.Component;
#Component
public class AuthenticationProviderPostProcessor implements BeanPostProcessor{
#Autowired
private GrantedAuthoritiesMapper grantedAuthoritiesMapper;
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if(bean != null && bean instanceof AbstractLdapAuthenticationProvider){
setProviderAuthoritiesMapper((AbstractLdapAuthenticationProvider)bean);
}
return bean;
}
protected void setProviderAuthoritiesMapper(AbstractLdapAuthenticationProvider authenticationProvider){
if(authenticationProvider != null){
authenticationProvider.setAuthoritiesMapper(grantedAuthoritiesMapper);
}
}
}