summaryrefslogtreecommitdiff
path: root/src/io/OAuthRequester.java
blob: 7646e3f0226869cb5ab99814e5dd3f25e674abe1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package io;

import java.io.IOException;
import java.net.URLConnection;
import oauth.signpost.OAuth;
import oauth.signpost.OAuthConsumer;
import oauth.signpost.basic.DefaultOAuthConsumer;
import oauth.signpost.basic.DefaultOAuthProvider;
import oauth.signpost.exception.OAuthException;
import org.json.JSONObject;
import support.ConsumerKeySecret;
import support.OAuthAccessTokenSecret;
import utils.Configuration;

/**
 * An API requester that uses OAuth to sign its requests.
 *
 * @author Peter Wu
 */
public class OAuthRequester extends AbstractRequester {

    /**
     * Instance that signs signs HTTP requests with an OAuth token and secret.
     */
    private final OAuthConsumer consumer;

    /**
     * Instance that can retrieve an access token for the consumer.
     */
    private final DefaultOAuthProvider provider;

    /**
     * Instantiates a requester using OAuth. The caller must initialize the
     * access token before requests can be sent.
     *
     * @param cks The consumer secrets provided by Twitter.
     */
    public OAuthRequester(ConsumerKeySecret cks) {
        // create a new application-specific OAuth consumer
        consumer = new DefaultOAuthConsumer(cks.getKey(), cks.getSecret());
        // Note: Access tokens still require PIN
        provider = new DefaultOAuthProvider(Configuration.REQUEST_TOKEN_URL,
                Configuration.ACCESS_TOKEN_URL, Configuration.AUTHORIZE_URL);
    }

    /**
     * Set the access token to sign apps with. This access token can be
     * retrieved from dev.twitter.com (see
     * https://dev.twitter.com/docs/auth/tokens-devtwittercom) or via a PIN
     * (https://dev.twitter.com/docs/auth/pin-based-authorization).
     *
     * @param secrets Access token and token secret.
     */
    public void setAccessToken(OAuthAccessTokenSecret secrets) {
        String token = secrets.getToken();
        String secret = secrets.getSecret();
        assert token != null;
        assert secret != null;
        consumer.setTokenWithSecret(token, secret);
    }

    /**
     * Retrieves an URL which allows an authenticated user to retrieve a PIN for
     * this application.
     *
     * @return An URL.
     * @throws IOException if an error occurred while retrieving the URL.
     */
    public String getAuthURL() throws IOException {
        String authUrl;
        try {
            authUrl = provider.retrieveRequestToken(consumer, OAuth.OUT_OF_BAND);
        } catch (OAuthException ex) {
            throw new IOException(ex);
        }
        return authUrl;
    }

    /**
     * Gets access tokens from a PIN (out-of-band method). The PIN can be
     * retrieved by visiting the URL from {@code getAuthURL()}. See
     * https://dev.twitter.com/docs/auth/pin-based-authorization
     *
     * @param pin The PIN as found on the page.
     * @throws IOException if the PIN cannot be used to retrieve access tokens.
     */
    public void supplyPINForTokens(String pin) throws IOException {
        try {
            provider.retrieveAccessToken(consumer, pin);
        } catch (OAuthException ex) {
            throw new IOException(ex);
        }
    }

    @Override
    protected void preconnect(URLConnection conn) throws IOException {
        try {
            consumer.sign(conn);
        } catch (OAuthException ex) {
            throw new IOException(ex);
        }
    }

    public OAuthAccessTokenSecret getSecrets() {
        String token = consumer.getToken();
        String secret = consumer.getTokenSecret();
        if (token == null || secret == null) {
            return null;
        }
        return new OAuthAccessTokenSecret(token, secret);
    }

    @Override
    public boolean isValid() throws IOException {
        if (consumer.getToken() == null) {
            return false;
        }
        // NOTE: this actually contributes to the ratelimit (12/minute)
        // TODO: find alternative that does not hit the ratelimit
        JSONObject obj = getJSONRelax("1/application/rate_limit_status");
        return !obj.has("errors");
    }
}