I wrote 2 new classes: a decorator class that implements the OAuthSignatureMethod interface and a sub class of the CoreOAuthSignatureMethodFactory class. The decorator simply URL ecodes the String retruned by the sign method and the factory sub class wraps the OAuthSignatureMethod object returned by the getSignatureMethod method of the super class.
You need to make an additonal call on the OAuthRestTemplate in the client or it will not use the new CoreOAuthSignatureMethodFactory sub class. This is the call to:
restTemplate.setRequestFactory(requestFactory);
I would have thought that putting both the ProtectedResourceDetails and OAuthConsumerSupport in the OAuthRestTemplate would have been enough but apparently not.
The code:
SignatureMethodUrlEncode Class
Code:
public class SignatureMethodUrlEncode implements OAuthSignatureMethod {
private static Logger log = Logger.getLogger(SignatureMethodUrlEncode.class);
private OAuthSignatureMethod signatureMethod;
/**
* The constructor accepts a parameter that implements the OAuthSignatureMethod.
*
* @param signatureMethod
*/
SignatureMethodUrlEncode(OAuthSignatureMethod signatureMethod) {
this.signatureMethod = signatureMethod;
}
/**
* Simple delegates the method call to the OAuthSignatureMethod object it was constructed with.
*/
public String getName() {
return signatureMethod.getName();
}
/**
* The value returned by the OAuthSignatureMethod it delegates to is URL Encoded.
*
* @param signatureBaseString
*/
public String sign(String signatureBaseString) {
log.info("signatureBaseString: " + signatureBaseString);
String signature = signatureMethod.sign(signatureBaseString);
log.info("signature: " + signature);
try {
String encodedSignature = URLEncoder.encode(signature, "UTF-8");
log.info("encodedSignature: " + encodedSignature);
return encodedSignature;
}
catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return signature;
}
/**
* Simple delegates the method call to the OAuthSignatureMethod object it was constructed with.
*
* @param signatureBaseString
* @param signature
*/
public void verify(String signatureBaseString, String signature) throws InvalidSignatureException {
signatureMethod.verify(signatureBaseString, signature);
}
}
OAuthSignatureMethodFactoryUrlEncode Class
Code:
public class OAuthSignatureMethodFactoryUrlEncode extends CoreOAuthSignatureMethodFactory {
private static Logger log = Logger.getLogger(OAuthSignatureMethodFactoryUrlEncode.class);
/**
* This method decorates the OAuthSignatureMethod returned by a getSignatureMethod call
* to the super class with a SignatureMethodUrlEncode object.
*/
@Override
public OAuthSignatureMethod getSignatureMethod(String methodName, SignatureSecret signatureSecret, String tokenSecret) {
log.debug("methodName: " + methodName);
log.debug("signatureSecret: " + signatureSecret.toString());
log.debug("tokenSecret: " + tokenSecret);
OAuthSignatureMethod signatureMethod = super.getSignatureMethod(methodName, signatureSecret, tokenSecret);
return new SignatureMethodUrlEncode(signatureMethod);
}
}
Client Class
Code:
public class SeekClient {
private static Logger log = Logger.getLogger(SeekClient.class);
private final static String RESOURCE_ID = "resourceId";
private final ProtectedResourceDetails protectedResource = buildProtectedResource();
private OAuthConsumerSupport consumerSupport = buildConsumerSupport();
private ClientHttpRequestFactory requestFactory = buildSeekClientHttpRequestFactory();
private ProtectedResourceDetails buildProtectedResource() {
BaseProtectedResourceDetails protectedResource = new BaseProtectedResourceDetails();
Properties properties = Utility.getProperties();
String consumerKey = properties.getProperty("consumerKey");
String consumerSecret = properties.getProperty("consumerSecret");
SharedConsumerSecret sharedConsumerSecret = new SharedConsumerSecret(consumerSecret);
protectedResource.setConsumerKey(consumerKey);
protectedResource.setSharedSecret(sharedConsumerSecret);
protectedResource.setUse10a(false);
protectedResource.setId(RESOURCE_ID);
protectedResource.setAcceptsAuthorizationHeader(false);
return protectedResource;
}
private OAuthConsumerSupport buildConsumerSupport() {
CoreOAuthConsumerSupport consumerSupport = new CoreOAuthConsumerSupport();
consumerSupport.setStreamHandlerFactory(new DefaultOAuthURLStreamHandlerFactory());
consumerSupport.setSignatureFactory(new OAuthSignatureMethodFactoryUrlEncode()); // new decorator for signature generation
consumerSupport.setProtectedResourceDetailsService(new ProtectedResourceDetailsService() {
@Override
public ProtectedResourceDetails loadProtectedResourceDetailsById(String s) {
return protectedResource;
}
});
// log.info("OAuth params Query: " + consumerSupport.getOAuthQueryString(protectedResource, null, url, "GET", null));
// log.info("OAuth params Header: " + consumerSupport.getAuthorizationHeader(protectedResource, null, url, "GET", null));
return consumerSupport;
}
/*
* This needs to be built so that the OAuthSignatureMethodFactoryUrlEncode is called rather than
* the default.
*/
private ClientHttpRequestFactory buildSeekClientHttpRequestFactory() {
ClientHttpRequestFactory springRequestFactory = new SimpleClientHttpRequestFactory();
// OAuthClientHttpRequestFactory requestFactory = new OAuthClientHttpRequestFactorySeek(springRequestFactory, protectedResource, consumerSupport);
OAuthClientHttpRequestFactory requestFactory = new OAuthClientHttpRequestFactory(springRequestFactory, protectedResource, consumerSupport);
return requestFactory;
}
/**
* Makes a REST call to the specified URL. The servers expects OAuth 1.0a and all OAuth parameters
* on the URL of the Get call.
*
* @param url URL of the REST server.
* @return String from REST call.
*/
public String restQuery(URL url) {
log.info("URL: " + url);
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(consumerSupport);
//If this call is not made then the OAuthSignatureMethodFactoryUrlEncode will not be used in making rest calls.
restTemplate.setRequestFactory(requestFactory);
return restTemplate.getForObject(url.toString(), String.class);
}
}