PageRenderTime 42ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/app/com/atlassian/connect/play/java/oauth/OAuthSignatureCalculator.java

https://bitbucket.org/awei/ac-play-java
Java | 185 lines | 161 code | 21 blank | 3 comment | 4 complexity | 65a6a02495a7cfa7d9554bd8e9408d95 MD5 | raw file
Possible License(s): Apache-2.0
  1. package com.atlassian.connect.play.java.oauth;
  2. import com.atlassian.connect.play.java.AC;
  3. import com.google.common.base.Supplier;
  4. import com.google.common.base.Suppliers;
  5. import com.google.common.collect.Maps;
  6. import com.ning.http.client.FluentStringsMap;
  7. import net.oauth.OAuth;
  8. import net.oauth.OAuthAccessor;
  9. import net.oauth.OAuthConsumer;
  10. import net.oauth.OAuthException;
  11. import net.oauth.OAuthMessage;
  12. import net.oauth.OAuthServiceProvider;
  13. import net.oauth.signature.RSA_SHA1;
  14. import play.libs.WS;
  15. import java.io.IOException;
  16. import java.lang.reflect.Field;
  17. import java.lang.reflect.InvocationTargetException;
  18. import java.lang.reflect.Method;
  19. import java.net.URISyntaxException;
  20. import java.util.HashMap;
  21. import java.util.List;
  22. import java.util.Map;
  23. import static com.atlassian.connect.play.java.util.Utils.LOGGER;
  24. import static java.lang.String.format;
  25. public final class OAuthSignatureCalculator implements WS.SignatureCalculator
  26. {
  27. private static final Supplier<OAuthConsumer> LOCAL_CONSUMER = Suppliers.memoize(new Supplier<OAuthConsumer>()
  28. {
  29. @Override
  30. public OAuthConsumer get()
  31. {
  32. return loadLocalConsumer();
  33. }
  34. });
  35. @Override
  36. public void sign(WS.WSRequest request)
  37. {
  38. final String authorizationHeaderValue = getAuthorizationHeaderValue(request);
  39. LOGGER.debug(format("Generated OAuth authorisation header: '%s'", authorizationHeaderValue));
  40. request.setHeader("Authorization", authorizationHeaderValue);
  41. }
  42. public String getAuthorizationHeaderValue(WS.WSRequest request) throws IllegalArgumentException
  43. {
  44. try
  45. {
  46. final OAuthConsumer localConsumer = LOCAL_CONSUMER.get();
  47. final Map<String, String> params = addOAuthParameters(localConsumer);
  48. addQueryParams(params, getQueryParams(request));
  49. final String method = request.getMethod();
  50. final String url = request.getUrl();
  51. LOGGER.debug("Creating OAuth signature for:");
  52. LOGGER.debug(format("Method: '%s'", method));
  53. LOGGER.debug(format("URL: '%s'", url));
  54. LOGGER.debug(format("Parameters: %s", params));
  55. final OAuthMessage oauthMessage = new OAuthMessage(method, url, params.entrySet());
  56. oauthMessage.sign(new OAuthAccessor(localConsumer));
  57. return oauthMessage.getAuthorizationHeader(null);
  58. }
  59. catch (OAuthException e)
  60. {
  61. // shouldn't really happen...
  62. throw new IllegalArgumentException("Failed to sign the request", e);
  63. }
  64. catch (IOException | URISyntaxException e)
  65. {
  66. // this shouldn't happen as the message is not being read from any IO streams, but the OAuth library throws
  67. // these around like they're candy, but far less sweet and tasty.
  68. throw new RuntimeException(e);
  69. }
  70. }
  71. private FluentStringsMap getQueryParams(WS.WSRequest request)
  72. {
  73. final Object underlyingRequest = getRequestObject(getRequestField(request), request);
  74. return getQueryParams(getGetQueryParamsMethod(underlyingRequest), underlyingRequest);
  75. }
  76. private FluentStringsMap getQueryParams(Method m, Object request)
  77. {
  78. try
  79. {
  80. return (FluentStringsMap) m.invoke(request);
  81. }
  82. catch (IllegalAccessException | InvocationTargetException e)
  83. {
  84. throw new RuntimeException(e);
  85. }
  86. }
  87. private Method getGetQueryParamsMethod(Object o)
  88. {
  89. try
  90. {
  91. final Method m = o.getClass().getMethod("getQueryParams");
  92. m.setAccessible(true);
  93. return m;
  94. }
  95. catch (NoSuchMethodException e)
  96. {
  97. throw new RuntimeException(e);
  98. }
  99. }
  100. private Field getRequestField(WS.WSRequest request)
  101. {
  102. try
  103. {
  104. final Field f = request.getClass().getSuperclass().getDeclaredField("request");
  105. f.setAccessible(true);
  106. return f;
  107. }
  108. catch (NoSuchFieldException e)
  109. {
  110. throw new RuntimeException(e);
  111. }
  112. }
  113. private Object getRequestObject(Field f, WS.WSRequest request)
  114. {
  115. try
  116. {
  117. return f.get(request);
  118. }
  119. catch (IllegalAccessException e)
  120. {
  121. throw new RuntimeException(e);
  122. }
  123. }
  124. private void addQueryParams(Map<String, String> params, FluentStringsMap qp)
  125. {
  126. for (Map.Entry<String, List<String>> qparam : qp)
  127. {
  128. if (qparam.getValue().size() > 1)
  129. {
  130. throw new RuntimeException("Our OAuth library doesn't support multiple value query params!");
  131. }
  132. else if (!qparam.getValue().isEmpty())
  133. {
  134. params.put(qparam.getKey(), qparam.getValue().get(0));
  135. }
  136. }
  137. }
  138. private Map<String, String> addOAuthParameters(final OAuthConsumer local)
  139. {
  140. final HashMap<String, String> params = Maps.newHashMap();
  141. params.put(OAuth.OAUTH_SIGNATURE_METHOD, OAuth.RSA_SHA1);
  142. params.put(OAuth.OAUTH_VERSION, "1.0");
  143. params.put(OAuth.OAUTH_CONSUMER_KEY, local.consumerKey);
  144. params.put(OAuth.OAUTH_NONCE, getNonce());
  145. params.put(OAuth.OAUTH_TIMESTAMP, getTimestamp());
  146. return params;
  147. }
  148. private String getNonce()
  149. {
  150. return System.nanoTime() + "";
  151. }
  152. private static String getTimestamp()
  153. {
  154. return System.currentTimeMillis() / 1000 + "";
  155. }
  156. private static OAuthConsumer loadLocalConsumer()
  157. {
  158. final OAuthServiceProvider serviceProvider = new OAuthServiceProvider(null, null, null);
  159. final OAuthConsumer localConsumer = new OAuthConsumer(null, AC.PLUGIN_KEY, null, serviceProvider);
  160. localConsumer.setProperty(RSA_SHA1.PRIVATE_KEY, AC.privateKey.get());
  161. localConsumer.setProperty(RSA_SHA1.PUBLIC_KEY, AC.publicKey.get());
  162. return localConsumer;
  163. }
  164. }