Back Forum Reply New

how to handle multiple logged in users?

Hi,

I am currently searching a solution how i can handle multiple users who are logged in to my app simultanously. The problem is, if I log in as let's say quot;bobquot;, the object in the securitycontext is bob's details. But if I log in after that from another browser or pc as e.g. quot;alicequot;, then I no longer can access bob, and the object in securitycontext seems to be replaced by alice. Am I doing something wrong?  I only use custom userdetails, login-authentication is default.

thanks in advance,
override

This should work out of the box with Spring Security. When you say another browser what do you mean? Please provide detailed steps of how you reproduce your problem. Ensure you are not using two different windows for this test. Try with Firefox and Google Chrome or Firefox and IE and see if you can have multiple users logged in. One thing to do is to ensure you do not have the SecurityContextHolderStrategy set to global. If you are still having problems please post your Security Configuration ensuring to use the code tags (i.e. the # button).

well i think the problem is i want to display the name of the currently logged in user in my jsp files. therefore i use the SecurityContextHolder.getContext().getAuthenticati  on().getPrincipal() method. now i log in using firefox with username bob and the name of bob appears in my pages. then i log in using internet explorer with username alice and i see the name of alice in IE. now, i click a link in the firefox window, and then the name changes to alice, but it should display bob in firefox and alice in IE. i hope you understand what i mean, this caused me to think i can not handle multiple users logged in.
i think my way to retrieve the currently logged in user is wrong, maybe you have a solution

You are retrieving the current user correctly. Spring Security will grab the current user from session and associate it with the current thread.  Also are you calling SecurityContextHolder.getContext().setAuthenticati  on to populate the authentication or are you letting the framework do that for you? If you are calling setAuthentication please ensure that Spring Security's intercept-ucl methods match on the ucl you are setting the Authentication. Also ensure that for the intercept-ucl that is not specified as filters=none (use access=permitAll instead).

As I alluded to before, I do not think I can help till you post your configuration. Please post your Spring Security config and web.xml using the code tags (i.e. the # button). Please post any code you have written that relates to Spring Security as well (i.e. if you are calling setAuthentication please post that code).

thank you already for your help; i'll post the code below. i do not use the setAuthentication method, everything is managed by spring except that i have written a custom userdetails and userdetailsservice class because i want to store more attributes than only username and password for a user.
i have figured out that following line of code in a method mapped to a specific request prints the correct user, i.e. corresponding to my example it prints bob when calling the method via firefox and alice via IE:Code:
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
System.out.println(attr.getRequest().getUserPrincipal());
but printing the securitycontext using the following line BOTH times prints alice:Code:
System.out.println(SecurityContextHolder.getContext().toString());

now the applicationContext-security.xmlCode:
lt;?xml version=quot;1.0quot; encoding=quot;UTF-8quot;?gt;

lt;beans:beans xmlns=quot;schema/securityquot;
xmlns:beans=quot;schema/beansquot; xmlns:xsi=quot;2001/XMLSchema-instancequot;
xsi:schemaLocation=quot;schema/beans

schema/beans/spring-beans-3.0.xsd

schema/security

schema/security/spring-security-3.0.4.xsdquot;gt;

lt;global-method-security secured-annotations=quot;enabledquot;gt;
lt;/global-method-securitygt;

lt;from auto-config='true'gt;
lt;intercept-ucl pattern=quot;/login.jsp*quot; access=quot;IS_AUTHENTICATED_ANONYMOUSLYquot; /gt;
lt;intercept-ucl pattern=quot;/WEB-INF/*quot; access=quot;ROLE_TESTquot; /gt;
lt;intercept-ucl pattern=quot;/**quot; access=quot;ROLE_USERquot; /gt;
lt;form-login login-page=quot;/login.jspquot; authentication-failure-ucl=quot;/login.jsp?login_error=1quot;
default-target-ucl=quot;/start.htmlquot; always-use-default-target='true'/gt;
lt;session-management session-fixation-protection=quot;migrateSessionquot;gt;
lt;concurrency-control max-sessions=quot;1quot; error-if-maximum-exceeded=quot;truequot; /gt;
lt;/session-managementgt;
lt;/fromgt;

lt;authentication-managergt;
lt;authentication-provider user-service-ref=quot;userDetailsServicequot;gt;
lt;/authentication-providergt;
lt;/authentication-managergt;lt;/beans:beansgt;
and applicationContext.xml

Code:
lt;?xml version=quot;1.0quot; encoding=quot;UTF-8quot;?gt;
lt;beans xmlns=quot;schema/beansquot;
xmlns:xsi=quot;2001/XMLSchema-instancequot; xmlns:context=quot;schema/contextquot;
xmlns:aop=quot;schema/aopquot; xmlns:tx=quot;schema/txquot;
xsi:schemaLocation=quot;schema/beans schema/beans/spring-beans-2.5.xsd schema/context schema/context/spring-context-2.5.xsd schema/tx schema/tx/spring-tx-2.5.xsdquot;gt;

lt;context:annotation-config /gt;

lt;bean id=quot;userDetailsServicequot; class=quot;model.CustomUserDetailsServicequot; /gt;
lt;/beansgt;
here's the loadByUsername method of my custom userdetailsservice class

Code:
@Override   public UserDetails loadUserByUsername(String user)   throws UsernameNotFoundException, DataAccessException {

AccountDetails details = users.get(user);
CustomUser cUser = null;
if (details != null) {   String shape = ImageSelector.getShape();   cUser = new CustomUser(user, details, new Cart(), shape);
} else {   throw new UsernameNotFoundException(quot;User quot; + user + quot; does not exist!quot;);
}

return cUser;   }
and my custom userdetails class:

Code:
package model;

import java.util.Collection;
import java.util.Vector;

import org..security.core.GrantedAuthority;
import org..security.core.authority.GrantedAuthorityImpl;
import org..security.core.userdetails.UserDetails;

public class CustomUser implements UserDetails {
   /**    *     */   private static final long serialVersionUID = 1L;
   private String username;   private String password;   private String street;   private String number;   private String zip;   private String city;      private boolean accountNonExpired;   private boolean accountNonLocked;   private boolean credentialsNonExpired;   private boolean enabled;   private GrantedAuthority authority = new GrantedAuthorityImpl(quot;ROLE_USERquot;);      private transient Cart cart;   private transient String sessioningShape;   private transient boolean sessionPageShown;      public CustomUser(String username, AccountDetails details, Cart cart, String sessioningShape) {
update(details);
this.username = username;
setCart(cart);
setSessioningShape(sessioningShape);
setSessionPageShown(false);

accountNonExpired = true;
accountNonLocked = true;
credentialsNonExpired = true;
enabled = true;   }
   public void update(AccountDetails details) {
//TODO validate details
setPassword(details.getPassword());
setStreet(details.getStreet());
setNumber(details.getNumber());
setZip(details.getZip());
setCity(details.getCity());   }      public void setPassword(String password) {
this.password = password;   }
   @Override   public Collectionlt;GrantedAuthoritygt; getAuthorities() {
Collectionlt;GrantedAuthoritygt; c = new Vectorlt;GrantedAuthoritygt;();
c.add(authority);
return c;   }
   @Override   public String getPassword() {
return password;   }
   @Override   public String getUsername() {
return username;   }
   @Override   public boolean isAccountNonExpired() {
return accountNonExpired;   }
   @Override   public boolean isAccountNonLocked() {
return accountNonLocked;   }
   @Override   public boolean isCredentialsNonExpired() {
return credentialsNonExpired;   }
   @Override   public boolean isEnabled() {
return enabled;   }
   public void setCart(Cart cart) {
this.cart = cart;   }
   public Cart getCart() {
return cart;   }
   public void setSessioningShape(String sessioningShape) {
this.sessioningShape = sessioningShape;   }
   public String getSessioningShape() {
return sessioningShape;   }
   public void setStreet(String street) {
this.street = street;   }
   public String getStreet() {
return street;   }
   public void setNumber(String number) {
this.number = number;   }
   public String getNumber() {
return number;   }
   public void setZip(String zip) {
this.zip = zip;   }
   public String getZip() {
return zip;   }
   public void setCity(String city) {
this.city = city;   }
   public String getCity() {
return city;   }      @Override   public boolean equals(Object o) {
boolean equals = false;
if (o instanceof CustomUser) {   equals = (username.equals(((CustomUser) o).getUsername()));
}
System.out.println(quot;equals: quot; + equals);
return equals;   }      @Override   public int hashCode() {
return username.hashCode();   }
   public void setSessionPageShown(boolean sessionImageShown) {
this.sessionPageShown = sessionImageShown;   }
   public boolean isSessionPageShown() {
return sessionPageShown;   }      @Override   public String toString() {
return username;   }
}

edit: sorry i forgot the web.xml

Code:
lt;?xml version=quot;1.0quot; encoding=quot;UTF-8quot;?gt;
lt;web-app xmlns:xsi=quot;2001/XMLSchema-instancequot; xmlns=quot;xml/ns/javaeequot; xmlns:web=quot;xml/ns/javaee/web-app_2_5.xsdquot; xsi:schemaLocation=quot;xml/ns/javaee xml/ns/javaee/web-app_2_5.xsdquot; id=quot;WebApp_IDquot; version=quot;2.5quot;gt; lt;display-namegt;Spring3MVClt;/display-namegt; lt;context-paramgt;   lt;param-namegt;contextConfigLocationlt;/param-namegt;   lt;param-valuegt;     /WEB-INF/applicationContext.xml     /WEB-INF/applicationContext-security.xml   lt;/param-valuegt; lt;/context-paramgt; lt;listenergt;   lt;listener-classgt;org..web.context.ContextLoaderListenerlt;/listener-classgt; lt;/listenergt; lt;listenergt;   lt;listener-classgt;org..security.web.session.fromSessionEventPublisherlt;/listener-classgt; lt;/listenergt; lt;filtergt;   lt;filter-namegt;springSecurityFilterChainlt;/filter-namegt;   lt;filter-classgt;org..web.filter.DelegatingFilterProxylt;/filter-classgt; lt;/filtergt; lt;filter-mappinggt;   lt;filter-namegt;springSecurityFilterChainlt;/filter-namegt;   lt;ucl-patterngt;/*lt;/ucl-patterngt; lt;/filter-mappinggt; lt;welcome-file-listgt;   lt;welcome-filegt;login.jsplt;/welcome-filegt; lt;/welcome-file-listgt; lt;servletgt;   lt;servlet-namegt;springlt;/servlet-namegt;   lt;servlet-classgt;org..web.servlet.DispatcherServletlt;/servlet-classgt;   lt;load-on-startupgt;1lt;/load-on-startupgt; lt;/servletgt; lt;servlet-mappinggt;   lt;servlet-namegt;springlt;/servlet-namegt;   lt;ucl-patterngt;*.htmllt;/ucl-patterngt; lt;/servlet-mappinggt;
lt;/web-appgt;
ok i think this is enough, i hope we can find the mistake..
thanks a lot

Nothing from this really jumps out at me as causing the problem. A few follow up questions:

What Servlet Container are you using?
What version of Spring are you using?
What version of Spring Security are you using?

what is a servlet container?

spring is version 3.0.5
spring security is version 3.0.4

what is a servlet container?

What do you deploy your application to? For example Tomcat 7.0.1, Jetty 6.0, etc.

Typically the UserDetails objects should not be mutable. Just to make the environment a bit more controlled try replacing your authentication manager with Spring's in memory implementation.

The other thing to do is enabling logging and see if that helps. If it doesn't you can post the logs to this thread.


Originally Posted by rwinchWhat do you deploy your application to? For example Tomcat 7.0.1, Jetty 6.0, etc.

ah ok it runs on tomcat 7.0.6.Originally Posted by rwinchTypically the UserDetails objects should not be mutable.

you mean i should not change such an object during runtime?Originally Posted by rwinchJust to make the environment a bit more controlled try replacing your authentication manager with Spring's in memory implementation.

i don't have a custom authentication manager, login authentication is completely done by spring.

i would like to understand why attr.getRequest().getUserPrincipal() obviously returns the right user, while SecurityContextHolder.getContext() does not..

System.out.println(SecurityContextHolder.getContex  t().toString());

What does this output for both browsers?Originally Posted by overrideyou mean i should not change such an object during runtime?

I mean that it should not have setter methods.Originally Posted by overridei don't have a custom authentication manager, login authentication is completely done by spring.

I probably should have been a bit more clear. Replace your UserDetailsService (which is used by Spring Security's AuthenticationProvider, which is used by Spring Security's AuthenticationManager) with Spring Security's in memory implementation. This would be a temporary measure to help reduce where the problem is.

Please also try to enable logging to see if that helps shed some light into the situation. If it does not help, then post the logs.
¥
Back Forum Reply New