I have my spring integration http outbound gateway something like this.I am using my own rest template for pooling connection with ssl.I was getting 500 with french character hence I am injecting both UTF-8 and supported media type to message converter.Now Before I was injecting my own request factory and default rest template After injecting both then it started accepting french characters.Now when i changed to use my own rest template it don't accept message converter and when i try to inject this to my rest template I get this exception
Cause is - Could not write request: no suitable HttpMessageConverter found for request type [java.lang.String] and content type [text/plain;charset=UTF-8]
This worked for all request
<int-http:outbound-gateway id='batch-http' header-mapper="headerMapper"
request-channel='toHttp'
request-factory="requestFactory"
message-converters="batchHTTPConverter"
url-expression="payload.contains('${filterAttribute}') ? '${url1}' : '${url2}'" http-method="${httpMethod}"
expected-response-type='java.lang.String' charset='${charset}'
reply-timeout='${replyTimeout}' reply-channel='output'>
</int-http:outbound-gateway>
<beans:bean id="batchHTTPConverter" class="org.springframework.http.converter.StringHttpMessageConverter">
<beans:constructor-arg index="0" value="UTF-8"/>
<beans:property name="supportedMediaTypes" value = "application/json;UTF-8" />
</beans:bean>
<beans:bean id="requestFactory" class="test.batch.httpclient.CustomClientHttpRequestFactory">
<beans:constructor-arg ref="verifier"/>
</beans:bean>
<beans:bean id="verifier"
class="batch.NullHostnameVerifier">
</beans:bean>
This is not working for french or any input request
<header-filter input-channel="input"
output-channel="inputX" header-names="x-death"/>
<service-activator input-channel="inputX" ref="gw" />
<gateway id="gw" default-request-channel="toHttp" default-reply-timeout="0" error-channel="errors" />
<beans:bean id="inputfields" class="testbatch.httpclient.HTTPInputProperties">
<beans:property name="nonRetryErrorCodes" value="${nonRetryErrorCodes}"/>
</beans:bean>
<beans:bean id="responseInterceptor" class="testbatch.httpclient.ResponseInterceptor">
<beans:property name="inputProperties" ref="inputfields" />
</beans:bean>
<chain input-channel="errors" output-channel="output">
<!-- examine payload.cause (http status code etc) and decide whether
to throw an exception or return the status code for sending to output -->
<header-filter header-names="replyChannel, errorChannel" />
<transformer ref="responseInterceptor" />
</chain>
<int-http:outbound-gateway id='batch-http' header-mapper="headerMapper"
request-channel='toHttp'
rest-template="batchRestTemplate"
url-expression="payload.contains('${filterAttribute}') ? '${url1}' : '${url2}'" http-method="${httpMethod}"
expected-response-type='java.lang.String' charset='${charset}'
reply-timeout='${replyTimeout}' reply-channel='output'>
</int-http:outbound-gateway>
<beans:bean id="batchHTTPConverter" class="org.springframework.http.converter.StringHttpMessageConverter" >
<beans:constructor-arg index="0" value="UTF-8"/>
<beans:property name="supportedMediaTypes" value = "application/json;UTF-8" />
</beans:bean>
<beans:bean id="batchRestTemplate" class="testbatch.httpclient.BatchRestTemplate" >
<beans:property name="batchHTTPConverter" ref="batchHTTPConverter"/>
</beans:bean>
<beans:bean id="requestFactory"
class="testbatch.httpclient.CustomClientHttpRequestFactory">
<beans:constructor-arg ref="verifier"/>
</beans:bean>
<beans:bean id="verifier"
class="testbatch.httpclient.NullHostnameVerifier">
</beans:bean>
<beans:bean id="headerMapper" class="org.springframework.integration.http.support.DefaultHttpHeaderMapper"
factory-method="outboundMapper">
<beans:property name="outboundHeaderNames" value="${mapHeaders}"/>
<beans:property name="userDefinedHeaderPrefix" value=""/>
</beans:bean>
<channel id="output" />
<channel id="input" />
<channel id="inputX" />
<channel id="toHttp" />
</beans:beans>
My rest template
public class BatchRestTemplate extends RestTemplate{
private static final Logger LOGGER = LoggerFactory
.getLogger(BatchRestTemplate.class);
private StringHttpMessageConverter batchHTTPConverter;
public StringHttpMessageConverter getBatchHTTPConverter() {
return batchHTTPConverter;
}
public void setBatchHTTPConverter(StringHttpMessageConverter batchHTTPConverter) {
this.batchHTTPConverter = batchHTTPConverter;
}
public BatchRestTemplate() {
super(createBatchHttpRequestFactory());
List<HttpMessageConverter<?>> messageConverters= new ArrayList<HttpMessageConverter<?>>();
messageConverters.addAll(getMessageConverters());
messageConverters.add(getBatchHTTPConverter());
super.setMessageConverters(messageConverters);
}
private static ClientHttpRequestFactory createBatchHttpRequestFactory() {
CloseableHttpClient httpClient;
HttpComponentsClientHttpRequestFactory httpRequestFactory;
final int timeout = 3000;
SSLConnectionSocketFactory socketFactory;
try {
socketFactory = new SSLConnectionSocketFactory(
SSLContext.getDefault(),
new String[] {"TLSv1"},
null,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", socketFactory)
.build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
cm.setMaxTotal(700);
cm.setDefaultMaxPerRoute(300);
cm.closeExpiredConnections();
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(timeout)
.setConnectionRequestTimeout(timeout).setSocketTimeout(timeout).build();
httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).setConnectionManager(cm).build();
httpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
return httpRequestFactory;
}
catch (Exception e) {
LOGGER.debug("error exception", e);
}
return null;
}
}
You have a bug in your own code:
public BatchRestTemplate() {
..........
messageConverters.add(getBatchHTTPConverter());
..........
}
But... There is no batchHTTPConverter yet!. It will appear there only after setBatchHTTPConverter().
In other words you can't use the property from the constructor because setters are called latter after the object instantiating.
Related
when i am running spring integration SFTP with zookeeper: Facing issue while file metada put in metadatastore. i have mention below code.
Below is my configuration
<beans:bean id="compositeFilter"
class="org.springframework.integration.file.filters.ChainFileListFilter">
<beans:constructor-arg >
<beans:set>
<beans:bean
class="org.springframework.integration.sftp.filters.SftpRegexPatternFileListFilter">
<beans:constructor-arg value="^.*\.(dat|DAT)$" />
</beans:bean>
<beans:bean
class="org.springframework.integration.sftp.filters.SftpPersistentAcceptOnceFileListFilter">
<beans:constructor-arg name="store"
ref="metadataStore" />
<beans:constructor-arg value="filterprefix" />
</beans:bean>
</beans:set>
</beans:constructor-arg>
</beans:bean>
<beans:bean id="zookeeperClient"
class="org.springframework.integration.zookeeper.config.CuratorFrameworkFactoryBean">
<beans:constructor-arg value="${zookeeper.server.uri}" />
</beans:bean>
<beans:bean id="metadataStore"
class="org.springframework.integration.zookeeper.metadata.ZookeeperMetadataStore">
<beans:constructor-arg ref="zookeeperClient" />
<beans:property name="root" value="/metaDataStore" />
</beans:bean>
Below are the exception trace which I am getting. when i run above program i am getting following error.
Caused by:
Caused by: java.lang.IllegalArgumentException: Invalid path string "/AtdFaureciaMetaDataStore/.." caused by relative paths not allowed #27
at org.apache.curator.utils.PathUtils.validatePath(PathUtils.java:102)
at org.apache.curator.utils.PathUtils.validatePath(PathUtils.java:37)
at org.apache.curator.utils.ZKPaths.fixForNamespace(ZKPaths.java:105)
at org.apache.curator.framework.imps.NamespaceImpl.fixForNamespace(NamespaceImpl.java:104)
at org.apache.curator.framework.imps.CuratorFrameworkImpl.fixForNamespace(CuratorFrameworkImpl.java:599)
at org.apache.curator.framework.imps.CreateBuilderImpl.forPath(CreateBuilderImpl.java:458)
at org.apache.curator.framework.imps.CreateBuilderImpl.forPath(CreateBuilderImpl.java:44)
at org.springframework.integration.zookeeper.metadata.ZookeeperMetadataStore.createNode(ZookeeperMetadataStore.java:257)
at org.springframework.integration.zookeeper.metadata.ZookeeperMetadataStore.putIfAbsent(ZookeeperMetadataStore.java:119)
Consider to use ChainFileListFilter instead of CompositeFileListFilter:
**
* The {#link CompositeFileListFilter} extension which chains the result
* of the previous filter to the next one. If a filter in the chain returns
* an empty list, the remaining filters are not invoked.
*
* #param <F> The type that will be filtered.
*
* #author Artem Bilan
* #author Gary Russell
*
* #since 4.3.7
*
*/
public class ChainFileListFilter<F> extends CompositeFileListFilter<F> {
It doesn’t pass discarded files to the next filters in chain.
On the other hand really consider some non-empty prefix for the SftpPersistentAcceptOnceFileListFilter to avoid that relative path error.
i have used sftp:inbound-streaming-channel-adapter with zookeeper.but it is giving me exception : java.lang.ClassCastException: com.jcraft.jsch.ChannelSftp$LsEntry cannot be cast to java.io.File. I am using the following code
<int-sftp:inbound-streaming-channel-adapter
id="sftpAdapter" channel="receiveChannel"
session-factory="cachingSessionFactory"
remote-file-separator="/" remote-directory-expression="'${ftpServerLoc}'" filter="compositeFilter"
auto-startup="true">
<int:poller fixed-rate="${pollarInterval}"
max-messages-per-poll="1" />
</int-sftp:inbound-streaming-channel-adapter>
<beans:bean id="compositeFilter"
class="org.springframework.integration.file.filters.CompositeFileListFilter">
<beans:constructor-arg>
<beans:list>
<beans:bean
class="org.springframework.integration.file.filters.RegexPatternFileListFilter">
<beans:constructor-arg value="^.*\.(dat|DAT)$" />
</beans:bean>
<beans:bean
class="org.springframework.integration.sftp.filters.SftpPersistentAcceptOnceFileListFilter">
<beans:constructor-arg name="store"
ref="metadataStore" />
<beans:constructor-arg value="" />
</beans:bean>
</beans:list>
</beans:constructor-arg>
</beans:bean>
The org.springframework.integration.file.filters.RegexPatternFileListFilter should be org.springframework.integration.sftp.filters.SftpRegexPatternFileListFilter.
The one you have applies to java.io.File; the sftp version applies to LsEntry (Jsch's representation of the remote file).
I have spring xd component called throttle where i store the messages and post are and throttle them and send them slowly.I am running my xd in 3 containers.I have holding delay for delayer as 0.When one container goes down.I loose messages.Below is my configuration.Looks like its not storing to postgre and loosing in memory or cache.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:int-groovy="http://www.springframework.org/schema/integration/groovy"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:ehcache="http://www.springframework.org/schema/cache"
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-4.0.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/integration/jdbc
http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd
http://www.springframework.org/schema/integration/groovy
http://www.springframework.org/schema/integration/groovy/spring-integration-groovy.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.1.xsd">
<ehcache:annotation-driven cache-manager="cacheManager" />
<context:property-placeholder
location="classpath*:dms-security-${region}.properties, classpath*:dms-jms-${region}.properties, classpath*:dms-mongo-${region}.properties" />
<context:component-scan base-package="com.testhrottle.api.dms.*"
use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.context.annotation.Configuration" />
</context:component-scan>
<channel id="input">
<!-- <interceptors>
<ref bean="messageInterceptor" />
</interceptors> -->
</channel>
<channel id="output" />
<channel id="sms" />
<channel id="eml" />
<channel id="del" />
<!-- <header-value-router input-channel="input" header-name="Channel-Type" >
<mapping value="PHN" channel="sms" />
<mapping value="EML" channel="eml" />
<mapping value="DEL" channel="del" />
</header-value-router> -->
<router input-channel="input">
<beans:bean name="messageRouter" class="com.testhrottle.xd.util.MessageRouter">
<beans:property name="cache" ref="configCache" />
</beans:bean>
</router>
<service-activator input-channel="del" ref="delete" method="delete"/>
<filter input-channel="eml" output-channel="output">
<beans:bean class="com.testhrottle.xd.throttle.Throttle">
<beans:constructor-arg value="${tpsThreshold}" />
<beans:constructor-arg value="${spanSeconds}" />
<beans:property name="cache" ref="configCache" />
<beans:property name="dailyLimitCounter" ref="dailyLimitCounter" />
<beans:property name="errorPublishing" ref="errorPublishing" />
</beans:bean>
</filter>
<filter input-channel="sms" output-channel="output">
<beans:bean class="com.testhrottle.xd.throttle.SmsThrottle">
<beans:constructor-arg value="${smsTpsThreshold}" />
<beans:constructor-arg value="${smsSpanSeconds}" />
<beans:property name="cache" ref="configCache" />
<beans:property name="dailyLimitCounter" ref="dailyLimitCounter" />
<beans:property name="errorPublishing" ref="errorPublishing" />
</beans:bean>
</filter>
<channel id="requeue">
<dispatcher task-executor="taskExecutor" />
</channel>
<task:executor id="taskExecutor" pool-size="1" />
<delayer id="delayer" input-channel="requeue" default-delay="${holdingDelay}"
expression="headers['delay']" message-store="messageStore"
output-channel="input" />
<!-- <int-jdbc:message-store id="messageStore" data-source="dataSource" /> -->
<beans:bean id="messageStore" class="com.testhrottle.xd.util.CustomJdbcMessageStore">
<beans:constructor-arg ref="dataSource"/>
</beans:bean>
<!-- <beans:bean name="messageInterceptor" class="com.testhrottle.xd.util.MessageInterceptor">
<beans:property name="cache" ref="configCache" />
</beans:bean> -->
<beans:bean name="configCache"
class="com.testhrottle.xd.cache.ConfigCache">
<beans:property name="jdbcTemplate" ref="jdbcTemplate" />
<beans:property name="holdRetryIntervelInSeconds" value="${holdRetryIntervelInSeconds}" />
<beans:property name="configQuery" value="select alrt_type_cd alertType,dlvry_days_of_week daysOfWeek,DLVRY_STRT_TM startTime,DLVRY_END_TM endTime,DLVRY_STRT_DT startDate,DLVRY_END_DT endDate,hold_ind holdFlag, max_msgs_per_day maxMsgPerDay,purge_ind purge from ${schema}.alrt_type where alrt_type_cd = ?" />
</beans:bean>
<beans:bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName" value="org.postgresql.Driver"/>
<beans:property name="url" value="${dbURL}"/>
<beans:property name="username" value="${userName}"/>
<beans:property name="password" value="#{encryptedDatum.decryptBase64Encoded('${passWord}')}"/>
</beans:bean>
<beans:bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<beans:property name="dataSource">
<beans:ref bean="dataSource" />
</beans:property>
</beans:bean>
<beans:bean id="encryptedDatum" class="com.testhrottle.api.dms.core.security.EncryptedSecuredDatum"/>
<!-- <beans:bean id="rabbitTemplate" class="org.springframework.amqp.rabbit.core.RabbitTemplate"/> -->
<beans:bean id="errorPublishing" class="com.testhrottle.xd.util.ErrorPublishing">
<!-- <beans:property name="rabbitTemplate" ref="rabbitTemplate" /> -->
</beans:bean>
<beans:bean id="delete" class="com.testhrottle.xd.util.Delete"/>
<!--
<beans:bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName" value="org.postgresql.Driver"/>
<beans:property name="url" value="jdbc:postgresql://localhost:5432/postgres"/>
<beans:property name="username" value="postgres"/>
<beans:property name="password" value="postgres"/>
</beans:bean>
<beans:bean name="configCache"
class="com.testhrottle.xd.cache.ConfigCache">
<beans:property name="jdbcTemplate" ref="jdbcTemplate" />
<beans:property name="holdRetryIntervelInSeconds" value="10" />
<beans:property name="configQuery" value="select alrt_type_cd alertType,dlvry_days_of_week daysOfWeek,DLVRY_STRT_TM startTime,DLVRY_END_TM endTime,DLVRY_STRT_DT startDate,DLVRY_END_DT endDate,hold_ind holdFlag, max_msgs_per_day maxMsgPerDay from dms_wb.alrt_type where alrt_type_cd = ?;
" />
</beans:bean>
<beans:bean name="cacheTest"
class="com.testhrottle.xd.cache.CacheTest">
<beans:property name="cache" ref="configCache" />
</beans:bean> -->
<beans:bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<beans:bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<beans:property name="cacheManager" ref="ehcache" />
</beans:bean>
<beans:bean id="ehcache"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<beans:property name="configLocation" value="classpath:ehcache.xml" />
<beans:property name="shared" value="true" />
</beans:bean>
<beans:bean name="dailyLimitCounter" class="com.testhrottle.xd.throttle.DailyLimitCounter"/>
<task:scheduler id="taskSchedulerInbound" pool-size="10" />
<task:scheduled-tasks>
<task:scheduled ref="dailyLimitCounter" method="clearAlertDailyCount" cron="59 59 23 * * *" />
</task:scheduled-tasks>
</beans:beans>
so if i remove this it should work in same thread.
<channel id="requeue">
<dispatcher task-executor="taskExecutor" />
</channel>
<task:executor id="taskExecutor" pool-size="1" />
Looks like your <dispatcher task-executor="taskExecutor" /> is guilty.
Since you jump out of the Message Bus thread, that acks (commits) the message on the Broker, but the crash of the node doesn't effect that already (rallback), because your message has been moved to different thread. And there it hasn't reached your DB to be commited there, too.
In general it would be better to do everything in the Spring XD withing container's (XD) threads and rely on the Message Bus persistent mechanism.
Or commit messages to DB manually, but in the same XD thread.
Makes sense?
I have implemented the DynamicFtpChannelResolver found in the spring integration samples in order to allow dynamic FTP locations in my integration app.
As part of the outbound adapter I have added an advice chain. The FtpCompleteAdvice requires access to an existing service bean but at runtime this is not injected presumably because the context is dynamically created.
Is there a way for autowiring to work or another way to get access to this service bean?
Here is an extract of the xml:
<int:channel id="toFtpChannel" />
<bean id="ftpClientFactory" class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<property name="host" value="${host}" />
<property name="port" value="${port}" />
<property name="user" value="${user}" />
<property name="password" value="${password}" />
</bean>
<int-sftp:outbound-channel-adapter id="ftpOutbound" session-factory="ftpClientFactory" channel="toFtpChannel" remote-directory="${remote.directory}" remote-file-separator="/" remote-filename-generator-expression="headers.filename">
<int-sftp:request-handler-advice-chain>
<bean class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice">
<property name="retryTemplate" ref="retryTemplate" />
</bean>
<bean class="com.bstonetech.ptms.integration.util.FtpCompleteAdvice">
<property name="interfaceType" value="OUTBOUND" />
<property name="interfaceName" value="TEST" />
</bean>
</int-sftp:request-handler-advice-chain>
</int-sftp:outbound-channel-adapter>
<bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
<property name="retryPolicy">
<bean class="org.springframework.retry.policy.SimpleRetryPolicy">
<property name="maxAttempts" value="3" />
</bean>
</property>
<property name="backOffPolicy">
<bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
<property name="maxInterval" value="600000" />
<property name="initialInterval" value="3000" />
<property name="multiplier" value="2" />
</bean>
</property>
</bean>
public class FtpCompleteAdvice extends AbstractRequestHandlerAdvice {
#Autowired
private IEmailUtilities emailUtilities;
#Autowired
private IFileService fileService;
private String interfaceType;
private String interfaceName;
public void setInterfaceType(String interfaceType) {
this.interfaceType = interfaceType;
}
public void setInterfaceName(String interfaceName) {
this.interfaceName = interfaceName;
}
#Override
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) throws Exception {
Object result = callback.execute();
String filename = (String)message.getHeaders().get("filename");
//insert ftp row into file_ctl
fileService.insertFtpFile(filename, interfaceName, interfaceType, new Date());
//send email to confirm ftp
emailUtilities.afterFtp(filename, interfaceName);
return result;
}
}
You need to make the new context a child of the main context that has those beans. This is discussed in the forum posts referenced in the sample's README, when using a similar technique for inbound endpoints.
Then, any beans in the parent context are available for wiring.
I have a <password-encoder> and CustomDetailService refered in AuthenticationManager. I added the following bean in spring-security after all the other security filters (concurrency, customLogoutFilter, etc.,) and <http auto-config="false" ..>:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org
/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<!-- Disable annotation-based method security -->
<global-method-security secured-annotations="disabled" />
<beans:bean id="sessionRegistry"
class="org.springframework.security.core.session.SessionRegistryImpl" />
<!-- Service that provides user credentials for use by the authentication provider -->
<beans:bean id="customDetailService" class="xxx.security.CustomDetailService" />
<!-- Assign the user details service to the default authentication provider -->
<beans:bean class="xxx.security.XyzPasswordEncoder" id="passwordEncoder" />
<!-- Get an alias to the default authentication manager -->
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="customDetailService">
<password-encoder ref="passwordEncoder" />
</authentication-provider>
</authentication-manager>
<!-- Register an exception filter that takes an entry point -->
<beans:bean id="exceptionTranslationFilter"
class="org.springframework.security.web.access.ExceptionTranslationFilter">
<beans:property name="authenticationEntryPoint" ref="authenticationEntryPoint" />
<beans:property name="accessDeniedHandler" ref="accessDeniedHandler" />
</beans:bean>
<beans:bean id="authenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/public/auth/login.htmlx" />
</beans:bean>
<beans:bean id="accessDeniedHandler"
class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
<beans:property name="errorPage" value="/error/access-denied.jsp" />
</beans:bean>
<!-- Register a custom authentication filter and register success/failure
handlers -->
<beans:bean id="customAuthenticationFilter"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="sessionAuthenticationStrategy"
ref="concurrentSessionControlStrategy" />
<beans:property name="authenticationSuccessHandler"
ref="loginSuccessHandler" />
<beans:property name="authenticationFailureHandler"
ref="loginFailureHandler" />
</beans:bean>
<beans:bean id="concurrentSessionControlStrategy"
class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">
<beans:constructor-arg name="sessionRegistry"
ref="sessionRegistry" />
</beans:bean>
<beans:bean id="loginSuccessHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl" value="/LoginSuccess" />
</beans:bean>
<beans:bean id="loginFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl" value="/LoginFailed" />
</beans:bean>
<!-- Register a custom logout filter -->
<beans:bean id="customLogoutFilter" class="xxx.security.LogoutFilterWrapper">
<beans:property name="logoutSuccessfulUrl" value="/public/auth/login.htmlx" />
<beans:property name="logoutSuccessfulUrlAdmin" value="/public/auth/admlogin.htmlx" />
<beans:property name="logoutSuccessfulUrlInactivity"
value="/public/auth/timedout.htmlx" />
</beans:bean>
<!-- Register a concurrent session filter. This will limit the number of
sessions a user can have -->
<beans:bean id="concurrencyFilter"
class="org.springframework.security.web.session.ConcurrentSessionFilter">
<beans:property name="sessionRegistry" ref="sessionRegistry" />
<beans:property name="expiredUrl"
value="/public/error/multi-login-not-supported.htmlx" />
</beans:bean>
<!-- Register a filter to log in as a different user -->
<beans:bean id="switchUserProcessingFilter" class="org.springframework.security.web.authentication.switchuser.SwitchUserFilter">
<beans:property name="userDetailsService" ref="customDetailService" />
<beans:property name="switchUserUrl" value="/j_spring_security_switch_user" />
<beans:property name="exitUserUrl" value="/j_spring_security_exit_user" />
<beans:property name="targetUrl" value="/" />
</beans:bean>
<http auto-config="false" entry-point-ref="authenticationEntryPoint">
<custom-filter position="FORM_LOGIN_FILTER" ref="customAuthenticationFilter" />
<custom-filter position="LOGOUT_FILTER" ref="customLogoutFilter" />
<custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
<custom-filter position="SWITCH_USER_FILTER" ref="switchUserProcessingFilter" />
<session-management session-fixation-protection="none" />
<!-- Configure the filter security interceptor. URL patterns default to
Apache Ant path syntax -->
<intercept-url pattern="/**/xyz_product*" access="ROLE_XYZ_PRODUCT" />
<intercept-url pattern="/root/user/index.htmlx" access="ROLE_XYZ_PRODUCT" />
<!-- Allow unrestrictricted access to assets -->
<intercept-url pattern="/assets/**" filters="none" />
<!-- Allow unrestrictricted access to public areas -->
<intercept-url pattern="/public/**" filters="none" />
<!-- Allow unrestrictricted access to generated resources -->
<intercept-url pattern="/faces/**" filters="none" />
<!-- Enforce role-based access for login success servlet -->
<intercept-url pattern="/LoginSuccess"
access="ROLE_RESTRICTED,ROLE_ADMIN,ROLE_ADMIN_APP,ROLE_PHYSICIAN,ROLE_NURSE" />
<!-- Enforce role-based access for user area -->
<intercept-url pattern="/root/user/**" access="ROLE_PHYSICIAN,ROLE_NURSE" />
<!-- Enforce role-based access for admin area -->
<intercept-url pattern="/root/admin/*" access="ROLE_ADMIN,ROLE_ADMIN_APP" />
<intercept-url pattern="/root/admin/user/**" access="ROLE_ADMIN,ROLE_ADMIN_APP" />
// ommitted ...
</http>
</beans:beans>
Here's my facelets page:
<h:form>
<h:inputText id="j_username" value="" styleClass="textInput" size="50"/>
<p>Click <h:commandLink value="here" action="/j_spring_security_switch_user"/> to switch to
user </p>
</h:form>
Error in the logs:
org.springframework.security.web.access.intercept.FilterSecurityInterceptor
- RunAsManager did not change Authentication object
I was able to fix this. The problem was with my jsf page not sending j_username to SwitchUserFilter when I bind the jsf action to '/j_spring_security_switch_user'. However, a passthrough through a controller binding works.
I blogged my experience here:
http://www.reverttoconsole.com/blog/spring/switch-user-su-like-behavior-in-spring/