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

Custom authenticators fail with ClassCastException: com.atlassian.confluence.user.SessionSafePrincipal cannot be cast to com.atlassian.user.User

    XMLWordPrintable

Details

    Description

      The Siteminder authenticator is broken with Confluence 4.1 and later due to a change to Confluence's internal authentication process.

      The actual error message is really unobvious:

      2012-09-06 14:20:02,188 ERROR [http-8080-1] [[Catalina].[localhost].[/wiki].[action]] log Servlet.service() for servlet action threw exception
      java.lang.ClassCastException: com.atlassian.confluence.user.SessionSafePrincipal cannot be cast to com.atlassian.user.User
      	at com.atlassian.confluence.user.AuthenticatedUserThreadLocal.getUser(AuthenticatedUserThreadLocal.java:25)
      	at com.atlassian.confluence.util.UserThreadLocalFilter.doFilter(UserThreadLocalFilter.java:36)
              ...
      

      It looks like all the custom authenticators expect the Principal in the session to be a com.atlassian.user.User, and return that from the Authenticator.getUser() method. If the session-bound Principal isn't a User object, the authentication still succeeds, and the failure appears in a call to AuthenticatedUserThreadLocal later in the request.

      Here's the relevant code snippet which appears in all our custom authenticators:

      public class SiteMinderAuthenticator extends ConfluenceAuthenticator
      {
          // ...
      
          public Principal getUser(final HttpServletRequest request, HttpServletResponse response)
          {
              // ...
      
              final HttpSession existingSession = request.getSession(false);
              if (existingSession != null && existingSession.getAttribute(DefaultAuthenticator.LOGGED_IN_KEY) != null)
              {
                  Principal loggedInUser = (Principal) existingSession.getAttribute(DefaultAuthenticator.LOGGED_IN_KEY);
                  log.debug("{} is already logged in.", loggedInUser.getName());
                  return loggedInUser;
              }
      
              // ...
          }
      
          // ...
      }
      

      The simple fix is to use getUserFromSession() in the authenticator, instead of getting the principal and returning it from getUser() directly, although I'm not sure yet whether this is backwards compatible.

      However, since Confluence relies on the authenticator returning a User object not just a regular Principal from getUser(), it would also be helpful to enforce at authentication time that the authenticator is returning a User object. Then this problem would have a much more obvious error message, not an obscure failure in AuthenticatorUserThreadLocal somewhere later in the request.

      Attachments

        Activity

          People

            Unassigned Unassigned
            matt@atlassian.com Matt Ryall
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: