summaryrefslogtreecommitdiff
path: root/src/io/BearerRequester.java
blob: 8af38f8bc9f8bcb87c5de2d1594e6032932a99a2 (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
package io;

import com.google.gson.JsonObject;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.Charsets;
import support.ConsumerKeySecret;

/**
 * An API requester used for application-only requests. Not all requests are
 * allowed, see https://dev.twitter.com/docs/auth/application-only-auth for
 * details.
 *
 * @author Peter Wu
 */
public class BearerRequester extends AbstractRequester {

    /**
     * A base64-encoded access token that authenticates requests.
     */
    private final String access_token;

    /**
     * Instantiates a requester with the given access token. The caller should
     * test the token for validity.
     *
     * @param access_token The bearer token that authenticates a request.
     */
    public BearerRequester(String access_token) {
        this.access_token = access_token;
    }

    /**
     * Instantiates an instance, requesting an access token from the provided
     * consumer key and secret.
     *
     * @param secrets The consumer secrets provided by Twitter.
     * @throws IOException if a failure occurred while acquiring a token.
     */
    public BearerRequester(ConsumerKeySecret secrets)
            throws IOException {
        String postData = "grant_type=client_credentials";
        URL url = buildUrl("oauth2/token");
        HttpURLConnection conn = open(url);
        try {
            conn.setRequestMethod("POST");
            // set request headers
            conn.addRequestProperty("Authorization", "Basic "
                    + secrets.getBearerTokenBase64());
            conn.addRequestProperty("Content-Type",
                    "application/x-www-form-urlencoded; charset=UTF-8");
            conn.setFixedLengthStreamingMode(postData.length());
            // connect and send request
            conn.setDoOutput(true);
            conn.getOutputStream().write(postData.getBytes(Charsets.UTF_8));

            JsonObject resp = getResponseAsJson(conn).getAsJsonObject();
            if (!resp.getAsJsonObject().getAsJsonPrimitive("token_type").getAsString().equals("bearer")) {
                throw new IOException("Expected bearer token type");
            }
            access_token = resp.getAsJsonPrimitive("access_token").getAsString();
        }
        catch (ClassCastException ex) {
            throw new IOException("Response was not a JsonObject");
        }
        finally {
            conn.disconnect();
        }
    }

    @Override
    protected void preconnect(URLConnection conn) throws IOException {
        // requests do not have to be signed, instead rely on the Bearer token
        conn.addRequestProperty("Authorization", "Bearer " + access_token);
    }

    /**
     * @return the access token that authenticates requests.
     */
    public String getAccessToken() {
        return access_token;
    }

    @Override
    public boolean isValid() throws IOException {
        try {
            // NOTE: this actually contributes to the ratelimit (12/minute)
            // TODO: find alternative that does not hit the ratelimit
            Response obj = getJSON("application/rate_limit_status");
            return obj.getResp().getAsJsonObject().has("errors");
        } catch (RateLimitException ex) {
            return false;
        }
    }
}