users@jersey.java.net

[Jersey] OAuth signature does not seem to comply with OAuth specification

From: <azadbolour_at_bolour.com>
Date: Tue, 15 Nov 2011 16:36:11 +0000 (GMT)

This is a restatement (with updates) of an an ealier message
erroneously posted to the issues list:
http://java.net/projects/jersey/lists/issues/archive/2011-11/message/10
9.

The OAuth specification, http://oauth.net/core/1.0a/#anchor13, states
that in signing a request, the base signature that is to be signed by
the secret key should include name=value pairs for the request
parameters in lexicographic order of the parameter names. And if there
are multiple values for a parameter, the name=value pairs for that
parameter are to appear in the base signature string in the order of
the values. Thus, the major sort order is the parameter name, and the
minor sort order is the parameter value.

But the method OAuthSignature.normalizeParameters that constructs the
OAuth base string in the Jersey OAuth implementation sorts the
parameters not in this major/minor sort order of name/values, but
instead by the value of the string "name=value".

Here is an example where sorting by the "name=value" string does not
produce the correct result.

Suppose there is a parameter named "org" (value "acme") and another
named "org-country" (value "US").

The standard says org should come before org-country in the base
signature string.

But the method OAuthSignature.normalizeParameters sorts the strings
"org=acme" and "org-country=US", and since '-' comes before '=' in byte
ordering, places 'org-country' before org in the signature string,
contrary to the standard.

This is the case in the OAuthSignature class both in
oauth-signature-1.9-ea04-sources.jar
oauth-signature-1.9-SNAPSHOT-sources.jar.

The upshot is that the correct signature of a non-Jersey client
adhering to the standard can be rejected by a Jersey server.

To fix this issue, one can change the sort order to use the following
name/value pair class (snippet shown below) rather than the string
"name=value".

public class OAuthKeyValue implements Comparable<OAuthKeyValue>
{
    private String name;
    private String value;

    // ....

    @Override
    public int compareTo(OAuthKeyValue o)
    {
        int comp = this.name.compareTo(o.name);
        if (comp == 0)
            comp = this.value.compareTo(o.value);
        return comp;
    }

    // ....
}

I am working with such a fix right now, and can share it if desired.

Azad