Closed pgoldweic closed 7 years ago
I finally arrived to a solution for the problem, after I realized that all apps which depend on LTI libraries such as this one, which in turn depend solely on the same OAuth libraries, and with no servlet filters of any kind in place, are affected by the same problem. Summary: this is an encoding issue that occurs because the Canvas LMS does not appear to set the character encoding of the LTI launch request. As a consequence, the servlet container in Java assumes the default encoding for the time zone (usually ISO-5589...), and this causes the incorrect decoding of the http parameters which are crucial in the computation of the LTI signature. The solution for me was to add a servlet filter to my LTI servlet, which sets the "UTF-8" character encoding in the request before anybody else can grab any parameters out of the request (such as the old OAuth libraries do).
Hope this helps others avoid the same problem.
Thank you! This was driving me nuts, I developed and tested the authentication into my LTI consumer with moodle what worked 100%, but when one of our clients tried it with sakai I kept on getting 'Failed to validate: signature_invalid' caused by
<imsx_statusInfo>
<imsx_codeMajor>failure</imsx_codeMajor>
<imsx_severity>status</imsx_severity>
<imsx_description>**OAuth oauth_body_hash mismatch** B64key=12345 HDRkey=12345 secret=secret</imsx_description>
<imsx_messageRefIdentifier>5723178e13436</imsx_messageRefIdentifier>
<imsx_operationRefIdentifier></imsx_operationRefIdentifier>
</imsx_statusInfo>
To debug I used https://online.dr-chuck.com/sakai-api-test/lms.php to simulate the sakai LTI tool for my consumer. And created a simple LTI consumer web application based on the basic-util source.
I've attached the servlet (LTI.java) and the servlet filter that fixes the issue.
Could I propose the following solution? Instead of using a filter, just set the encoding when the encoding is not set. For my case this is in org.imsglobal.lti.launch.LtiOauthVerifier function verify:
/**
* This method verifies the signed HttpServletRequest
* @param request the HttpServletRequest that will be verified
* @param secret the secret to verify the properties with
* @return the result of the verification, along with contextual
* information
* @throws LtiVerificationException
*/
@Override
public LtiVerificationResult verify(HttpServletRequest request, String secret) throws LtiVerificationException {
String encoding = request.getCharacterEncoding();
if (encoding==null){
try {
request.setCharacterEncoding("UTF-8");
} catch (UnsupportedEncodingException e1) {
return new LtiVerificationResult(false, LtiError.BAD_REQUEST, "The request did not have an encoding, and I could not set it to UTF-8");
}
}
OAuthMessage oam = OAuthServlet.getMessage(request, OAuthServlet.getRequestURL(request));
Looks like a good idea to me. Would be nice to have it included within the LTI library itself instead of having to rely on the clients to set the encoding (that is, either inside a filter, or, explicitly setting the request encoding in any servlet that uses the LTI library)
Unfortunately in my actual app it didn't work, it had to be done before the servlet was executed, It wasn't working without the filter. My test website did work without the filter
Interesting. I wonder if your actual app is somehow grabbing the request parameters before the setting gets done. Fortunately the filter solution always works though!
I've just come across an LTI validation issue for a Canvas LTI app (using basiclti-util-java to do the LTI validation within Java) and a particular student whose name/lastname include special characters. The symptom is that the LTI validation fails for this student, while it succeeds when the special characters are removed from the user's name within Canvas. The special characters in question are Spanish characters (an accent +a tilde above an 'n'). While this tells me that character encoding must be an issue here, I cannot tell who is at fault (is it the Canvas LTI consumer sending incorrectly encoded strings, or is the basiclti-util-java library somehow at fault?). Here's a bit more information that might help: 1- I've experimented with an alternative Java LTI library (blti-sandwich) and got the same result - failed validation-. I see that both libraries use the same underlying OAuth libraries, which might explain the uniformity here perhaps. 2- I've added a couple of logging messages within Java to print out the relevant http (lti-related) parameters being passed. When the name/lastname get printed out, they get shown with messed up characters - just what one would expect if reading with one encoding something that was encoded with a different one-. If I then re-encode these strings as UTF-8 strings within Java (reading them as ISO-8859_1 first) they then print out fine to the console. This seems to suggest that perhaps the strings sent over by the Canvas LMS were encoded using ISO 8859_1. 3- An alternative LTI app that uses PHP-based LTI validation (Blti library) written by a colleague validates correctly this particular user's request. This suggests that somehow the PHP-based LTI library is somehow avoiding the (special character) problem altogether.
Any thoughts will be appreciated. Thanks in advance.