2.3. Preventing Duplicate Logins
This feature prevents one account from being logged in at several places at once. The later login is kept and the earlier one is logged out.
This feature does not work through configuration alone. The product cannot know who logged in, so the application has to report the user ID at the moment login succeeds. Both configuration and source code changes are therefore required.
Configuration
The default value of allowDuplicateLogin is false, so this feature is on from the start. The example below states false explicitly to make the intent clear; behavior is the same if you omit it.
The remaining settings determine what happens when a duplicate login is found.
If you need to allow duplicate logins, set allowDuplicateLogin to true. In that case duplicateLoginPolicy is ignored and fixed at legacy.
web.xml
<init-param>
<param-name>allowDuplicateLogin</param-name>
<param-value>false</param-value> {/* must be false for duplicate login prevention to be active */}
</init-param>
<init-param>
<param-name>duplicateLoginPolicy</param-name>
<param-value>legacy</param-value> {/* legacy is the default, so legacy mode applies even without this entry */}
</init-param>
<init-param>
<param-name>invalidateDuplicateLogin</param-name>
<param-value>true</param-value> {/* must be true to invalidate the existing session automatically on a detected duplicate login */}
</init-param>
<init-param>
<param-name>logoutUrl</param-name>
<param-value>/logout.jsp</param-value> {/* logout URL used on duplicate login */}
</init-param>
OpenmaruFilterConfiguration
@Configuration
public class OpenmaruFilterConfiguration implements WebMvcConfigurer {
@Bean
public FilterRegistrationBean getFilterRegistrationBean() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean(new InfinispanHotRodSessionFilter());
registrationBean.setOrder(Integer.MIN_VALUE);
...
// must be false for duplicate login prevention to be active
registrationBean.addInitParameter(Constants.ALLOW_DUPLICATE_LOGIN, "false");
// legacy is the default, so legacy mode applies even without this entry
registrationBean.addInitParameter(Constants.DUPLICATE_LOGIN_POLICY, "legacy");
// must be true to invalidate the existing session automatically on a detected duplicate login
registrationBean.addInitParameter(Constants.INVALIDATE_DUPLICATE_LOGIN, "true");
// logout URL used on duplicate login
registrationBean.addInitParameter(Constants.LOGOUT_URL, "/logout.jsp");
...
registrationBean.setUrlPatterns(Arrays.asList("/*"));
registrationBean.setDispatcherTypes(DispatcherType.ERROR, DispatcherType.INCLUDE, DispatcherType.FORWARD, DispatcherType.REQUEST);
return registrationBean;
}
...
}
Source Code Changes
This is why configuration alone is not enough. The application has to report "this person has logged in" before the product can find another login for the same account.
There are two places to add code.
- Immediately after a successful login — always required
- Logout handling — required only when
invalidateDuplicateLoginisfalse
After a Successful Login
Add the following on the line after the user passes authentication. Put that user's ID in place of [USER_ID].
SessionLoginManager.getInstance().login(request, [USER_ID]);
Logout and Session Invalidation
When invalidateDuplicateLogin=true (automatic logout handling)
When invalidateDuplicateLogin is set to true, logout is handled automatically on a duplicate login.
Behavior
1. On detecting a duplicate login, `SessionLoginManager.getInstance().logout()` is called automatically
2. Session invalidation (`session.invalidate()`) is handled automatically as well
3. The user is redirected automatically to the configured logout URL (when logoutUrl is set)
You therefore do not need to write separate logout handling code in the application.
When invalidateDuplicateLogin=false (manual logout handling)
If you set invalidateDuplicateLogin to false, the system does not invalidate the session automatically even when a duplicate login is detected. This is useful when you want to check for duplicate logins and invalidate them yourself.
Behavior
1. On detecting a duplicate login, the existing session is not invalidated
2. Session information is not removed from the session store (loginRemove is not called)
3. SessionLoginManager.logout() is not called
4. session.invalidate() is not called
5. Only the redirect to the configured logoutUrl is performed (when logoutUrl is set)
When you need to handle logout manually, use the following code.
SessionLoginManager.getInstance().logout(request);
Handling an Explicit User Logout
When the user clicks a logout button, handle it as follows.
// logout handling example
public void doLogout(HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
// OPENMARU Cluster logout handling
SessionLoginManager.getInstance().logout(request);
// invalidate the session
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
// redirect to the login page
response.sendRedirect("/login.jsp");
} catch (Exception e) {
// error handling on logout failure
log.error("An error occurred during logout handling", e);
throw e;
}
}
- On an explicit user logout, you must call
SessionLoginManager.getInstance().logout(request)and thensession.invalidate(). - If you set
invalidateDuplicateLogin=true, duplicate logins are handled automatically and no separate code is needed.