src/main/java/org/imsglobal/lti/BasicLTIUtil.java
public static String postLaunchHTML(
            final Map<String, String> cleanProperties, String endpoint, boolean debug) {
        if (cleanProperties == null || cleanProperties.isEmpty()) {
            throw new IllegalArgumentException(
                    "cleanProperties == null || cleanProperties.isEmpty()");
        }
        if (endpoint == null) {
            throw new IllegalArgumentException("endpoint == null");
        }
        Map<String, String> newMap = null;
        if (debug) {
            // sort the properties for readability
            newMap = new TreeMap<String, String>(cleanProperties);
        } else {
            newMap = cleanProperties;
        }
        StringBuilder text = new StringBuilder();
        // paint form
        text.append("<div id=\"ltiLaunchFormSubmitArea\">\n");
        text.append("<form action=\"");
        text.append(endpoint);
        text.append("\" name=\"ltiLaunchForm\" id=\"ltiLaunchForm\" method=\"post\" ");
        text.append(" encType=\"application/x-www-form-urlencoded\" accept-charset=\"utf-8\">\n");
        for (Entry<String, String> entry : newMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            if (value == null) {
                continue;
            }
            // This will escape the contents pretty much - at least
            // we will be safe and not generate dangerous HTML
            key = htmlspecialchars(key);
            value = htmlspecialchars(value);
            if (key.equals(BASICLTI_SUBMIT)) {
                text.append("<input type=\"submit\" name=\"");
            } else {
                text.append("<input type=\"hidden\" name=\"");
            }
            text.append(key);
            text.append("\" value=\"");
            text.append(value);
            text.append("\"/>\n");
        }
        text.append("</form>\n");
        text.append("</div>\n");

        // Paint the auto-pop up if we are transitioning from https: to http:
        // and are not already the top frame...
        text.append("<script type=\"text/javascript\">\n");
        text.append("if (window.top!=window.self) {\n");
        text.append("  theform = document.getElementById('ltiLaunchForm');\n");
        text.append("  if ( theform && theform.action ) {\n");
        text.append("   formAction = theform.action;\n");
        text.append("   ourUrl = window.location.href;\n");
        text.append("   if ( formAction.indexOf('http://') == 0 && ourUrl.indexOf('https://') == 0 ) {\n");
        text.append("      theform.target = '_blank';\n");
        text.append("      window.console && console.log('Launching http from https in new window!');\n");
        text.append("    }\n");
        text.append("  }\n");
        text.append("}\n");
        text.append("</script>\n");

        // paint debug output
        if (debug) {
            text.append("<pre>\n");
            text.append("<b>BasicLTI Endpoint</b>\n");
            text.append(endpoint);
            text.append("\n\n");
            text.append("<b>BasicLTI Parameters:</b>\n");
            for (Entry<String, String> entry : newMap.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (value == null) {
                    continue;
                }
                text.append(htmlspecialchars(key));
                text.append("=");
                text.append(htmlspecialchars(value));
                text.append("\n");
            }
            text.append("</pre>\n");
        } else {
            // paint auto submit script
            text
                    .append(" <script language=\"javascript\"> \n"
                            + "	document.getElementById(\"ltiLaunchFormSubmitArea\").style.display = \"none\";\n"
                            + "	nei = document.createElement('input');\n"
                            + "	nei.setAttribute('type', 'hidden');\n"
                            + "	nei.setAttribute('name', '"
                            + BASICLTI_SUBMIT
                            + "');\n"
                            + "	nei.setAttribute('value', '"
                            + newMap.get(BASICLTI_SUBMIT)
                            + "');\n"
                            + "	document.getElementById(\"ltiLaunchForm\").appendChild(nei);\n"
                            + "	document.ltiLaunchForm.submit(); \n" + " </script> \n");
        }

        String htmltext = text.toString();
        return htmltext;
    }
