Create Two Factor Authentication in Spring MVC - spring-mvc

Currently our webapps use Spring Security (Acegi Security 1.0.3) with username and password authentication. I have recently been given the task of plugging in two factor authentication (grid cards or tokens) into the framework.
However, there are many extension points in Spring Security - so I would appreciate it if you could give me some pointers as to whether I have gone about it in the right way.
The work flow would be: User logs in with their username and password > User is issued with a grid card challenge > Upon successful authentication they are granted access.
Here is the solution I have working at the moment.
Firstly I created a SimpleFormController (I called it GridChallengeController) that handles the two-factor authentication). If successful, users will be assigned the GridUser role and will be redirected to the page they originally requested.
Code:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
AcegiCrowdUserDetails details = (AcegiCrowdUserDetails) auth.getPrincipal();
details.addAuthority("GridUser");
UsernamePasswordAuthenticationToken existing = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(SecurityContextHolder.getContext().getAuthentication().getPrincipal(),
existing.getCredentials(), details.getAuthorities()));
SavedRequest saved = (SavedRequest) request.getSession().getAttribute(AbstractProcessingFilter.ACEGI_SAVED_REQUEST_KEY);
return new ModelAndView(new RedirectView(saved.getFullRequestUrl()));
Then I extend the org.acegisecurity.ui.ExceptionTranslationFilter to allow for another authentication entry point. It will be triggered when the accessDecisionManager throws a TwoFactorAccessDeniedException (extends org.acegisecurity.AuthenticationException). Here are the relevant methods:
Code:
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
private AuthenticationEntryPoint twoFactorAuthenticationEntryPoint;
...
try {
chain.doFilter(request, response);
} catch (TwoFactorAccessDeniedException ex) {
handleException(request, response, chain, ex);
} catch (AuthenticationException ex) {
handleException(request, response, chain, ex);
} catch (AccessDeniedException ex) {
handleException(request, response, chain, ex);
} catch (ServletException ex) {
...
}
}
private void handleException(ServletRequest request, ServletResponse response, FilterChain chain, AcegiSecurityException exception) throws IOException, ServletException {
if (exception instanceof TwoFactorAccessDeniedException) {
sendStartTwoFactorAuthentication(request, response, chain, (AuthenticationException) exception);
} else if (exception instanceof AuthenticationException) {
sendStartAuthentication(request, response, chain, (AuthenticationException) exception);
} else if (exception instanceof AccessDeniedException) {
...
}
}
private void sendStartTwoFactorAuthentication(ServletRequest request, ServletResponse response, FilterChain chain, AuthenticationException reason) throws ServletException, IOException {
twoFactorAuthenticationEntryPoint.commence((HttpServletRequest) request, (HttpServletResponse) response, reason);
}
Finally, I extend org.acegisecurity.vote.AffirmativeBased to throw a TwoFactorAccessDeniedException when a user has not passed two-factor authentication (Users are allocated the GridUser role when they are authenticated with their grid card).
Code:
#Override
public void decide(Authentication authentication, Object object, ConfigAttributeDefinition config) throws AccessDeniedException {
super.decide(authentication, object, config);
FilterInvocation f = (FilterInvocation) object;
if (!hasRole(authentication, "GridUser") && !hasRole(authentication, "ROLE_ANONYMOUS") && !f.getRequestUrl().equalsIgnoreCase("/gridchallenge.htm")) {
throw new TwoFactorAccessDeniedException("Need a grid logon");
}
}
Here are the relevant snippets of my security XML file:
Code:
<bean id="exceptionTranslationFilter" class="authentication.TwoFactorExceptionTranslationFilter">
<property name="authenticationEntryPoint">
<bean id="basicProcessingFilterEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/acegilogin.jsp"/>
<property name="forceHttps" value="false"/>
</bean>
</property>
<property name="twoFactorAuthenticationEntryPoint">
<bean id="gridProcessingFilterEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/gridchallenge.htm"/>
<property name="forceHttps" value="false"/>
</bean>
</property>
<property name="accessDeniedHandler">
<bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
<property name="errorPage" value="/accessDenied.jsp"/>
</bean>
</property>
</bean>
<bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager">
<bean class="authentication.TwoFactorAffirmativeBased">
<property name="allowIfAllAbstainDecisions" value="false"/>
<property name="decisionVoters">
<list>
<ref bean="roleVoter"/>
<bean class="org.acegisecurity.vote.AuthenticatedVoter"/>
</list>
</property>
</bean>
</property>
<property name="objectDefinitionSource">
<value><![CDATA[
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/admin/**=Vaas_Administrator
/guard/**=Guard
/acegilogin.jsp=IS_AUTHENTICATED_ANONYMOUSLY
/gridchallenge.htm=IS_AUTHENTICATED_FULLY
/**=VaasUser
]]></value>
</property>
</bean>
Is there any thing should I add furthermore so that my app to work correctly?

Related

spring data redis message listener listening messages twice

I am trying to use org.springframework.data.redis.listener.RedisMessageListenerContainer to listen on the redis pubsub channel.
my MessageListener class looks like this
#Component
public class RedisMessageListener {
#Autowired
private ProcessAdapterImpl processAdapter;
private static Logger logger = LoggerFactory.getLogger(RedisMessageListener.class);
public void handleMessage(Serializable message, String channel) {
logger.debug("handleMessage >>>>> Message received: " + message.toString() + " channel:" + channel);
processAdapter.onEventReceived(message.toString());
}
}
and in application context
<bean id="tbProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:conf/notifier-local.properties
</value>
</property>
</bean>
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${redis.server}" />
<property name="port" value="${redis.port}" />
<property name="usePool" value="true" />
</bean>
<!-- redis template definition -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"
p:connection-factory-ref="jedisConnectionFactory" />
<bean id="redisPublisher"
class="com.vgroup.apps.notifier.event.publisher.RedisPublisherImpl" />
<bean id="messageListener"
class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
<constructor-arg>
<bean class="com.vgroup.apps.notifier.event.listener.RedisMessageListener" />
</constructor-arg>
</bean>
<bean id="redisContainer"
class="org.springframework.data.redis.listener.RedisMessageListenerContainer">
<property name="connectionFactory" ref="jedisConnectionFactory" />
<property name="messageListeners">
<map>
<entry key-ref="messageListener">
<bean class="org.springframework.data.redis.listener.ChannelTopic">
<constructor-arg value="${redis.queue}" />
</bean>
</entry>
</map>
</property>
</bean>
redis publisher looks like below
#Component
public class RedisPublisherImpl implements IRedisPublisher {
#Autowired
private StringRedisTemplate redisTemplate;
#Autowired
private ObjectMapper mapper;
private static Logger logger = LoggerFactory.getLogger(RedisPublisherImpl.class);
public void afterPropertiesSet() throws Exception {
}
#Override
public void publish(Object event) {
logger.info("Start executing publish object");
try {
String jsonString = mapper.writeValueAsString(event);
redisTemplate.convertAndSend("notifications", jsonString);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
logger.info("End executing publish object");
}
}
with this configuration, for some strange reasons I am getting a message twice (some times even 3-4 times) even if it is sent by my publisher only once
in my logs I can see that it is message is being listened by 2 different rediscontainer threads
2015-12-03 09:13:12.152 [redisContainer-2] DEBUG c.v.a.n.e.l.RedisMessageListener - handleMessage >>>>> Message received: abc channel:notifications
2015-12-03 09:13:12.152 [redisContainer-2] DEBUG c.v.a.n.e.l.RedisMessageListener - handleMessage >>>>> Message received: def channel:notifications
2015-12-03 09:13:12.156 [redisContainer-3] DEBUG c.v.a.n.e.l.RedisMessageListener - handleMessage >>>>> Message received: abc channel:notifications
2015-12-03 09:13:12.157 [redisContainer-3] DEBUG c.v.a.n.e.l.RedisMessageListener - handleMessage >>>>> Message received: def channel:notifications
Check if the beans are creating twice (I.e the subscription is happening twice). I had similar problem, in web.xml. I had both contextListener and DispatchServlet which is initializing the beans twice there by subscribing twice.

How to convert from spring-integration-kafka 1.0.0M (XML config) to spring-integration-kafka 1.2.1 (Java config)?

I implemented spring-integration-kafka 1.0.0M into a Spring MVC project last year using the XML configuration and it was very simple to do. Since Spring seems to be moving in a Java configuration direction (rather than XML), I would like to convert from using the spring-integration-kafka XML configuration to the Java configuration, which the latest version of spring-integration-kafka (1.2.1) supports. The problem is that there really aren't many complete examples of this being done online, and the examples I have found look to be out-of-date from what I can tell. The configuration I have is pretty simple:
<bean id="kafkaStringEncoder" class="org.springframework.integration.kafka.serializer.common.StringEncoder" />
<bean id="customObjectMapper" class="ad.content.api.utils.ObjectMapperFactory" factory-method="getMapper" />
<int:channel id="kafkaConversionRequest" />
<bean id="producerProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="properties">
<props>
<prop key="message.send.max.retries">${kafka.retries}</prop>
</props>
</property>
</bean>
<int-kafka:producer-context id="kafkaWidgetProducerContext" producer-properties="producerProperties">
<int-kafka:producer-configurations>
<int-kafka:producer-configuration
broker-list="${kafka.broker}" key-class-type="java.lang.String"
key-encoder="kafkaStringEncoder" value-class-type="java.lang.String"
value-encoder="kafkaStringEncoder" topic="widget-.*"
compression-codec="default" async="true" />
</int-kafka:producer-configurations>
</int-kafka:producer-context>
<!-- declare spring integration gateway for kafka -->
<int:gateway service-interface="ad.content.api.models.kafka.KafkaGateway" default-reply-timeout="2000">
<int:method name="publishConversion" request-channel="kafkaConversionRequest" />
</int:gateway>
<int:chain input-channel="kafkaConversionRequest" output-channel="kafkaToJson">
<int:header-enricher>
<int:header name="topic" value="widget-conversion" />
</int:header-enricher>
</int:chain>
<int:object-to-json-transformer input-channel="kafkaToJson" output-channel="kafkaOutbound" object-mapper="customObjectMapper" />
<int-kafka:outbound-channel-adapter id="kafkaOutbound" kafka-producer-context-ref="kafkaWidgetProducerContext" />
Here's what I can figure out so far:
// gateway
#MessagingGateway(defaultReplyTimeout="2000")
public interface KafkaGateway {
#Gateway(requestChannel="kafkaConversionRequest", headers=#GatewayHeader(name="topic", value="widget-conversion"))
void publishConversion(Conversion conversion);
}
// create channel
#Bean(name="kafkaConversionRequest")
public MessageChannel getConversionRequest() {
return new DirectChannel();
}
#Bean
public KafkaProducerMessageHandler getHandler() throws Exception {
return new KafkaProducerMessageHandler(getContext());
}
#Bean
public KafkaProducerContext getContext() throws Exception {
KafkaProducerContext context = new KafkaProducerContext();
context.setProducerConfigurations(Collections.singletonMap("config", getConfiguration()));
return context;
}
#Bean
public ProducerConfiguration<String, String> getConfiguration() throws Exception {
return new ProducerConfiguration<String, String>(getMetaData(), getProducer());
}
#Bean
#Transformer(inputChannel="kafkaToJson", outputChannel="kafkaOutbound")
public ObjectToJsonTransformer getJsonTransformer() {
return new ObjectToJsonTransformer();
}
#Bean
public ProducerMetadata<String, String> getMetaData() {
StringSerializer serializer = new StringSerializer();
return new ProducerMetadata<String, String>("widget-.*", String.class, String.class, serializer, serializer);
}
#Bean
public Producer<String, String> getProducer() throws Exception {
return new ProducerFactoryBean<String, String>(getMetaData(), "dev.kafka-broker01:9092").getObject();
}
There's an outstanding pull request for a kafka sample that might help you.
Here is a fully functional example of configuring Kafka using Spring Java Config and equivalent XML version as well: https://spring.io/blog/2015/04/15/using-apache-kafka-for-integration-and-data-processing-pipelines-with-spring

Spring Security ignoring access-denied-handler with Method Level Security

I'm using Spring 3.2.4 and am unable to get Spring Security to redirect to my access-denied-handler when using Annotation based method level security. I have found several different posts about this, but to date, there does not seem to be any solutions that I have found.
My security.xml file:
<!-- need this here to be able to secure methods in components other than controllers (as scanned in applicationContext.xml) -->
<global-method-security secured-annotations="enabled" pre-post-annotations="enabled" jsr250-annotations="enabled" ></global-method-security>
<!-- Annotation/JavaConfig examples http://stackoverflow.com/questions/7361513/spring-security-login-page -->
<http use-expressions="true" entry-point-ref="authenticationEntryPoint">
<access-denied-handler ref="accessDeniedHandler"/>
<intercept-url pattern="/secure/login" access="permitAll" />
<intercept-url pattern="/secure/logout" access="permitAll" />
<intercept-url pattern="/secure/denied" access="permitAll" />
<session-management session-fixation-protection="migrateSession" session-authentication-error-url="/login.jsp?authFailed=true">
<concurrency-control max-sessions="10" error-if-maximum-exceeded="true" expired-url="/login.html" session-registry-alias="sessionRegistry"/>
</session-management>
<intercept-url pattern="/**" access="isAuthenticated()" />
<form-login default-target-url="/" authentication-failure-url="/secure/denied" />
<logout logout-url="/secure/logout" logout-success-url="/" />
<expression-handler ref="defaultWebSecurityExpressionHandler" />
</http>
<beans:bean id="authenticationEntryPoint" class="com.ia.security.LoginUrlAuthenticationEntryPoint">
<beans:constructor-arg name="loginFormUrl" value="/secure/login"/>
</beans:bean>
<beans:bean id="accessDeniedHandler" class="com.ia.security.AccessDeniedHandlerImpl">
<beans:property name="errorPage" value="/secure/denied"/>
</beans:bean>
My AccessDeniedHandlerImpl.java :
public class AccessDeniedHandlerImpl extends org.springframework.security.web.access.AccessDeniedHandlerImpl {
// SLF4J logger
private static final Logger logger = LoggerFactory.getLogger(AccessDeniedHandlerImpl.class);
#Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
logger.log("AccessDeniedException triggered!");
super.handle(request, response, accessDeniedException);
}
}
My Annotated Method:
#PreAuthorize("hasAuthority('ROLE_ZZZZ')")
public ModelAndView getUserInfo( #PathVariable long userId ){
ModelAndView mv = new ModelAndView();
User u = userService.findUser( userId );
mv.addObject("user", u);
return mv;
}
Is there anything special I need to do such that my access-denied-handler is called?
After several hours of searching around and tracing Spring code, I finally discovered what was happening. I am listing this here in case it is of value to someone else.
The access-denied-handler is used by the ExceptionTranslationFilter in case of an AccessDeniedException. However, the org.springframework.web.servlet.DispatcherServlet was first trying the handle the exception. Specifically, I had a org.springframework.web.servlet.handler.SimpleMappingExceptionResolver defined with a defaultErrorView. Consequently, the SimpleMappingExceptionResolver was consuming the exception by redirecting to an appropriate view, and consequently, there was no exception left to bubble up to the ExceptionTranslationFilter.
The fix was rather simple. Configure the SimpleMappingExceptionResolver to ignore all AccessDeniedException.
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="defaultErrorView" value="uncaughtException" />
<property name="excludedExceptions" value="org.springframework.security.access.AccessDeniedException" />
<property name="exceptionMappings">
<props>
<prop key=".DataAccessException">dataAccessFailure</prop>
<prop key=".NoSuchRequestHandlingMethodException">resourceNotFound</prop>
<prop key=".TypeMismatchException">resourceNotFound</prop>
<prop key=".MissingServletRequestParameterException">resourceNotFound</prop>
</props>
</property>
</bean>
Now, whenever an AccessDeniedException is thrown, the resolver ignores it and allows it to bubble up the stack to the ExceptionTranslationFilter which then calls upon the access-denied-handler to handle the exception.
I run into the same issue. In my case there was already a #ControllerAdvise definied which should handle exceptions - so I added the AccessDeniedException directly:
#Component
#ControllerAdvice
public class ControllerBase {
...
#ExceptionHandler(value = AccessDeniedException.class)
public ModelAndView accessDenied() {
return new ModelAndView("redirect:login.html");
}
}
Good luck with it!
Extending the Erics answer with JavaConfig for SimpleMappingExceptionResolver to ignore AccessDeniedException so that it can be thrown as response and doesn't get swallowed by the SimpleMappingExceptionResolver.
#Configuration
#EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter {
#Bean
public SimpleMappingExceptionResolver exceptionResolver() {
SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
exceptionResolver.setExcludedExceptions(AccessDeniedException.class);
return exceptionResolver;
}
}
Added on to Jessi answer above (https://stackoverflow.com/a/25948861/13215486). Note that if you want to tell the difference between Access Denied, and Access Forbidden, then you need to do a little more work.
#Component
#ControllerAdvice
public class ControllerBase {
...
#ExceptionHandler(value = AccessDeniedException.class)
public ModelAndView accessDenied(HttpServletRequest request) {
ModelAndView mav = new ModelAndView("redirect:login.html");
mav.setStatus(request.getRemoteUser() != null ? HttpStatus.FORBIDDEN : HttpStatus.UNAUTHORIZED);
return mav;
}
}

Integrating Atmosphere with Spring MVC

I want to provide push notifications in a Spring MVC project, using JDK 1.6 targeting all browsers. I followed this post and finally decided to go with Atmosphere.
For Server-sent events, My server controller is (source):
#Controller
public class AtmosphereController {
#RequestMapping(value="/getTime", method=RequestMethod.GET)
#ResponseBody
public void websockets(final AtmosphereResource atmosphereResource) {
final HttpServletRequest request = atmosphereResource.getRequest();
final HttpServletResponse response = atmosphereResource.getResponse();
atmosphereResource.suspend();
final Broadcaster bc = atmosphereResource.getBroadcaster();
bc.scheduleFixedBroadcast(new Callable<String>() {
public String call() throws Exception {
return (new Date()).toString();
}
}, 10, TimeUnit.SECONDS);
}
}
While running, I got org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.atmosphere.cpr.AtmosphereResource]: Specified class is an interface.
In solution to this, I got this relevant post. I added this to my dispatcher-servlet.xml:
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
</list>
</property>
</bean>
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean id= "atmosphereResource"
class="org.atmosphere.cpr.AtmosphereResourceImpl" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
Doing this, also results in a new error:
[cvc-complex-type.2.1: Element 'mvc:annotation-driven' must have no character or element information item [children], because the type's content type is empty.]
I've also tried this. Please help me inject AtmosphereResource in Spring Controller. Do I also need to update web.xml or some other configuration file to make it work or what part I'm missing. Please help!
Please also comment on other alternatives to provide Server-Side Events functionality. Thanks in advance!
Your argument-resolvers must be a class like this:
public class AtmosphereArgumentResolver implements HandlerMethodArgumentResolver {
#Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest httpServletRequest= webRequest.getNativeRequest(HttpServletRequest.class);
return Meteor.build(httpServletRequest).getAtmosphereResource();
}
#Override
public boolean supportsParameter(MethodParameter parameter) {
return AtmosphereResource.class.isAssignableFrom(parameter.getParameterType());
}
}
and try this:
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="com.yourpackage.AtmosphereArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
try Atmosphere 2.1.0-RC1 and following this document . All you need to do is to add the atmosphere-spring.jar to your dependency.
-- Jeanfrancois

Spring security:How to map j_spring_security_check in controller?

I'm trying to integrate spring security into existing code base which is in spring mvc.
In my existing code base i v'e a client delegate in web project which interacts with service delegate in service project which in turn interacts with service interface of back-end layer.It is the service interface impl of back-end layer which i'm making implement the UserDetailsService interface.
P.S - I'm creating/converting/passing on various objects i.e. Model,DO,DTO,Request,Response etc across all the layers.
So now,when i click on submit i want the control to go through the delegate from web to back-end layer till the class which implements UserDetailsService interface. How can i achieve this?
[Update]:After going through this link i changed my security xml like shown below:
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/welcome.html" access="hasRole('ROLE_USER')" />
<security:form-login login-page="/portalLogin.html" login-processing-url="/signIn" always-use-default-target="true"
username-parameter="username" password-parameter="password"
default-target-url="/welcome.html" authentication-failure-url="/loginfailed.html" />
<security:logout logout-success-url="/logout.html" />
</security:http>
My LoginController is like this:
#RequestMapping("/signIn")
public ModelAndView onClickLogin(#ModelAttribute("dashboard")
LoginModel loginModel,Model model){
try{
delegate.clickLogin(loginModel);
if(null != loginModel.getError()){
// return new ModelAndView("error");
}
}catch(Exception exception){
}
return new ModelAndView("redirect:welcome.html");
}
[Update]:Sorry for very late update.Controller Mapping issue is resolved, now i'm facing issues because of UsernamePasswordAuthenticationFilter.After comparing logs generated by above code with properly working code logs,i figured out that spring security is not firing 'UsernamePasswordAuthenticationFilter' for some reasons in my case.'UsernamePasswordAuthenticationFilter' is the one which authenticates the user.
//Logs when authentication is done
[while using spring's default /j_spring_security_check].
DEBUG FilterChainProxy - /j_spring_security_check at position 3 of 10 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
DEBUG UsernamePasswordAuthenticationFilter - Request is to process authentication
DEBUG ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
session created
DEBUG SessionImpl - Opened session at timestamp: 13661947944
SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])
After openSession
DEBUG SessionImpl - Opened session at timestamp: 13661947944
Criteria before eq::this::CriteriaImpl(com.infy.itrade.core.entity.LoginDO:this[][])::CriteriaImpl(com.infy.itrade.core.entity.LoginDO:this[][])...
//Logs when authentication is not done [while using custom login processing url : /signIn.html].
DEBUG FilterChainProxy - /signIn.html at position 3 of 10 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter' //UsernamePasswordAuthenticationFilter is not doing authentication process instead it skips to next filter.
DEBUG FilterChainProxy - /signIn.html at position 4 of 10 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
DEBUG FilterChainProxy - /signIn.html at position 5 of 10 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
I created a custom filter 'MyFilter' which extends 'AbstractAuthenticationProcessingFilter'. But still 'MyFilter' doesn't do any authentication as the log shows the following:
DEBUG FilterChainProxy - /signIn.html at position 2 of 9 in additional filter chain; firing Filter: 'LogoutFilter'
DEBUG FilterChainProxy - /signIn.html at position 3 of 9 in additional filter chain; firing Filter: 'MyFilter'
DEBUG FilterChainProxy - /signIn.html at position 4 of 9 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
MyFilter:
public class MyFilter extends AbstractAuthenticationProcessingFilter {
private static final String DEFAULT_FILTER_PROCESSES_URL = "/signIn";
private static final String POST = "POST";
public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME";
private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
public MyFilter() {
super(DEFAULT_FILTER_PROCESSES_URL);
}
public MyFilter(String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
// TODO Auto-generated constructor stub
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse arg1) throws AuthenticationException,
IOException, ServletException {
// TODO Auto-generated method stub
String username = obtainUsername(request);
String password = obtainPassword(request);
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
username = username.trim();
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
HttpSession session = request.getSession(false);
if (session != null || getAllowSessionCreation()) {
request.getSession().setAttribute(
SPRING_SECURITY_LAST_USERNAME_KEY,
TextEscapeUtils.escapeEntities(username));
}
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
#Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
if (request.getMethod().equals(POST)) {
// If the incoming request is a POST, then we send it up
// to the AbstractAuthenticationProcessingFilter.
super.doFilter(request, response, chain);
} else {
// If it's a GET, we ignore this request and send it
// to the next filter in the chain. In this case, that
// pretty much means the request will hit the /login
// controller which will process the request to show the
// login page.
chain.doFilter(request, response);
}
}
...
}
Context xml:
<bean id="loginUrlAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/portalLogin.html"/>
</bean>
<bean id="MyFilter" class="com.infosys.itrade.core.dao.security.MyFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationSuccessHandler" ref="successHandler"></property>
<property name="authenticationFailureHandler" ref="failureHandler"></property>
<property name="filterProcessesUrl" value="/signIn"></property>
</bean>
<bean id="successHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/welcome.html" />
</bean>
<bean id="failureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/loginfailed.html" />
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider
user-service-ref="LoginUserDetailsService">
</security:authentication-provider>
</security:authentication-manager>
<bean id="LoginUserDetailsService"
class="com.infy.itrade.core.service.login.LoginServiceImpl">
<property name="logindao" ref="loginDAOImpl" />
</bean>
<bean id="loginDAOImpl" class="com.infy.itrade.core.dao.login.LoginDAODBImpl">
<property name="sessionFactory"> <ref bean ="sessionFactory"/> </property>
</bean>
</beans>
What am i missing here?
[Update]: Since i couldn't get this working i changed my approach as suggested by others here i.e. I'm avoiding the architectural flow for login module alone. But right now i'm facing a different issue with the new approach for which i'll ask a different question. Thanks.

Resources