/**
   * Authenticate the given username/password pair, in conjunction with the onBehalfOf user. The
   * rules are that the username/password pair must successfully authenticate the user, and the
   * onBehalfOf user must exist in the user database.
   *
   * @param context
   * @param auth
   * @return a SWORD context holding the various user information
   * @throws SwordAuthException
   * @throws SwordError
   * @throws DSpaceSwordException
   */
  private SwordContext authenticate(Context context, AuthCredentials auth)
      throws SwordAuthException, SwordError, DSpaceSwordException {
    String obo = auth.getOnBehalfOf();
    String un = auth.getUsername();
    String pw = auth.getPassword();

    // smooth out the OnBehalfOf request, so that empty strings are
    // treated as null
    if ("".equals(obo)) {
      obo = null;
    }

    // first find out if we support on-behalf-of deposit
    boolean mediated =
        ConfigurationManager.getBooleanProperty("swordv2-server", "on-behalf-of.enable");
    if (!mediated && obo != null) {
      // user is trying to do a mediated deposit on a repository which does not support it
      log.error("Attempted mediated deposit on service not configured to do so");
      throw new SwordError(
          UriRegistry.ERROR_MEDIATION_NOT_ALLOWED,
          "Mediated deposit to this service is not permitted");
    }

    log.info(
        LogManager.getHeader(
            context, "sword_authenticate", "username="******",on_behalf_of=" + obo));

    try {
      // attempt to authenticate the primary user
      SwordContext sc = new SwordContext();
      EPerson ep = null;
      boolean authenticated = false;
      if (this.authenticates(context, un, pw)) {
        // if authenticated, obtain the eperson object
        ep = context.getCurrentUser();

        if (ep != null) {
          authenticated = true;
          sc.setAuthenticated(ep);
          // Set any special groups - invoke the authentication mgr.
          int[] groupIDs = AuthenticationManager.getSpecialGroups(context, null);

          for (int i = 0; i < groupIDs.length; i++) {
            context.setSpecialGroup(groupIDs[i]);
            log.debug("Adding Special Group id=" + String.valueOf(groupIDs[i]));
          }

          sc.setAuthenticatorContext(context);
          sc.setContext(context);
        }

        // if there is an onBehalfOfuser, then find their eperson
        // record, and if it exists set it.  If not, then the
        // authentication process fails
        EPerson epObo = null;
        if (obo != null) {
          epObo = EPerson.findByEmail(context, obo);
          if (epObo == null) {
            epObo = EPerson.findByNetid(context, obo);
          }

          if (epObo != null) {
            sc.setOnBehalfOf(epObo);
            Context oboContext = this.constructContext();
            oboContext.setCurrentUser(epObo);
            // Set any special groups - invoke the authentication mgr.
            int[] groupIDs = AuthenticationManager.getSpecialGroups(oboContext, null);

            for (int i = 0; i < groupIDs.length; i++) {
              oboContext.setSpecialGroup(groupIDs[i]);
              log.debug("Adding Special Group id=" + String.valueOf(groupIDs[i]));
            }
            sc.setContext(oboContext);
          } else {
            authenticated = false;
            throw new SwordError(
                UriRegistry.ERROR_TARGET_OWNER_UNKNOWN,
                "unable to identify on-behalf-of user: "******"sword_unable_to_set_user", "username="******"Unable to authenticate with the supplied credentials");
        } else {
          // FIXME: this shouldn't ever happen now, but may as well leave it in just in case
          // there's a bug elsewhere
          log.info(
              LogManager.getHeader(
                  context,
                  "sword_unable_to_set_on_behalf_of",
                  "username="******",on_behalf_of=" + obo));
          throw new SwordAuthException("Unable to authenticate the onBehalfOf account");
        }
      }

      return sc;
    } catch (SQLException e) {
      log.error("caught exception: ", e);
      throw new DSpaceSwordException(
          "There was a problem accessing the repository user database", e);
    } catch (AuthorizeException e) {
      log.error("caught exception: ", e);
      throw new SwordAuthException("There was a problem authenticating or authorising the user", e);
    }
  }