/**
   * Retrieve the details of a user by username
   *
   * @param username The username of a user to retrieve
   * @param source The authentication source if known
   * @return User The user requested
   * @throws AuthenticationException if any errors occur
   */
  @Override
  public User getUser(JsonSessionState session, String username, String source)
      throws AuthenticationException {
    // Sanity check
    if (username == null || username.equals("") || source == null || source.equals("")) {
      throw new AuthenticationException("Invalid user data requested");
    }

    // SSO Users
    if (sso.containsKey(source)) {
      GenericUser user = (GenericUser) sso.get(source).getUserObject(session);
      // Sanity check our data
      if (user == null || !user.getUsername().equals(username)) {
        throw new AuthenticationException("Unknown user '" + username + "'");
      }
      return user;
    }

    // Trust token users
    if (source.startsWith(TRUST_TOKEN_PREFIX)) {
      String sUsername = (String) session.get("username");
      String sSource = (String) session.get("source");

      // We can't lookup token users so it must match
      if (sUsername == null
          || !username.equals(sUsername)
          || sSource == null
          || !source.equals(sSource)) {
        throw new AuthenticationException("Unknown user '" + username + "'");
      }

      // Seems valid, create a basic user object and return
      GenericUser user = new GenericUser();
      user.setUsername(username);
      user.setSource(source);
      return user;
    }

    // Standard users
    authManager.setActivePlugin(source);
    return authManager.getUser(username);
  }
  /**
   * Get the list of roles possessed by the current user.
   *
   * @param user The user object of the current user
   * @return String[] A list of roles
   */
  @Override
  public String[] getRolesList(JsonSessionState session, User user) {
    String source = user.getSource();
    List<String> ssoRoles = new ArrayList<String>();

    // SSO Users
    if (sso.containsKey(source)) {
      ssoRoles.addAll(sso.get(source).getRolesList(session));
    }

    // Standard Users
    GenericUser gUser = (GenericUser) user;
    String[] standardRoles = roleManager.getRoles(gUser.getUsername());
    for (String role : standardRoles) {
      // Merge the two
      if (!ssoRoles.contains(role)) {
        ssoRoles.add(role);
      }
    }

    // Cast to array and return
    return ssoRoles.toArray(standardRoles);
  }
  /**
   * Get user details from SSO connection and set them in the user session.
   *
   * @return boolean: Flag whether a user was actually logged in or not.
   */
  @Override
  public boolean ssoCheckUserDetails(JsonSessionState session) {
    // After the SSO roun-trip, restore any old query parameters we lost
    List<String> currentParams = request.getParameterNames();
    // Cast a copy of keySet() to array to avoid errors as we modify
    String[] oldParams = session.keySet().toArray(new String[0]);
    // Loop through session data...
    for (String key : oldParams) {
      // ... looking for SSO stored params
      if (key.startsWith(SSO_STORAGE_PREFIX)) {
        // Remove our prefix...
        String oldParam = key.replace(SSO_STORAGE_PREFIX, "");
        // ... and check if it survived the trip
        if (!currentParams.contains(oldParam)) {
          // No it didn't, add it to form data... the parameters are
          // already accessible from there in Jython
          String data = (String) session.get(key);
          formData.set(oldParam, data);
          // Don't forget to clear it from the session
          session.remove(key);
        }
      }
    }

    // Check our SSO providers for valid logins
    for (String ssoId : sso.keySet()) {
      sso.get(ssoId).ssoCheckUserDetails(session);
      GenericUser user = (GenericUser) sso.get(ssoId).getUserObject(session);
      if (user != null) {
        session.set("username", user.getUsername());
        session.set("source", ssoId);
        return true;
      }
    }
    return false;
  }