cancel
Showing results for 
Search instead for 
Did you mean: 

Prevent multiple login using the same user name and password

Former Member
0 Kudos

Hello Experts,

I need to prevent multiple logins with same credentials on my storefront, how can i achieve that?

Lets say user_A is already login then user_B tries to login to the application with the same credentials of user_A then logout the user_A and allow the user_B to login.

Thanks Experts! :)

bhavirisetty
Active Participant
0 Kudos

Hi,

Try using below configuration,

 <security:session-management>
             <security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
         </security:session-management>

Or write custom ConcurrentSessionFilter, not sure how this works in clustered environment if we are not using centralized session.

Thanks

Accepted Solutions (0)

Answers (1)

Answers (1)

srini_y
Explorer
0 Kudos

This can be achieved easily in any spring application by using concurrency-control namespace element in your spring security session-management. This should expire the original/leastRecentlyUsed session:

<security:session-management>
     <security:concurrency-control max-sessions="1" />
</security:session-management>

Also, you’ll need to add the following to web.xml:

<listener>
    <description>
    	This is essential to make sure that the Spring Security session registry is        
notified when the session is destroyed - so that the expired sessions are
cleaned up. </description> <listener-class> org.springframework.security.web.session.HttpSessionEventPublisher </listener-class> </listener>


However, things are a bit different in Hybris.

What happens when you define session-management with concurrency-control?
When session-management configuration is defined, spring security enables and adds the SessionManagementFilter to the filter chain. Having concurrency-control defined adds ConcurrentSessionFilter to the filter chain and also makes the sessionAuthenticationStrategy as CompositeSessionAuthenticationStrategy with the below 3 strategies set to delegateStrategies property (in the order):

1. CsrfAuthenticationStrategy
2. ConcurrentSessionControlAuthenticationStrategy
3. RegisterSessionAuthenticationStrategy

Make sure that session-fixation-protection or invalid-session-url aren't defined in the session-management tag. Otherwise, the SessionFixationProtectionStrategy will also be added to the delegateStrategies of ConcurrentSessionControlAuthenticationStrategy.

Checkout HttpConfigurationBuilder for more information.

What hybris does?
Hybris has a beanpostprocessor defined - RemoveDefaultSessionFixationStrategyBeanPostProcessor which makes sure that HybrisSessionFixationProtectionStrategy is added to the delegateStrategies of the CompositeSessionAuthenticationStrategy. HybrisSessionFixationProtectionStrategy is a custom implementation of spring's SessionFixationProtectionStrategy which takes care of invalidating jalosessions in addition to what SessionFixationProtectionStrategy does -> preventing the Session Fixation attack by creating a new session or otherwise changing the session ID when a user logs in.


Fix:

It is important that RegisterSessionAuthenticationStrategy is after SessionFixationProtectionStrategy so that the correct session is registered.

As RemoveDefaultSessionFixationStrategyBeanPostProcessor adds HybrisSessionFixationProtectionStrategy at the end of the delegateStrategies list, the session registered by the RegisterSessionAuthenticationStrategy will be removed and a new session would be created by HybrisSessionFixationProtectionStrategy.

I have implemented a beanpostprocessor to reorder the delegateStrategies as shown below in the web/src of storefront extension and defined it as a bean in spring-security-config.xml.

@Override
public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException
{
	if (bean instanceof CompositeSessionAuthenticationStrategy)
	{
	      final CompositeSessionAuthenticationStrategy compositeStrategy = (CompositeSessionAuthenticationStrategy) bean;
	      <br>              try
	      {
		   final List<SessionAuthenticationStrategy> strategies = this.getStrategiesFrom(compositeStrategy);
		   final Iterator<SessionAuthenticationStrategy> iterator = strategies.iterator();
		   RegisterSessionAuthenticationStrategy registerSessionAuthStrategy = null;
		   while (iterator.hasNext())
		   {
			final SessionAuthenticationStrategy current = iterator.next();

			if (current instanceof RegisterSessionAuthenticationStrategy)
			{
			    registerSessionAuthStrategy = (RegisterSessionAuthenticationStrategy) current;
			    iterator.remove();
			}
		    }

		    if (null != registerSessionAuthStrategy)
		    {
			strategies.add(registerSessionAuthStrategy);
			LOG.info("Moved RegisterSessionAuthenticationStrategy to the end of the delegateStrategies");
		    }
		}
		catch (final IllegalAccessException e)
		{
		      throw new RuntimeException("Error reordering delegate strategies", e);
		}
	}

        return bean;
}


In my case, I want to restrict the concurrent login hence I have defined the session-management as shown below with error-if-maximum-exceeded=true:

<security:session-management>
     <security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</security:session-management>


To display a meaningful message and not to disable the user, I have updated the LoginFailureAuthenticationHandler:

@Override
public void onAuthenticationFailure(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException exception) throws IOException, ServletException
	{
		if (exception instanceof SessionAuthenticationException)
		{
			this.setDefaultFailureUrl("/?concurrentSession=true");
		} else
		{
			// Register brute attacks
			bruteForceAttackCounter.registerLoginFailure(request.getParameter("j_username"));
		}


		// Store the j_username in the session
		request.getSession().setAttribute("SPRING_SECURITY_LAST_USERNAME", request.getParameter("j_username"));


		super.onAuthenticationFailure(request, response, exception);
	}

Updated HomePageController home() to accept
@RequestParam(value = "concurrentSession", defaultValue = "false") final boolean concurrentSession

and in case if it is true set and redirect to login page.

GlobalMessages.addFlashMessage(redirectModel, GlobalMessages.ERROR_MESSAGES_HOLDER, "user.concurrent.login");
Added below entry in base_en.properties:
user.concurrent.login=Your login attempt failed as you already have an active session.


Note: You need to implement your own custom SessionRegistry for the above solution to work in Clustered Environment as the SessionRegistryImpl maintains the sessions in local map specific which would be different for each node.