The solution works. The CoreOAuthConsumerSupport subclass method getSignatureBaseString now adds the form parameters to the base string. I just added a loop to add the form parameters listed in the formParameters map.
Code:
public class CoreOAuthConsumerSupportForm extends CoreOAuthConsumerSupport {
MultiValueMap<String, String> formParameters;
/**
* Get the signature base string for the specified parameters. It is
* presumed the parameters are NOT OAuth-encoded.
*
* @param oauthParams
* The parameters (NOT oauth-encoded).
* @param requestURL
* The request URL.
* @param httpMethod
* The http method.
* @return The signature base string.
*/
protected String getSignatureBaseString(Map<String, Set<CharSequence>> oauthParams, URL requestURL, String httpMethod) {
TreeMap<String, TreeSet<String>> sortedParameters = new TreeMap<String, TreeSet<String>>();
for (Map.Entry<String, Set<CharSequence>> param : oauthParams
.entrySet()) {
// first encode all parameter names and values (spec section 9.1)
String key = oauthEncode(param.getKey());
// add the encoded parameters sorted according to the spec.
TreeSet<String> sortedValues = sortedParameters.get(key);
if (sortedValues == null) {
sortedValues = new TreeSet<String>();
sortedParameters.put(key, sortedValues);
}
for (CharSequence value : param.getValue()) {
sortedValues.add(oauthEncode(value.toString()));
}
}
//new code to add form parameters to base string
for (Entry<String, List<String>> entry : formParameters.entrySet()) {
String key = oauthEncode(entry.getKey());
TreeSet<String> sortedValues = sortedParameters.get(key);
if (sortedValues == null) {
sortedValues = new TreeSet<String>();
sortedParameters.put(key, sortedValues);
}
for (CharSequence value : entry.getValue()) {
sortedValues.add(oauthEncode(value.toString()));
}
}
// now concatenate them into a single query string according to the spec.
StringBuilder queryString = new StringBuilder();
Iterator<Map.Entry<String, TreeSet<String>>> sortedIt = sortedParameters
.entrySet().iterator();
while (sortedIt.hasNext()) {
Map.Entry<String, TreeSet<String>> sortedParameter = sortedIt
.next();
for (String parameterValue : sortedParameter.getValue()) {
if (parameterValue == null) {
parameterValue = "";
}
queryString.append(sortedParameter.getKey()).append('=').append(parameterValue);
if (sortedIt.hasNext()) {
queryString.append('&');
}
}
}
StringBuilder url = new StringBuilder(requestURL.getProtocol()
.toLowerCase()).append("://").append(
requestURL.getHost().toLowerCase());
if ((requestURL.getPort() >= 0)
&& (requestURL.getPort() != requestURL.getDefaultPort())) {
url.append(":").append(requestURL.getPort());
}
url.append(requestURL.getPath());
return new StringBuilder(httpMethod.toUpperCase()).append('&')
.append(oauthEncode(url.toString())).append('&')
.append(oauthEncode(queryString.toString())).toString();
}
public MultiValueMap<String, String> getFormParameters() {
return formParameters;
}
public void setFormParameters(MultiValueMap<String, String> formParameters) {
this.formParameters = formParameters;
}
}
This is called by a method in the OAuth client:
Code:
public <T> void seekRestPost(URL url, HttpEntity<T> entity, MultiValueMap<String, String> formParameters) {
log.info("URL: " + url);
//needed to fix missing functionality in Spring OAuth
consumerSupportForm.setFormParameters(formParameters);
Map<String, OAuthConsumerToken> tokens = new Hashtable<String, OAuthConsumerToken>();
OAuthConsumerToken token = new OAuthConsumerToken();
tokens.put(RESOURCE_ID, token);
OAuthSecurityContextImpl securityContext = new OAuthSecurityContextImpl();
securityContext.setAccessTokens(tokens);
OAuthSecurityContextHolder.setContext(securityContext);
OAuthRestTemplate restTemplate = new OAuthRestTemplate(protectedResource);
restTemplate.setSupport(consumerSupportForm);
//If this call is not made then the OAuthSignatureMethodFactoryUrlEncode will not be used in making rest calls.
restTemplate.setRequestFactory(requestFactoryForm);
restTemplate.postForLocation(url.toString(), entity);
}