@SuppressWarnings("unchecked")
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    String ipAddress = request.getRemoteAddr();

    if (M_log.isDebugEnabled()) {
      M_log.debug("Basic LTI Provider request from IP=" + ipAddress);
    }

    String enabled = ServerConfigurationService.getString("basiclti.provider.enabled", null);
    if (enabled == null || !("true".equals(enabled))) {
      M_log.warn("Basic LTI Provider is Disabled IP=" + ipAddress);
      response.sendError(HttpServletResponse.SC_FORBIDDEN, "Basic LTI Provider is Disabled");
      return;
    }

    if ("/casa.json".equals(request.getPathInfo())) {
      if (ServerConfigurationService.getBoolean("casa.provider.enabled", true)) {
        handleCASAList(request, response);
        return;
      } else {
        M_log.warn("CASA Provider is Disabled IP=" + ipAddress);
        response.sendError(HttpServletResponse.SC_FORBIDDEN, "CASA Provider is Disabled");
        return;
      }
    }

    if ("/canvas-config.xml".equals(request.getPathInfo())) {
      if (ServerConfigurationService.getBoolean("canvas.config.enabled", true)) {
        handleCanvasConfig(request, response);
        return;
      } else {
        M_log.warn("Canvas config is Disabled IP=" + ipAddress);
        response.sendError(HttpServletResponse.SC_FORBIDDEN, "Canvas config is Disabled");
        return;
      }
    }

    // If this is a LTI request of any kind, make sure we don't have any
    // prior payload in the session.
    if (BasicLTIUtil.isRequest(request)) {
      Session sess = SessionManager.getCurrentSession();
      sess.removeAttribute("payload");
    }

    // Check if we support ContentItem.
    // If we are doing ContentItem and have a payload and are not a launch
    // short-circuit to ContentItem
    if ("/content.item".equals(request.getPathInfo())) {
      if (!ServerConfigurationService.getBoolean("contentitem.provider", true)) {
        M_log.warn("ContentItem is Disabled IP=" + ipAddress);
        response.sendError(HttpServletResponse.SC_FORBIDDEN, "ContentItem is Disabled");
        return;
      } else {
        Session sess = SessionManager.getCurrentSession();
        Map session_payload = (Map) sess.getAttribute("payload");
        if (session_payload != null) {
          // Post-Login requests to content.item
          M_log.debug("ContentItem already logged in " + sess.getUserId());
          handleContentItem(request, response, session_payload);
          return;
        }
      }
    }

    if (M_log.isDebugEnabled()) {
      Map<String, String[]> params = (Map<String, String[]>) request.getParameterMap();
      for (Map.Entry<String, String[]> param : params.entrySet()) {
        M_log.debug(param.getKey() + ":" + param.getValue()[0]);
      }
    }

    Map payload = getPayloadAsMap(request);

    // Get the list of highly trusted consumers from sakai.properties.
    // If the incoming consumer is highly trusted, we use the context_id and
    // site_id as is,
    // ie without prefixing them with the oauth_consumer_key first.
    // We also don't both checking their roles in the site.
    boolean isTrustedConsumer = BasicLTIProviderUtil.isHighlyTrustedConsumer(payload);

    /*
     * Get the list of email trusted consumers from sakai.properties. If the
     * incoming consumer is email trusted, we use the email address provided
     * by the consumer and look up the "user" info from sakai instead of
     * consumer's. This use case is especially valuable if 2 different LMS's
     * acting as TP and TC referring to same user and can be uniquely
     * identified by email address. more details SAK-29372
     */
    boolean isEmailTrustedConsumer = BasicLTIProviderUtil.isEmailTrustedConsumer(payload);

    /*
     * Checking if the email trusted consumer property and trusted consumer
     * and not both enabled. the case would be an error condition
     */
    if (isTrustedConsumer && isEmailTrustedConsumer) {
      M_log.warn(
          "Both Email Trusted and Trusted Consumer property is enabled, this is invalid  IP="
              + ipAddress);
      response.sendError(
          HttpServletResponse.SC_FORBIDDEN,
          "Both Email Trusted and Trusted Consumer property is enabled, this is invalid ");
      return;
    }

    try {
      invokeProcessors(payload, isTrustedConsumer, ProcessingState.beforeValidation);

      validate(payload, isTrustedConsumer);

      invokeProcessors(payload, isTrustedConsumer, ProcessingState.afterValidation);

      User user =
          userFinderOrCreator.findOrCreateUser(payload, isTrustedConsumer, isEmailTrustedConsumer);

      invokeProcessors(payload, isTrustedConsumer, ProcessingState.afterUserCreation, user);

      // Check if we are loop-backing on the same server, and already logged in as same user
      Session sess = SessionManager.getCurrentSession();
      String serverUrl = SakaiBLTIUtil.getOurServerUrl();
      String ext_sakai_server = (String) payload.get("ext_sakai_server");

      if ("/content.item".equals(request.getPathInfo())
          && isTrustedConsumer
          && ext_sakai_server != null
          && ext_sakai_server.equals(serverUrl)
          && user.getId().equals(sess.getUserId())) {

        M_log.debug("ContentItem looping back as " + sess.getUserId());
        sess.setAttribute("payload", payload);
        handleContentItem(request, response, payload);
        return;
      }

      loginUser(ipAddress, user);

      // Re-grab the session
      sess = SessionManager.getCurrentSession();

      invokeProcessors(payload, isTrustedConsumer, ProcessingState.afterLogin, user);

      // This needs to happen after login, when we have a session for the user.
      userLocaleSetter.setupUserLocale(payload, user, isTrustedConsumer, isEmailTrustedConsumer);

      userPictureSetter.setupUserPicture(payload, user, isTrustedConsumer, isEmailTrustedConsumer);

      // The first launch of content.item - no site needed
      if ("/content.item".equals(request.getPathInfo())) {
        M_log.debug("ContentItem inital external login " + sess.getUserId());
        sess.setAttribute("payload", payload);
        handleContentItem(request, response, payload);
        return;
      }

      Site site = findOrCreateSite(payload, isTrustedConsumer);

      invokeProcessors(payload, isTrustedConsumer, ProcessingState.afterSiteCreation, user, site);

      siteEmailPreferenceSetter.setupUserEmailPreferenceForSite(
          payload, user, site, isTrustedConsumer);

      site =
          siteMembershipUpdater.addOrUpdateSiteMembership(payload, isTrustedConsumer, user, site);

      invokeProcessors(payload, isTrustedConsumer, ProcessingState.afterSiteMembership, user, site);

      String toolPlacementId = addOrCreateTool(payload, isTrustedConsumer, user, site);

      invokeProcessors(payload, isTrustedConsumer, ProcessingState.beforeLaunch, user, site);

      syncSiteMembershipsOnceThenSchedule(payload, site, isTrustedConsumer, isEmailTrustedConsumer);

      // Construct a URL to this tool
      StringBuilder url = new StringBuilder();
      url.append(SakaiBLTIUtil.getOurServerUrl());
      url.append(ServerConfigurationService.getString("portalPath", "/portal"));
      url.append("/tool-reset/");
      url.append(toolPlacementId);
      url.append("?panel=Main");

      if (M_log.isDebugEnabled()) {
        M_log.debug("url=" + url.toString());
      }
      // String toolLink = ServerConfigurationService.getPortalUrl()+ "/tool-reset/" + placement_id
      // + "?panel=Main";
      // Compensate for bug in getPortalUrl()
      // toolLink = toolLink.replace("IMS BLTI Portlet", "portal");
      response.setContentType("text/html");
      response.setStatus(HttpServletResponse.SC_FOUND);
      response.sendRedirect(url.toString());

    } catch (LTIException ltiException) {
      doError(
          request,
          response,
          ltiException.getErrorKey(),
          ltiException.getMessage(),
          ltiException.getCause());
    }

    /*

    PrintWriter out = response.getWriter();
    out.println("<body><div style=\"text-align: center\">");
    out.println("&nbsp;<br/>&nbsp;<br/>&nbsp;<br/>&nbsp;<br/>");
    out.println("&nbsp;<br/>&nbsp;<br/>&nbsp;<br/>&nbsp;<br/>");
    out.println("<a href=\"" + url.toString() + "\">");
    out.println("<span id=\"hideme\">" + rb.getString("launch.continue")
    		+ "</span>");
    out.println("</a>");
    out.println(" <script language=\"javascript\"> \n"
    				+ "    document.getElementById(\"hideme\").style.display = \"none\";\n"
    				+ "    location.href=\"" + url.toString() + "\";\n"
    				+ " </script> \n");
    out.println("</div>");
    out.println("</body>");

    out.close();
    */

  }