View difference between Paste ID: ZGY25cq4 and
SHOW: | | - or go back to the newest paste.
1-
1+
2
import groovyx.net.http.HTTPBuilder;
3
4
import java.io.IOException;
5
import java.net.URISyntaxException;
6
import java.util.HashMap;
7
import java.util.Map;
8
9
import org.apache.http.client.ClientProtocolException;
10
import org.scribe.http.Request;
11
import org.scribe.http.Request.Verb;
12
import org.scribe.oauth.Scribe;
13
import org.scribe.oauth.Token;
14
15
/**
16
 * Adds OAuth Consumer support to HttpBuilder using Pablo Fernandez's Scribe
17
 * library (http://github.com/fernandezpablo85/scribe).
18
 * 
19
 * Instantiate your own Scribe and pass it to the <code>create</code> factory
20
 * method. Provide an <code>accessToken</code> parameter in the
21
 * <code>args</code> map of each request or use <code>setAccessToken</code> to
22
 * use the same one repeatedly.
23
 * 
24
 * Example: <code>
25
 * def serviceProps = new Properties([    "consumer.key" : "myApiToken", 
26
 *                                     "consumer.secret" : "myApiSecret" ])
27
 * 
28
 * def scribe = new Scribe(serviceProps)
29
 * 
30
 * //Use Scribe as described on its github to get the request and access 
31
 * //tokens. We'll pretend we just have one.
32
 * 
33
 * def access = new Token("theAccessToken","andItsSecret")
34
 * 
35
 * def http = OAuthHttpBuilder.create(
36
 *               "http://www.twitter.com/oauth/some_resource", 
37
 *               scribe 
38
 *            );
39
 * 
40
 * http.get(      query : [ arg1 : "value1", arg2 : "value2" ], 
41
 *           accessToken: access );
42
 * </code>
43
 * 
44
 * @author Erem Boto
45
 */
