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?
Related
Please help us out in understanding what this node in the applicationHost.config mean:
Basically we need to know what are these property ids? I guess they are leaving the website in an unstable condition and most probably corrupting the bindings.
<customMetadata>
<key path="LM/W3SVC">
<property id="130001" dataType="String" userType="2" attributes="Inherit" value="BITS-Sessions" />
<property id="130002" dataType="String" userType="2" attributes="Inherit" value="18446744073709551615" />
<property id="130003" dataType="DWord" userType="2" attributes="Inherit" value="1209600" />
<property id="130004" dataType="DWord" userType="2" attributes="Inherit" value="0" />
<property id="130005" dataType="String" userType="2" attributes="Inherit" value="" />
<property id="130007" dataType="String" userType="2" attributes="Inherit" value="" />
<property id="130008" dataType="DWord" userType="2" attributes="Inherit" value="86400" />
<property id="130010" dataType="DWord" userType="2" attributes="Inherit" value="0" />
<property id="130011" dataType="DWord" userType="2" attributes="Inherit" value="1" />
<property id="130012" dataType="DWord" userType="2" attributes="Inherit" value="12" />
<property id="130013" dataType="DWord" userType="2" attributes="Inherit" value="1" />
<property id="130014" dataType="DWord" userType="2" attributes="Inherit" value="0" />
<property id="130015" dataType="DWord" userType="2" attributes="Inherit" value="0" />
<property id="130016" dataType="DWord" userType="2" attributes="Inherit" value="0" />
<property id="130017" dataType="DWord" userType="2" attributes="Inherit" value="50" />
<property id="130018" dataType="DWord" userType="2" attributes="Inherit" value="0" />
<property id="2073" dataType="MultiSZ" userType="1" attributes="Inherit" value="C:\windows\system32\bitssrv.dll
" />
</key>
<key path="LM/W3SVC/INFO">
<property id="4012" dataType="String" userType="1" attributes="Inherit" value="NCSA Common Log File Format,Microsoft IIS Log File Format,W3C Extended Log File Format,ODBC Logging" />
<property id="2120" dataType="MultiSZ" userType="1" attributes="None" value="400,0,,,0
" />
</key>
</customMetadata>
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 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.
I am new to mobicents diameter and followed the example downloaded here.
Executing both ExampleClient and ExampleServer on the same machine with different ports the "Result-code" is 3002
"Error-message" is "No connection to peer"
Where am I wrong?
Protocol error:
DIAMETER_UNABLE_TO_DELIVER 3002
This error is given when Diameter can not deliver the message to
the destination, either because no host within the realm
supporting the required application was available to process the
request, or because Destination-Host AVP was given without the
associated Destination-Realm AVP.
client-jdiameter-config.xml
<?xml version="1.0"?>
<Configuration xmlns="http://www.jdiameter.org/jdiameter-server">
<LocalPeer>
<URI value="aaa://127.0.0.1:1812" />
<IPAddresses>
<IPAddress value="127.0.0.1" />
</IPAddresses>
<Realm value="mobicents.org" />
<VendorID value="0" />
<ProductName value="jDiameter" />
<FirmwareRevision value="1" />
<OverloadMonitor>
<Entry index="1" lowThreshold="0.5" highThreshold="0.6">
<ApplicationID>
<VendorId value="0" />
<AuthApplId value="333333" />
<AcctApplId value="0" />
</ApplicationID>
</Entry>
</OverloadMonitor>
</LocalPeer>
<Parameters>
<AcceptUndefinedPeer value="false" />
<DuplicateProtection value="true" />
<DuplicateTimer value="240000" />
<UseUriAsFqdn value="false" />
<QueueSize value="10000" />
<MessageTimeOut value="60000" />
<StopTimeOut value="10000" />
<CeaTimeOut value="10000" />
<IacTimeOut value="30000" />
<DwaTimeOut value="10000" />
<DpaTimeOut value="5000" />
<RecTimeOut value="10000" />
<Concurrent>
<Entity name="ThreadGroup" size="64" />
<Entity name="ProcessingMessageTimer" size="1" />
<Entity name="DuplicationMessageTimer" size="1" />
<Entity name="RedirectMessageTimer" size="1" />
<Entity name="PeerOverloadTimer" size="1" />
<Entity name="ConnectionTimer" size="1" />
<Entity name="StatisticTimer" size="1" />
</Concurrent>
</Parameters>
<Network>
<Peers>
<Peer name="aaa://127.0.0.1:3868" attempt_connect="true" rating="1" />
</Peers>
<Realms>
<Realm name="mobicents.org" peers="127.0.0.1"
local_action="LOCAL" dynamic="false" exp_time="1">
<ApplicationID>
<VendorId value="0" />
<AuthApplId value="333333" />
<AcctApplId value="0" />
</ApplicationID>
</Realm>
</Realms>
</Network>
<Extensions />
</Configuration>
server-jdiameter-config.xml
<?xml version="1.0"?>
<Configuration xmlns="http://www.jdiameter.org/jdiameter-server">
<LocalPeer>
<URI value="aaa://127.0.0.1:3868" />
<IPAddresses>
<IPAddress value="127.0.0.1" />
</IPAddresses>
<Realm value="mobicents.org" />
<VendorID value="0" />
<ProductName value="jDiameter" />
<FirmwareRevision value="1" />
<OverloadMonitor>
<Entry index="1" lowThreshold="0.5" highThreshold="0.6">
<ApplicationID>
<VendorId value="0" />
<AuthApplId value="333333" />
<AcctApplId value="0" />
</ApplicationID>
</Entry>
</OverloadMonitor>
</LocalPeer>
<Parameters>
<!-- set to true, we can safely remove client def in this case -->
<AcceptUndefinedPeer value="true" />
<DuplicateProtection value="true" />
<DuplicateTimer value="240000" />
<UseUriAsFqdn value="false" />
<QueueSize value="10000" />
<MessageTimeOut value="60000" />
<StopTimeOut value="10000" />
<CeaTimeOut value="10000" />
<IacTimeOut value="30000" />
<DwaTimeOut value="10000" />
<DpaTimeOut value="5000" />
<RecTimeOut value="10000" />
<Concurrent>
<Entity name="ThreadGroup" size="64" />
<Entity name="ProcessingMessageTimer" size="1" />
<Entity name="DuplicationMessageTimer" size="1" />
<Entity name="RedirectMessageTimer" size="1" />
<Entity name="PeerOverloadTimer" size="1" />
<Entity name="ConnectionTimer" size="1" />
<Entity name="StatisticTimer" size="1" />
</Concurrent>
</Parameters>
<Network>
<Peers>
<!-- our client, lets define it -->
<Peer name="aaa://127.0.0.1:1812" attempt_connect="false"
rating="1" />
</Peers>
<Realms>
<Realm name="mobicents.org" peers="127.0.0.1" local_action="LOCAL" dynamic="false" exp_time="1">
<ApplicationID>
<VendorId value="0" />
<AuthApplId value="333333" />
<AcctApplId value="0" />
</ApplicationID>
</Realm>
</Realms>
</Network>
<Extensions />
</Configuration>
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/