public static String postLaunchHTML(
            final Map<String, String> cleanProperties, String endpoint, boolean debug) {
        if (cleanProperties == null || cleanProperties.isEmpty()) {
            throw new IllegalArgumentException(
                    "cleanProperties == null || cleanProperties.isEmpty()");
        }
        if (endpoint == null) {
            throw new IllegalArgumentException("endpoint == null");
        }
        Map<String, String> newMap = null;
        if (debug) {
            // sort the properties for readability
            newMap = new TreeMap<String, String>(cleanProperties);
        } else {
            newMap = cleanProperties;
        }
        StringBuilder text = new StringBuilder();
        // paint form
        text.append("<div id=\"ltiLaunchFormSubmitArea\">\n");
        text.append("<form action=\"");
        text.append(endpoint);
        text.append("\" name=\"ltiLaunchForm\" id=\"ltiLaunchForm\" method=\"post\" ");
        text.append(" encType=\"application/x-www-form-urlencoded\" accept-charset=\"utf-8\">\n");
        for (Entry<String, String> entry : newMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            if (value == null) {
                continue;
            }
            // This will escape the contents pretty much - at least
            // we will be safe and not generate dangerous HTML
            key = htmlspecialchars(key);
            value = htmlspecialchars(value);
            if (key.equals(BASICLTI_SUBMIT)) {
                text.append("<input type=\"submit\" name=\"");
            } else {
                text.append("<input type=\"hidden\" name=\"");
            }
            text.append(key);
            text.append("\" value=\"");
            text.append(value);
            text.append("\"/>\n");
        }
        text.append("</form>\n");
        text.append("</div>\n");

        // Paint the auto-pop up if we are transitioning from https: to http:
        // and are not already the top frame...
        text.append("<script type=\"text/javascript\">\n");
        text.append("if (window.top!=window.self) {\n");
        text.append("  theform = document.getElementById('ltiLaunchForm');\n");
        text.append("  if ( theform && theform.action ) {\n");
        text.append("   formAction = theform.action;\n");
        text.append("   ourUrl = window.location.href;\n");
        text.append("   if ( formAction.indexOf('http://') == 0 && ourUrl.indexOf('https://') == 0 ) {\n");
        text.append("      theform.target = '_blank';\n");
        text.append("      window.console && console.log('Launching http from https in new window!');\n");
        text.append("    }\n");
        text.append("  }\n");
        text.append("}\n");
        text.append("</script>\n");

        // paint debug output
        if (debug) {
            text.append("<pre>\n");
            text.append("<b>BasicLTI Endpoint</b>\n");
            text.append(endpoint);
            text.append("\n\n");
            text.append("<b>BasicLTI Parameters:</b>\n");
            for (Entry<String, String> entry : newMap.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (value == null) {
                    continue;
                }
                text.append(htmlspecialchars(key));
                text.append("=");
                text.append(htmlspecialchars(value));
                text.append("\n");
            }
            text.append("</pre>\n");
        } else {
            // paint auto submit script
            text
                    .append(" <script language=\"javascript\"> \n"
                            + "	document.getElementById(\"ltiLaunchFormSubmitArea\").style.display = \"none\";\n"
                            + "	nei = document.createElement('input');\n"
                            + "	nei.setAttribute('type', 'hidden');\n"
                            + "	nei.setAttribute('name', '"
                            + BASICLTI_SUBMIT
                            + "');\n"
                            + "	nei.setAttribute('value', '"
                            + newMap.get(BASICLTI_SUBMIT)
                            + "');\n"
                            + "	document.getElementById(\"ltiLaunchForm\").appendChild(nei);\n"
                            + "	document.ltiLaunchForm.submit(); \n" + " </script> \n");
        }

        String htmltext = text.toString();
        return htmltext;
    }
Create the HTML to render a POST form and then automatically submit it.
Make sure to call {@link #cleanupProperties(Properties)} before signing.

@param cleanProperties Assumes you have called
{@link #cleanupProperties(Properties)} beforehand.
@param endpoint The LTI launch url.
@param debug Useful for viewing the HTML before posting to end point.
@return the HTML ready for IFRAME src = inclusion.