Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Eclipse Scout » [Solved] Session quirks - User loading session meant for someone else in the UI(A user can inadvertently load a session in the UI meant for another user)
[Solved] Session quirks - User loading session meant for someone else in the UI [message #1864014] Mon, 11 March 2024 14:34 Go to next message
J D is currently offline J DFriend
Messages: 103
Registered: February 2021
Senior Member
Hi there everyone,

I've recently discovered that sometimes a user can inadvertently load another user's session in the UI of my application. The UI then clearly displays another username and loads that other user's permissions.

It does not happen when the user logs in. It sometimes happens when the user clicks the refresh button in the browser or first closes the tab and then chooses to reopen the closed tab using the browser's "Reopen closed tab" menu option.

I don't know why this is happening. Has anyone experienced this sort of problem?

What can I do to prevent these "session quirks/gliches" because it becomes a problem if a user gains access to a session with admin rights for example?

Thanks a lot for your kind assistance.

Cheers,

JD

[Updated on: Tue, 16 April 2024 10:36]

Report message to a moderator

Re: Session quirks - User loading session meant for someone else in the UI [message #1864020 is a reply to message #1864014] Mon, 11 March 2024 19:26 Go to previous messageGo to next message
Matthias OtterbachFriend
Messages: 58
Registered: August 2015
Location: Munich
Member
Sound like a serious problem; is this locally reproducible? I don't think we have experienced such problems.

Which exact version are you using? Do you have any log output when this problem occurs? Is the session just started for the "wrong user" (log output "Client/Server session started [...]") - or is it a session which was previously already started? Was a session for the other user started at all previously?

Do the users directly access the application server (which are you using)? Or are there any proxies? How are the users authenticated?
Re: Session quirks - User loading session meant for someone else in the UI [message #1864095 is a reply to message #1864020] Fri, 15 March 2024 13:03 Go to previous messageGo to next message
J D is currently offline J DFriend
Messages: 103
Registered: February 2021
Senior Member
Hi there Matthias,

Thanks for your reply.

1) I'll try and answer your questions one after the other

a) Which exact version are you using?

I'm using Eclipse Scout 23.2

b) Do you have any log output when this problem occurs?

No I don't. I have some logs, but I do not know exactly when this occurs in the log

c) Is the session just started for the "wrong user" (log output "Client/Server session started [...]") - or is it a session which was previously already started?

The session is started for the right user because permissions have to be retrieved. It is just that when several sessions are active, sometimes a page refresh loads the wrong session.

d) Was a session for the other user started at all previously?

Yes it was.

e) Do the users directly access the application server (which are you using)? Or are there any proxies?

Users access the application server directly. There are no proxies.

f) How are the users authenticated?

Users are authenticated against a database behind a REST server. The REST server receives the username and password, passes it to the database and the database returns the user's id, fullname and roleId/groupId. This roleId/groupId is then used to fetch the user's permissions.

The authentication works OK.

The first indication that sessions have crossed is when a user notices that someone else's name is displayed in the UI and/or permissions are no longer what the user is used to.

2) I did some searching on the Net and I found out that Tomcat had some problems with sessions crossing in the past.

Apache Tomcat user session mix up and DoS
https://alphabot.com/security/blog/2018/java/Apache-Tomcat-user-session-mix-up-and-DoS.html#user-sessions-can-get-mixed-up

Bug 1607582 (CVE-2018-8037) - CVE-2018-8037 tomcat: Due to a mishandling of close in NIO/NIO2 connectors user sessions can get mixed up
https://bugzilla.redhat.com/show_bug.cgi?id=1607582

CVE-2018-8037 Detail
https://nvd.nist.gov/vuln/detail/CVE-2018-8037

Apache Tomcat 9.x vulnerabilities
https://tomcat.apache.org/security-9.html

It appears that it affects Apache Tomcat 9.0.0.M9 to 9.0.9 and 8.5.5 to 8.5.31.

I'm using Apache Tomcat 9.0.80


Cheers,

JD

[Updated on: Fri, 15 March 2024 13:04]

Report message to a moderator

