1b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien/* 2b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Copyright 2007, 2008 Netflix, Inc. 3b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 4b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Licensed under the Apache License, Version 2.0 (the "License"); 5b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * you may not use this file except in compliance with the License. 6b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * You may obtain a copy of the License at 7b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 8b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * http://www.apache.org/licenses/LICENSE-2.0 9b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 10b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Unless required by applicable law or agreed to in writing, software 11b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * distributed under the License is distributed on an "AS IS" BASIS, 12b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * See the License for the specific language governing permissions and 14b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * limitations under the License. 15b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 16b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 17b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienpackage net.oauth.client; 18b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 19b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.io.ByteArrayInputStream; 20b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.io.IOException; 21b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.io.InputStream; 22b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.net.URISyntaxException; 23b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.net.URL; 24b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.ArrayList; 25b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.Collection; 26b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.Iterator; 27b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.List; 28b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.Map; 29b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.OAuth; 30b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.OAuthAccessor; 31b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.OAuthConsumer; 32b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.OAuthException; 33b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.OAuthMessage; 34b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.OAuthProblemException; 35b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.http.HttpClient; 36b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.http.HttpMessage; 37b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.http.HttpMessageDecoder; 38b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.http.HttpResponseMessage; 39b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 40b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien/** 41b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Methods for an OAuth consumer to request tokens from a service provider. 42b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * <p> 43b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * This class can also be used to request access to protected resources, in some 44b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * cases. But not in all cases. For example, this class can't handle arbitrary 45b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * HTTP headers. 46b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * <p> 47b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Methods of this class return a response as an OAuthMessage, from which you 48b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * can get a body or parameters but not both. Calling a getParameter method will 49b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * read and close the body (like readBodyAsString), so you can't read it later. 50b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * If you read or close the body first, then getParameter can't read it. The 51b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * response headers should tell you whether the response contains encoded 52b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * parameters, that is whether you should call getParameter or not. 53b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * <p> 54b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Methods of this class don't follow redirects. When they receive a redirect 55b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * response, they throw an OAuthProblemException, with properties 56b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * HttpResponseMessage.STATUS_CODE = the redirect code 57b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * HttpResponseMessage.LOCATION = the redirect URL. Such a redirect can't be 58b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * handled at the HTTP level, if the second request must carry another OAuth 59b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * signature (with different parameters). For example, Google's Service Provider 60b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * routinely redirects requests for access to protected resources, and requires 61b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * the redirected request to be signed. 62b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 63b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @author John Kristian 64b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @hide 65b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 66b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienpublic class OAuthClient { 67b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 68b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public OAuthClient(HttpClient http) 69b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien { 70b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien this.http = http; 71b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 72b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 73b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private HttpClient http; 74b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 75b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public void setHttpClient(HttpClient http) { 76b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien this.http = http; 77b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 78b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 79b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public HttpClient getHttpClient() { 80b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return http; 81b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 82b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 83b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 84b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Get a fresh request token from the service provider. 85b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 86b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @param accessor 87b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * should contain a consumer that contains a non-null consumerKey 88b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * and consumerSecret. Also, 89b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * accessor.consumer.serviceProvider.requestTokenURL should be 90b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * the URL (determined by the service provider) for getting a 91b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * request token. 92b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws OAuthProblemException 93b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * the HTTP response status code was not 200 (OK) 94b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 95b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public void getRequestToken(OAuthAccessor accessor) throws IOException, 96b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuthException, URISyntaxException { 97b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien getRequestToken(accessor, null); 98b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 99b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 100b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 101b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Get a fresh request token from the service provider. 102b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 103b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @param accessor 104b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * should contain a consumer that contains a non-null consumerKey 105b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * and consumerSecret. Also, 106b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * accessor.consumer.serviceProvider.requestTokenURL should be 107b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * the URL (determined by the service provider) for getting a 108b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * request token. 109b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @param httpMethod 110b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * typically OAuthMessage.POST or OAuthMessage.GET, or null to 111b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * use the default method. 112b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws OAuthProblemException 113b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * the HTTP response status code was not 200 (OK) 114b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 115b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public void getRequestToken(OAuthAccessor accessor, String httpMethod) 116b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien throws IOException, OAuthException, URISyntaxException { 117b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien getRequestToken(accessor, httpMethod, null); 118b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 119b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 120b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** Get a fresh request token from the service provider. 121b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 122b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @param accessor 123b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * should contain a consumer that contains a non-null consumerKey 124b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * and consumerSecret. Also, 125b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * accessor.consumer.serviceProvider.requestTokenURL should be 126b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * the URL (determined by the service provider) for getting a 127b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * request token. 128b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @param httpMethod 129b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * typically OAuthMessage.POST or OAuthMessage.GET, or null to 130b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * use the default method. 131b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @param parameters 132b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * additional parameters for this request, or null to indicate 133b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * that there are no additional parameters. 134b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws OAuthProblemException 135b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * the HTTP response status code was not 200 (OK) 136b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 137b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public void getRequestToken(OAuthAccessor accessor, String httpMethod, 138b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien Collection<? extends Map.Entry> parameters) throws IOException, 139b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuthException, URISyntaxException { 140b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien accessor.accessToken = null; 141b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien accessor.tokenSecret = null; 142b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien { 143b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien // This code supports the 'Variable Accessor Secret' extension 144b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien // described in http://oauth.pbwiki.com/AccessorSecret 145b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien Object accessorSecret = accessor 146b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien .getProperty(OAuthConsumer.ACCESSOR_SECRET); 147b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (accessorSecret != null) { 148b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien List<Map.Entry> p = (parameters == null) ? new ArrayList<Map.Entry>( 149b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 1) 150b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien : new ArrayList<Map.Entry>(parameters); 151b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien p.add(new OAuth.Parameter("oauth_accessor_secret", 152b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien accessorSecret.toString())); 153b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien parameters = p; 154b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien // But don't modify the caller's parameters. 155b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 156b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 157b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuthMessage response = invoke(accessor, httpMethod, 158b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien accessor.consumer.serviceProvider.requestTokenURL, parameters); 159b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien accessor.requestToken = response.getParameter(OAuth.OAUTH_TOKEN); 160b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien accessor.tokenSecret = response.getParameter(OAuth.OAUTH_TOKEN_SECRET); 161b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien response.requireParameters(OAuth.OAUTH_TOKEN, OAuth.OAUTH_TOKEN_SECRET); 162b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 163b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 164b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 165b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Get an access token from the service provider, in exchange for an 166b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * authorized request token. 167b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 168b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @param accessor 169b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * should contain a non-null requestToken and tokenSecret, and a 170b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * consumer that contains a consumerKey and consumerSecret. Also, 171b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * accessor.consumer.serviceProvider.accessTokenURL should be the 172b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * URL (determined by the service provider) for getting an access 173b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * token. 174b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @param httpMethod 175b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * typically OAuthMessage.POST or OAuthMessage.GET, or null to 176b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * use the default method. 177b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @param parameters 178b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * additional parameters for this request, or null to indicate 179b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * that there are no additional parameters. 180b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws OAuthProblemException 181b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * the HTTP response status code was not 200 (OK) 182b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 183b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public OAuthMessage getAccessToken(OAuthAccessor accessor, String httpMethod, 184b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien Collection<? extends Map.Entry> parameters) throws IOException, OAuthException, URISyntaxException { 185b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (accessor.requestToken != null) { 186b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (parameters == null) { 187b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien parameters = OAuth.newList(OAuth.OAUTH_TOKEN, accessor.requestToken); 188b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } else if (!OAuth.newMap(parameters).containsKey(OAuth.OAUTH_TOKEN)) { 189b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien List<Map.Entry> p = new ArrayList<Map.Entry>(parameters); 190b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien p.add(new OAuth.Parameter(OAuth.OAUTH_TOKEN, accessor.requestToken)); 191b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien parameters = p; 192b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 193b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 194b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuthMessage response = invoke(accessor, httpMethod, 195b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien accessor.consumer.serviceProvider.accessTokenURL, parameters); 196b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien response.requireParameters(OAuth.OAUTH_TOKEN, OAuth.OAUTH_TOKEN_SECRET); 197b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien accessor.accessToken = response.getParameter(OAuth.OAUTH_TOKEN); 198b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien accessor.tokenSecret = response.getParameter(OAuth.OAUTH_TOKEN_SECRET); 199b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return response; 200b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 201b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 202b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 203b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Construct a request message, send it to the service provider and get the 204b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * response. 205b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 206b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @param httpMethod 207b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * the HTTP request method, or null to use the default method 208b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @return the response 209b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws URISyntaxException 210b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * the given url isn't valid syntactically 211b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws OAuthProblemException 212b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * the HTTP response status code was not 200 (OK) 213b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 214b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public OAuthMessage invoke(OAuthAccessor accessor, String httpMethod, 215b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String url, Collection<? extends Map.Entry> parameters) 216b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien throws IOException, OAuthException, URISyntaxException { 217b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String ps = (String) accessor.consumer.getProperty(PARAMETER_STYLE); 218b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien ParameterStyle style = (ps == null) ? ParameterStyle.BODY : Enum 219b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien .valueOf(ParameterStyle.class, ps); 220b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuthMessage request = accessor.newRequestMessage(httpMethod, url, 221b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien parameters); 222b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return invoke(request, style); 223b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 224b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 225b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 226b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * The name of the OAuthConsumer property whose value is the ParameterStyle 227b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * to be used by invoke. 228b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 229b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static final String PARAMETER_STYLE = "parameterStyle"; 230b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 231b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 232b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * The name of the OAuthConsumer property whose value is the Accept-Encoding 233b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * header in HTTP requests. 234b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @deprecated use {@link OAuthConsumer#ACCEPT_ENCODING} instead 235b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 236b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien @Deprecated 237b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static final String ACCEPT_ENCODING = OAuthConsumer.ACCEPT_ENCODING; 238b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 239b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 240b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Construct a request message, send it to the service provider and get the 241b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * response. 242b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 243b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @return the response 244b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws URISyntaxException 245b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * the given url isn't valid syntactically 246b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws OAuthProblemException 247b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * the HTTP response status code was not 200 (OK) 248b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 249b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public OAuthMessage invoke(OAuthAccessor accessor, String url, 250b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien Collection<? extends Map.Entry> parameters) throws IOException, 251b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuthException, URISyntaxException { 252b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return invoke(accessor, null, url, parameters); 253b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 254b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 255b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 256b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Send a request message to the service provider and get the response. 257b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 258b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @return the response 259b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws IOException 260b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * failed to communicate with the service provider 261b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws OAuthProblemException 262b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * the HTTP response status code was not 200 (OK) 263b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 264b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public OAuthMessage invoke(OAuthMessage request, ParameterStyle style) 265b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien throws IOException, OAuthException { 266b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien final boolean isPost = POST.equalsIgnoreCase(request.method); 267b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien InputStream body = request.getBodyAsStream(); 268b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (style == ParameterStyle.BODY && !(isPost && body == null)) { 269b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien style = ParameterStyle.QUERY_STRING; 270b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 271b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String url = request.URL; 272b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien final List<Map.Entry<String, String>> headers = 273b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien new ArrayList<Map.Entry<String, String>>(request.getHeaders()); 274b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien switch (style) { 275b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien case QUERY_STRING: 276b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien url = OAuth.addParameters(url, request.getParameters()); 277b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien break; 278b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien case BODY: { 279b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien byte[] form = OAuth.formEncode(request.getParameters()).getBytes( 280b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien request.getBodyEncoding()); 281b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien headers.add(new OAuth.Parameter(HttpMessage.CONTENT_TYPE, 282b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuth.FORM_ENCODED)); 283b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien headers.add(new OAuth.Parameter(CONTENT_LENGTH, form.length + "")); 284b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien body = new ByteArrayInputStream(form); 285b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien break; 286b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 287b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien case AUTHORIZATION_HEADER: 288b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien headers.add(new OAuth.Parameter("Authorization", request.getAuthorizationHeader(null))); 289b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien // Find the non-OAuth parameters: 290b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien List<Map.Entry<String, String>> others = request.getParameters(); 291b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (others != null && !others.isEmpty()) { 292b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien others = new ArrayList<Map.Entry<String, String>>(others); 293b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien for (Iterator<Map.Entry<String, String>> p = others.iterator(); p 294b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien .hasNext();) { 295b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (p.next().getKey().startsWith("oauth_")) { 296b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien p.remove(); 297b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 298b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 299b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien // Place the non-OAuth parameters elsewhere in the request: 300b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (isPost && body == null) { 301b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien byte[] form = OAuth.formEncode(others).getBytes( 302b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien request.getBodyEncoding()); 303b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien headers.add(new OAuth.Parameter(HttpMessage.CONTENT_TYPE, 304b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuth.FORM_ENCODED)); 305b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien headers.add(new OAuth.Parameter(CONTENT_LENGTH, form.length 306b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien + "")); 307b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien body = new ByteArrayInputStream(form); 308b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } else { 309b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien url = OAuth.addParameters(url, others); 310b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 311b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 312b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien break; 313b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 314b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien final HttpMessage httpRequest = new HttpMessage(request.method, new URL(url), body); 315b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien httpRequest.headers.addAll(headers); 316b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien HttpResponseMessage httpResponse = http.execute(httpRequest); 317b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien httpResponse = HttpMessageDecoder.decode(httpResponse); 318b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuthMessage response = new OAuthResponseMessage(httpResponse); 319b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (httpResponse.getStatusCode() != HttpResponseMessage.STATUS_OK) { 320b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuthProblemException problem = new OAuthProblemException(); 321b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien try { 322b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien response.getParameters(); // decode the response body 323b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } catch (IOException ignored) { 324b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 325b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien problem.getParameters().putAll(response.getDump()); 326b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien try { 327b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien InputStream b = response.getBodyAsStream(); 328b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (b != null) { 329b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien b.close(); // release resources 330b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 331b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } catch (IOException ignored) { 332b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 333b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien throw problem; 334b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 335b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return response; 336b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 337b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 338b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** Where to place parameters in an HTTP message. */ 339b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public enum ParameterStyle { 340b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien AUTHORIZATION_HEADER, BODY, QUERY_STRING; 341b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien }; 342b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 343b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien protected static final String PUT = OAuthMessage.PUT; 344b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien protected static final String POST = OAuthMessage.POST; 345b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien protected static final String DELETE = OAuthMessage.DELETE; 346b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien protected static final String CONTENT_LENGTH = HttpMessage.CONTENT_LENGTH; 347b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 348b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien} 349