This is a repost from the IMS Developer’s forum – I forgot to put this in my own blog.
Possible issues with the OAuth C# library. I was working with some folks on C# Basic LTI and came across a seeming interoperability. Here is the discussion:
I looked at the Java Implementations and the PHP implementation and both seem to go to some length *to* double URL-encode the signature string. The PHP code interoperates with the Java code as distributed.
This results in the base signature string having %2520 where there are spaces. Which looks like a mistaken double-encode – but I think that it is an intentional double encode.
If you look at this page (broken into multiple lines to enhance readiblilty)
http://hueniverse.com/2008/10/beginners-guide-to-oauth-part-iv-signing-requests/
After you pick “Non-URL Safe Parameter” expand the little + signs and follow it through – it ends up with a base string that includes a %2520:
GET&http%3A%2F%2Fphotos.example.net%3A8001%2FPhotos&oauth_consumer_key
%3Ddpf43f3%252B%252Bp%252B%25232l4k3l03%26oauth_nonce
%3Dkllo~9940~pd9333jh%26oauth_signature_method%3DHMAC-SHA1
%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d
%25280%25290sl2jdk%26oauth_version%3D1.0%26photo%2520size%3D300%2525
%26title%3DBack%2520of%2520%2524100%2520Dollars%2520Bill
As I look at the sample Java code below – it is effectively double encoding very much on purpose.
So far, this suggests that it is *correct* when spaces turn into %2520 in the pre-signature string instead of %20. So I am thinking that the the sample VB.NET code from oauth.net *might* be wrong.
Sample Java code
public static String getBaseString(OAuthMessage message)
throws IOException, URISyntaxException {
List<Map.Entry<String, String>> parameters;
String url = message.URL;
int q = url.indexOf('?');
if (q < 0) {
parameters = message.getParameters();
} else {
// Combine the URL query string with the other parameters:
parameters = new ArrayList<Map.Entry<String, String>>();
parameters.addAll(OAuth.decodeForm(message.URL.substring(q + 1)));
parameters.addAll(message.getParameters());
url = url.substring(0, q);
}
return OAuth.percentEncode(message.method.toUpperCase()) + '&'
+ OAuth.percentEncode(normalizeUrl(url)) + '&'
+ OAuth.percentEncode(normalizeParameters(parameters));
}
protected static String normalizeParameters(Collection<? extends Map.Entry> parameters)
throws IOException {
if (parameters == null) {
return "";
}
List<ComparableParameter> p = new ArrayList<ComparableParameter>(parameters.size());
for (Map.Entry parameter : parameters) {
if (!"oauth_signature".equals(parameter.getKey())) {
p.add(new ComparableParameter(parameter));
}
}
Collections.sort(p);
return OAuth.formEncode(getParameters(p));
}
public static void formEncode(Iterable<? extends Map.Entry> parameters,OutputStream into)
throws IOException {
if (parameters != null) {
boolean first = true;
for (Map.Entry parameter : parameters) {
if (first) {
first = false;
} else {
into.write('&');
}
into.write(percentEncode(toString(parameter.getKey())).getBytes());
into.write('=');
into.write(percentEncode(toString(parameter.getValue())).getBytes());
}
}
}