46
@SuppressWarnings("unchecked")
47
public class OAuthHttpBuilder {
48
  private final Scribe signer;
49
  private final HTTPBuilder delegate;
50
  private Token defaultAccessToken = null;
51
52
  
53
  /*
54
   * Class provision
55
   */
56
  public static OAuthHttpBuilder create( Object defaultUri,
57
                                         Object defaultContentType, 
58
                                         Scribe signer ) throws URISyntaxException {
59
    return new OAuthHttpBuilder(
60
        new HTTPBuilder(defaultUri, defaultContentType), signer);
61
  }
62
63
  public static OAuthHttpBuilder create( Object defaultUri, 
64
                                         Scribe signer )
65
  throws URISyntaxException {
66
    return new OAuthHttpBuilder(new HTTPBuilder(defaultUri), signer);
67
  }
68
69
  public OAuthHttpBuilder(HTTPBuilder delegate, Scribe signer) {
70
    this.signer = signer;
71
    this.delegate = delegate;
72
  }
73
74
  /*
75
   * Public Methods
76
   */
77
  /**
78
   * Sets the default access token to use when making OAuth requests.
79
   * 
80
   * @param token
81
   */
82
  public void setAccessToken(Token token) {
83
    this.defaultAccessToken = token;
84
  }
85
86
  /*
87
   * Wrapped HttpBuilder Methods
88
   */
89
  public Object get(Map<String, ?> args) 
90
  throws ClientProtocolException, IOException, URISyntaxException {
91
    preProcessArgsHeader(Verb.GET, args);
92
    return delegate.get(args);
93
  }
94
95
  public Object post(Map<String, ?> args) 
96
  throws ClientProtocolException, URISyntaxException, IOException {
97
    preProcessArgsHeader(Verb.POST, args);
98
    return delegate.post(args);
99
  }
100
101
  
102
  /*
103
   * Private Methods
104
   */
105
  /**
106
   * Uses provided "accessToken" and "uri" parameters to construct an
107
   * Authorization header with Scribe.
108
   * 
109
   * @param method
110
   *          the request's HTTP method
111
   * @param args
112
   *          the argument map as passed to get() or post()
113
   */
114
  public void preProcessArgsHeader(Verb method, Map<String, ?> args) {
115
    Token accessToken = accessTokenFromArgs(args);
116
    String uriParam = uriParamFromArgs(args);
117
118
    // God knows what happens if they aren't strings.
119
    Map<String, String> query = (Map<String, String>) args.get("query");
120
121
    Object bodyParams = args.get("body");
122
123
    // because we're using one map, the request won't be to spec if you have
124
    // repeated query parameters =(
125
    Map oauthParams = new HashMap();
126
    if (query != null) {
127
      oauthParams.putAll(query);
128
    }
129
130
    boolean shouldPutBody = (method == Verb.POST && bodyParams instanceof Map);
131
    if (shouldPutBody) {
132
      oauthParams.putAll((Map<String, String>) bodyParams);
133
    }
134
135
    String authHeader = makeAuthHeader( method, 
136
                                        uriParam,
137
                                        accessToken,
138
                                        oauthParams );
139
    addAuthorizationHeader(authHeader, args);
140
  }
141
142
  /**
143
   * Grabs the Scribe access token from the provided arguments, or returns the
144
   * default token.
145
   * 
146
   * @param args
147
   *          the arguments passed to either get or post.
148
   * @return the accessToken that was provided
149
   * @throws IllegalStateException
150
   *           when the accessToken parameter is not provided and no default
151
   *           accessToken was available.
152
   */
153
  private Token accessTokenFromArgs(Map args) throws IllegalStateException {
154
    Token accessToken = (Token) args.get("accessToken");
155
    if (accessToken == null) {
156
      accessToken = defaultAccessToken;
157
    }
158
    if (accessToken == null) {
159
      accessToken = new Token("", "");
160
    }
161
    return accessToken;
162
  }
163
164
  /**
165
   * Grabs the uri from the provided argument map, or returns the default URI.
166
   * 
167
   * @param args
168
   *          the arguments passed to either get or post
169
   * @return the provided uri
170
   * @throws IllegalStateException
171
   *           when the 'uri' parameters is not provided and no default uri was
172
   *           available.
173
   */
174
  private String uriParamFromArgs(Map args) throws IllegalStateException {
175
    String uriParam = (String) args.get("uri");
176
    
177
    if (uriParam == null) {
178
      uriParam = delegate.getUri().toString();
179
    }
180
    if (uriParam == null) {
181
      throw new IllegalStateException(
182
          "Default URI is null and no 'uri' parameter was provided"
183
      );
184
    }
185
    return uriParam;
186
  }
187
188
  /**
189
   * Adds the OAuth Authorization header to the wrapped HTTPBuilder.
190
   * 
191
   * @param authHeader
192
   *          the authorization header value
193
   * @param args
194
   *          the map of arguments passed to post/get
195
   */
196
  private void addAuthorizationHeader(String authHeader, Map args) {
197
    Map headers = (Map) args.get("headers");
198
    if (headers == null) {
199
      headers = new HashMap<String, String>();
200
      args.put("headers", headers);
201
    }
202
    headers.put("Authorization", authHeader);
203
  }
204
205
  /**
206
   * Constructs the authorization header from OAuth parameters.
207
   * 
208
   * @param method
209
   *          the request's HTTP method
210
   * @param uri
211
   *          the request's URI
212
   * @param accessToken
213
   *          the token for signing: can be access token or request token.
214
   * @param queryOrBodyParams
215
   *          the DECODED parameters for oauth to sign. With GET these are the
216
   *          query parameters. With POST both query parameters and body
217
   *          parameters (if this is a form-encoded request).
218
   * @return the signed OAuth "Authorization" header.
219
   */
220
  private String makeAuthHeader( Verb method, 
221
                                 String uri, 
222
                                 Token 
223
                                 accessToken,
224
                                 Map<String, ?> queryOrBodyParams ) {
225
    CustomRequest req = new CustomRequest(method, uri);
226
    for (Map.Entry param : queryOrBodyParams.entrySet()) {
227
      req.addBodyParameter( (String) param.getKey(), 
228
                            param.getValue().toString() );
229
    }
230
    signer.signRequest(req, accessToken);
231
    return req.authorization;
232
  }
233
234
  /**
235
   * Custom Scribe Request subclass gives us access to the Authorization header
236
   * when Scribe sets it.
237
   */
238
  protected static class CustomRequest extends Request {
239
    public CustomRequest(Verb verb, String url) {
240
      super(verb, url);
241
    }
242
243
    public String authorization = null;
244
245
    @Override
246
    public void addHeader(String key, String value) {
247
      if ("Authorization".equals(key)) {
248
        authorization = value;
249
      }
250
      super.addHeader(key, value);
251
    }
252
  }
253
}