Uploaded image for project: 'Confluence Data Center'
  1. Confluence Data Center
  2. CONFSERVER-21977

Updating user's propertySet should not throw exception even if user being updated by two servers in cluster at once

    XMLWordPrintable

Details

    Description

      Hello,

      It seems that Juha Ojaluoma may have found a bug with the UserAccessor as used in a custom authenticator. Here is the code that we will use in the Shibboleth Authenticator for Confluence (not asking for support of plugin or support of development of that plugin, only asking for support of the Confluence API). If you take out the synchronization block, you should be able to reproduce the exception caused by trying to update the same user's properties in two different transactions by what Erkki is saying. Could you add Juha Ojaluoma and/or Erkki Aalto to this ticket?

      import com.atlassian.confluence.user.UserPreferencesKeys;
      import com.opensymphony.module.propertyset.PropertyException;
      import com.atlassian.confluence.user.UserAccessor;
      import com.atlassian.user.User;
      ...
      /**
           * Updates last login and previous login dates. Contributed by Erkki Aalto and written by Juha Ojaluoma.
           *
           * @author Juha Ojaluoma
           */
          private void updateLastLogin(Principal principal) {
      
              //Set last login date
      
              // synchronize on the user name -- it's quite alright to update the property sets of two different users
              // in seperate concurrent transactions, but two concurrent transactions updateing the same user's property
              // set dies.
              //synchronized (userid.intern()) {
              // note: made a few slight changes to code- Gary.
              UserAccessor userAccessor = getUserAccessor();
              User user = (User)principal;
              String userId = user.getName();
              // TODO: Shouldn't synchronize, because that wouldn't help in a Confluence cluster (diff JVMs) for Confluence Enterprise/Confluence Massive. This should be added as a Confluence bug.
              synchronized (userId) {
                  try {
                      Date previousLoginDate = userAccessor.getPropertySet(user).getDate(UserPreferencesKeys.PROPERTY_USER_LAST_LOGIN_DATE);
                      if (previousLoginDate != null) {
                          try {
                              userAccessor.getPropertySet(user).remove(UserPreferencesKeys.PROPERTY_USER_LAST_LOGIN_DATE);
                              userAccessor.getPropertySet(user).setDate(UserPreferencesKeys.PROPERTY_USER_LAST_LOGIN_DATE, new Date());
                              userAccessor.getPropertySet(user).remove(UserPreferencesKeys.PROPERTY_USER_PREVIOUS_LOGIN_DATE);
                              userAccessor.getPropertySet(user).setDate(UserPreferencesKeys.PROPERTY_USER_PREVIOUS_LOGIN_DATE,previousLoginDate);
                          }
                          catch (PropertyException ee) {
                              log.error("Problem updating last login date/previous login date for user '" + userId + "'", ee);
                          }
                      } else {
                          try {
                              userAccessor.getPropertySet(user).remove(UserPreferencesKeys.PROPERTY_USER_LAST_LOGIN_DATE);
                              userAccessor.getPropertySet(user).setDate(UserPreferencesKeys.PROPERTY_USER_LAST_LOGIN_DATE, new Date());
                              userAccessor.getPropertySet(user).remove(UserPreferencesKeys.PROPERTY_USER_PREVIOUS_LOGIN_DATE);
                              userAccessor.getPropertySet(user).setDate(UserPreferencesKeys.PROPERTY_USER_PREVIOUS_LOGIN_DATE, new Date());
                          }
                          catch (PropertyException ee) {
                              log.error("There was a problem updating last login date/previous login date for user '" + userId + "'", ee);
                          }
                      }
                  }
                  catch (Exception e) {
                      log.error("Can not retrieve the user ('" + userId + "') to set its Last-Login-Date!", e);
                  }
                  catch (Throwable t) {
                      log.error("Error while setting the user ('" + userId + "') Last-Login-Date!", t);
                  }
              }
          }
      

      Attachments

        Activity

          People

            psemeniuk Petro Semeniuk (Inactive)
            6e54f9dce0da Gary Weaver
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: