Details
-
Bug
-
Resolution: Fixed
-
Medium
-
3.0
-
None
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); } } }