summaryrefslogtreecommitdiff
path: root/src/com/p4square/restlet/oauth/OAuthHelper.java
blob: 67dd238eb4baa161464a56af96ead92f95c6094d (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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/*
 * Copyright 2013 Jesse Morgan
 */

package com.p4square.restlet.oauth;

import java.net.URLEncoder;

import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.Restlet;
import org.restlet.data.ChallengeResponse;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.Form;
import org.restlet.data.Method;
import org.restlet.data.Reference;
import org.restlet.data.Status;
import org.restlet.engine.Engine;
import org.restlet.representation.Representation;

/**
 * Helper Class for OAuth 1.0 Authentication.
 *
 * @author Jesse Morgan <jesse@jesterpm.net>
 */
public abstract class OAuthHelper {
    private final Restlet mDispatcher;
    private final Token mConsumerToken;

    /**
     * Create a new OAuth Helper.
     * As currently implemented, there can only be one OAuthHelper per Restlet
     * Engine since this class registers its own provider for the OAuth
     * authentication protocol.
     *
     * FIXME: This could be improved by making OAuthAuthenticationHelper and
     * maybe Token aware of multiple service providers.
     *
     * @param context The restlet context which provides a ClientDispatcher.
     * @param consumerKey The OAuth consumer key for this application.
     * @param consumerSecret the OAuth consumer secret for this application.
     */
    public OAuthHelper(Context context, String consumerKey, String consumerSecret) {
        mDispatcher = context.getClientDispatcher();
        mConsumerToken = new Token(consumerKey, consumerSecret);

        Engine.getInstance().getRegisteredAuthenticators().add(new OAuthAuthenticatorHelper(mConsumerToken));
    }

    /**
     * @return the URL for the initial RequestToken request.
     */
    protected abstract String getRequestTokenUrl();

    /**
     * Request a RequestToken.
     *
     * @return a Token containing the RequestToken.
     * @throws OAuthException if the request fails.
     */
    public Token getRequestToken() throws OAuthException {
        Request request = new Request(Method.GET, getRequestTokenUrl());
        request.setChallengeResponse(new ChallengeResponse(ChallengeScheme.HTTP_OAUTH));

        Response response = mDispatcher.handle(request);

        return processTokenRequest(response);
    }

    /**
     * @return the URL to redirect the user to for Authentication.
     */
    public abstract String getLoginUrl(Token requestToken, String callback);

    /**
     * @return the URL for the AccessToken request.
     */
    protected abstract String getAccessTokenUrl();

    /**
     * Request an AccessToken for a previously authenticated RequestToken.
     *
     * @return an OAuthUser object containing the AccessToken.
     * @throws OAuthException if the request fails.
     */
    public OAuthUser getAccessToken(Token requestToken) throws OAuthException {
        Request request = new Request(Method.GET, getAccessTokenUrl());
        request.setChallengeResponse(requestToken.getChallengeResponse());

        return processAccessTokenRequest(request);
    }

    /**
     * Helper method to decode the token returned from an OAuth Request.
     *
     * @param response The Response object from the Request.
     * @return the Token from the oauth_token and oauth_token_secret parameters.
     * @throws OAuthException is the server reported an error.
     */
    protected Token processTokenRequest(Response response) throws OAuthException {
        Status status = response.getStatus();
        Representation entity = response.getEntity();

        try {
            if (status.isSuccess()) {
                Form form = new Form(entity);
                String token = form.getFirstValue("oauth_token");
                String secret = form.getFirstValue("oauth_token_secret");

                return new Token(token, secret);

            } else {
                throw new OAuthException(status);
            }
        } finally {
            entity.release();
        }
    }

    /**
     * Helper method to create an OAuthUser from the AccessToken request.
     *
     * The User's identifier is set to the Content-Location header, if present.
     *
     * @param response The Response to the AccessToken Request.
     * @return An OAuthUser object wrapping the AccessToken.
     * @throws OAuthException if the request failed.
     */
    public OAuthUser processAccessTokenRequest(Request request) throws OAuthException {
        Response response = getResponse(request);
        Token accessToken = processTokenRequest(response);

        Reference ref = response.getEntity().getLocationRef();
        if (ref != null) {
            return new OAuthUser(ref.toString(), accessToken);

        } else {
            return new OAuthUser(accessToken);
        }
    }

    /**
     * Helper method to get a Response for a Request.
     */
    public Response getResponse(Request request) {
        return mDispatcher.handle(request);
    }
}