Re: Session quirks - User loading session meant for someone else in the UI [message #1864506 is a reply to message #1864095] Wed, 20 March 2024 13:36 Go to previous messageGo to next message
Beat Schwarzentrub is currently offline Beat SchwarzentrubFriend
Messages: 214
Registered: November 2010
Senior Member
Hi JD

Are you absolutely sure that there is no intermediate server between the browser and the application server? There are a lot of components that are invisible but can still break things when improperly configured, e.g. load balancers or firewalls.

You should definitively check your logs. By default, there should be enough log messages on level INFO to reconstruct when and which type of session was created.

In a classic Scout applications you will find 3 types of "sessions":


  1. The HTTP session (HttpSession) is created and managed by the servlet container. The application can access the HTTP session through the standard J2EE API. It represents a "state" on the server. Its unique ID is stored in the cookie JSESSIONID and is sent along every subsequent HTTP request by the browser. This allows the container to match a (usually stateless) HTTP call with the existing HTTP session.
  2. The client session (ISession) is a Scout-specific object that consists of the application model. It contains all outlines, pages, forms, fields etc.
  3. The UI session (IUiSession ) connects the current browser window with a client session. It sends events from the model to the browser and vice-versa. It does not have a state of its own.


If you open a Scout application twice in two tabs in the same browser, they will share the same HTTP session (because cookies are shared between all tabs), but have two different client sessions (because the clientSessionId is stored the browser's "session storage", which is not shared between tabs). When you reload one of the tabs, the same client session will be re-used, but a new UI session will be created. If you open the application in two different browsers, you will have two different HTTP sessions, because the JSESSION cookie is not shared between browsers.

The scout sessions (client session, UI session) are stored in a "Session Store" object that itself is stored in a HTTP session attribute. This ensures that even if two different users were to request the same client session ID, they would not receive the same client session, because they can't see each other's session store.

index.php/fa/44078/0/

The situation you describe would only be possible if both users used the same HTTP session. Under normal circumstances this is impossible, because a new HTTP session is always created after a successful login (see FormBasedAccessController.handleAuthRequest). After that, the mapping from the JSESSIONID cookie to the HttpSession is done automatically by the container, before Scout is even involved. Did you check your Tomcat configuration? The default configuration should be fine, but if you have special settings or "login modules" installed, something might not work as expected. If you use your own AccessController implementation, please also carefully examine your code for any potential session mixups.

Beat
Re: Session quirks - User loading session meant for someone else in the UI [message #1864551 is a reply to message #1864014] Fri, 22 March 2024 15:16 Go to previous messageGo to next message
Mr Robot is currently offline Mr RobotFriend
Messages: 72
Registered: March 2020
Member
Can you show code for ServerSession execLoadSession?

Do you set "currentUser" in session shared variable? If yes, how do you load it?
Re: Session quirks - User loading session meant for someone else in the UI [message #1864627 is a reply to message #1864551] Fri, 29 March 2024 15:04 Go to previous messageGo to next message
J D is currently offline J DFriend
Messages: 103
Registered: February 2021
Senior Member
@Mr Robot and @Beat - thank you both for your kind assistance. Reading your responses helped me focus on how my ServerSession retrieves shared variables. This is a long post but please bear with me.

This is my ServerSession.java file

public class ServerSession extends AbstractServerSession {

  private static final long serialVersionUID = 1L;
  private static final Logger LOG = LoggerFactory.getLogger(ServerSession.class);

  public ServerSession() {
    super(true);
  }

  /**
   * @return The {@link ServerSession} which is associated with the current thread, or {@code null}
   *         if not found.
   */
  public static ServerSession get() {
    return ServerSessionProvider.currentSession(ServerSession.class);
  }

  /*
   * Sometimes the WRONG session is loaded!!!
   */
  @Override
  protected void execLoadSession() {
    // Initialize shared context variables
    setDbUserId(BEANS.get(IRestAuthenticationService.class).getDbUserId());
    setRoleId(BEANS.get(IRestAuthenticationService.class).getRoleId());
    setUserName(BEANS.get(IRestAuthenticationService.class).getDbUserName());

    //
    LOG.info("Created a new session for {}/{}", getDbUserId(), getUserName());
  }

  /*
   * My getters and setters to share variables
   * @link
   * https://www.eclipse.org/forums/index.php/m/1553093/?srch=getSharedContextVariable#msg_1553093
    * @Link
   * https://stackoverflow.com/questions/62936478/how-can-i-access-the-request-httpsession-from-
   * scout-client-side-code/62995731#62995731
   */
  public String getDbUserId() {
    return get().getSharedContextVariable("dbUserId", String.class);
  }

  public void setDbUserId(String newValue) {
    get().setSharedContextVariable("dbUserId", String.class, newValue);
  }

  public String getUserName() {
    return get().getSharedContextVariable("userName", String.class);
  }

  public void setUserName(String newValue) {
    get().setSharedContextVariable("userName", String.class, newValue);
  }

  public String getRoleId() {
    return get().getSharedContextVariable("roleId", String.class);
  }

  public void setRoleId(String newValue) {
    get().setSharedContextVariable("roleId", String.class, newValue);
  }
}


I think the problem is the execLoadSession method of ServerSession.java. While it works for a new user login, if the user refreshes his browser tab and a new session is created, there is NO guarantee that the same user's session will be reloaded IF many users are already logged in.


This is the RestAuthenticationService.java file

public class RestAuthenticationService implements IRestAuthenticationService {
  private static final Logger LOG = LoggerFactory.getLogger(RestAuthenticationService.class);

  private String message;

  private String dbUserId;

  private String roleId;

  private String username;

  @Override
  public Map<String, String> verify(String username, String hashedPassword) {
    Map<String, String> result = new HashMap<>();

    try {
      Response response = BEANS.get(RestAuthenticationResourceClient.class)
          .login(createEntity(username, hashedPassword));

      if (response.getStatus() == Response.Status.OK.getStatusCode()) {
        LoginEntityDo loginResult =
            (LoginEntityDo) response.readEntity(LoginResponseEntityDo.class).result().first();

        // Test for a successful login based on whether the result has an exception or not
        if (loginResult.exception().exists()) {
          // login failed
          result.put("message", loginResult.getException());
          result.put("username", loginResult.getFirstName() + " " + loginResult.getLastName());
          setMessage(loginResult.getException());
        } else {
          // login succeeded
          result.put("message", loginResult.getResponse());
          result.put("username", loginResult.getFirstName() + " " + loginResult.getLastName());
          result.put("id", loginResult.getId());
          //
          setDbUserName(loginResult.getFirstName() + " " + loginResult.getLastName());
          setMessage(loginResult.getResponse());
          setDbUserId(loginResult.getId());
          setRoleId(loginResult.getRoleId());          
          //
          LOG.info("User {} with ID {} logged in successfully. Server message: {}", getDbUserName(),
              getDbUserId(), getMessage());
        }
      }
    } catch (RuntimeException e) {
      LOG.error(e.getMessage());
      BEANS.get(ExceptionHandler.class).handle(e);
      throw new VetoException(/* getMessage() + "\n" + */ e.getMessage());
    }
    //
    return result;
  }

  /*
   * Creates the user authentification entity with hashed password that is sent to the REST server
   */
  private UserAuthentificationEntityDo createEntity(String username, String hashedPassword) {
    UserAuthentificationEntityDo user = new UserAuthentificationEntityDo();

    user.username().set(username);
    user.password().set(hashedPassword);
    //
    return user;
  }

  @Override
  public String getMessage() {
    return StringUtility.hasText(message) ? message : null;
  }

  @Override
  public void setMessage(String message) {
    this.message = message;
  }

  @Override
  public void setDbUserId(String id) {
    this.dbUserId = id;
  }

  @Override
  public String getDbUserId() {
    return StringUtility.hasText(dbUserId) ? dbUserId : null;
  }

  @Override
  public String getRoleId() {
    return StringUtility.hasText(roleId) ? roleId : null;
  }

  @Override
  public void setRoleId(String _roleId) {
    roleId = _roleId;
  }

  @Override
  public String getDbUserName() {
    return StringUtility.hasText(username) ? username : null;
  }

  @Override
  public void setDbUserName(String name) {
    username = name;
  }
}


Finally, the ClientSession.java file is:

public class ClientSession extends AbstractClientSession {
  private static final Logger LOG = LoggerFactory.getLogger(ClientSession.class);

  public static final String PREF_USER_LOCALE = "PREF_USER_LOCALE";

  public ClientSession() {
    super(true);
  }

  /**
   * @return The {@link IClientSession} which is associated with the current thread, or {@code null}
   *         if not found.
   */
  public static ClientSession get() {
    return ClientSessionProvider.currentSession(ClientSession.class);
  }

  @Override
  protected void execLoadSession() {
    // pre-load all known code types
    CODES.getAllCodeTypes("org.eclipse.scout.apps.yougenie.shared");

    // The locale needs to be set before the Desktop is created.
    String localeString =
        ClientUIPreferences.getClientPreferences(get()).get(PREF_USER_LOCALE, "fr-FR");
    if (localeString != null) {
      setLocale(Locale.forLanguageTag(localeString));
    }

    setDesktop(new Desktop());

    LOG.info("Loaded client session for {} on {}", get().getUserName(), LocalDateTime.now());
  }

  //
  // Getters for SharedContextVariables
  //
  public String getDbUserId() {
    return get().getSharedContextVariable("dbUserId", String.class);
  }

  public String getRoleId() {
    return get().getSharedContextVariable("roleId", String.class);
  }

  public String getUserName() {
    return get().getSharedContextVariable("userName", String.class);
  }
}


I would love to be able to add a user's database profile (database Id, full name, role Id) to the user's session profile (a Map structure perhaps?) and then use this enhanced session profile to create the appropriate user interface/permissions and use it for tab reloads too. However, I don't know how I can do that at the moment.

Any suggestions/code snippets will be greatly appreciated.

JD
Re: Session quirks - User loading session meant for someone else in the UI [message #1864632 is a reply to message #1864627] Sat, 30 March 2024 10:56 Go to previous messageGo to next message
Beat Schwarzentrub is currently offline Beat SchwarzentrubFriend
Messages: 214
Registered: November 2010
Senior Member
Quote:
I think the problem is the execLoadSession method of ServerSession.java.


No, the problem is caused by the state in your RestAuthenticationService. It appears that you use it as your ICredentialVerifier during login. That bean is marked as @ApplicationScoped, so there will be only a single instance of this class for all users. Usually, this is fine, but by adding members and writing data to them you made it stateful. Every time a user logs in, that state is overwritten with new values. No matter which session later accesses the data, they will always see the same data.

Here are a few ideas on how to fix this:


  • Split your REST service into two methods. The first only checks the credentials (valid or invalid), the second returns the additional data for a given username. The first method is used in the credential verifier, the second in the execLoad() method of the server session (when the user is already authenticated). This is the classic approach.
  • Implement your own IAccessController and after verification, write the received data to the JAAS principal (using IPrincipalProducer2, since the normal IPrincipalProducer can only use the username). This allows you to access those params again when creating the scout session.
  • In the credential verifier, store the additional data somewhere else. For example, a map with the userId as key, or a ThreadLocal.


In any case, you have to remove all members from your RestAuthenticationService class (message, dbUserId, roleId, username). This will never work correctly.

On a side note, why are you accessing the shared context variables via the static get() method? This is not necessary, just call the methods on the current instance.

Beat
Re: Session quirks - User loading session meant for someone else in the UI [message #1864756 is a reply to message #1864632] Sun, 07 April 2024 14:19 Go to previous message
J D is currently offline J DFriend
Messages: 103
Registered: February 2021
Senior Member
Beat Schwarzentrub wrote on Sat, 30 March 2024 10:56

Here are a few ideas on how to fix this:

Split your REST service into two methods. The first only checks the credentials (valid or invalid), the second returns the additional data for a given username. The first method is used in the credential verifier, the second in the execLoad() method of the server session (when the user is already authenticated). This is the classic approach.

Beat


hi there Beat,

Thanks a million for the clarification. I've opted for the classic approach you outlined in your reply.

My ServerSession's execLoadSession method now looks like this:

  @Override
  protected void execLoadSession() {
    // Fetch session properties for the given userId
    SessionPropertiesEntityDo session = (SessionPropertiesEntityDo) BEANS
        .get(ISessionPropertiesService.class).getSessionProperties(getUserId());
    // Initialize shared context variables
    setDbUserId(session.getDbUserId());
    setRoleId(session.getRoleId());
    setUserName(session.getFullName());
    //
    LOG.info("Created a new session for {}/{}", getDbUserId(), getUserName());
  }


I also ensured that the ISessionPropertiesService interface is NOT marked as @ApplicationScoped.

Cheers,

JD
Previous Topic:Server/Ui-Session List and the Upcoming Release
Next Topic:Extend Desktop with fixed Form / View
Goto Forum:
  


Current Time: Sat Nov 09 02:21:31 GMT 2024

Powered by FUDForum. Page generated in 0.05506 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top