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; 18b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 19b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.io.IOException; 20b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.io.InputStream; 21b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.io.InputStreamReader; 22b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.io.Reader; 23b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.net.URISyntaxException; 24b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.ArrayList; 25b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.Collection; 26b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.Collections; 27b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.HashMap; 28b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.List; 29b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.Map; 30b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.Set; 31b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.regex.Matcher; 32b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.regex.Pattern; 33b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.http.HttpMessage; 34b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.signature.OAuthSignatureMethod; 35b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 36b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien/** 37b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * A request or response message used in the OAuth protocol. 38b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * <p> 39b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * The parameters in this class are not percent-encoded. Methods like 40b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * OAuthClient.invoke and OAuthResponseMessage.completeParameters are 41b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * responsible for percent-encoding parameters before transmission and decoding 42b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * them after reception. 43b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 44b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @author John Kristian 45b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @hide 46b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 47b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienpublic class OAuthMessage { 48b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 49b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public OAuthMessage(String method, String URL, 50b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien Collection<? extends Map.Entry> parameters) { 51b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien this.method = method; 52b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien this.URL = URL; 53b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (parameters == null) { 54b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien this.parameters = new ArrayList<Map.Entry<String, String>>(); 55b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } else { 56b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien this.parameters = new ArrayList<Map.Entry<String, String>>(parameters.size()); 57b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien for (Map.Entry p : parameters) { 58b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien this.parameters.add(new OAuth.Parameter( 59b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien toString(p.getKey()), toString(p.getValue()))); 60b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 61b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 62b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 63b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 64b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public String method; 65b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public String URL; 66b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 67b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private final List<Map.Entry<String, String>> parameters; 68b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private Map<String, String> parameterMap; 69b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private boolean parametersAreComplete = false; 70b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private final List<Map.Entry<String, String>> headers = new ArrayList<Map.Entry<String, String>>(); 71b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 72b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public String toString() { 73b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return "OAuthMessage(" + method + ", " + URL + ", " + parameters + ")"; 74b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 75b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 76b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** A caller is about to get a parameter. */ 77b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private void beforeGetParameter() throws IOException { 78b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (!parametersAreComplete) { 79b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien completeParameters(); 80b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien parametersAreComplete = true; 81b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 82b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 83b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 84b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 85b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Finish adding parameters; for example read an HTTP response body and 86b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * parse parameters from it. 87b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 88b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien protected void completeParameters() throws IOException { 89b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 90b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 91b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public List<Map.Entry<String, String>> getParameters() throws IOException { 92b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien beforeGetParameter(); 93b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return Collections.unmodifiableList(parameters); 94b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 95b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 96b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public void addParameter(String key, String value) { 97b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien addParameter(new OAuth.Parameter(key, value)); 98b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 99b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 100b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public void addParameter(Map.Entry<String, String> parameter) { 101b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien parameters.add(parameter); 102b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien parameterMap = null; 103b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 104b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 105b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public void addParameters( 106b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien Collection<? extends Map.Entry<String, String>> parameters) { 107b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien this.parameters.addAll(parameters); 108b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien parameterMap = null; 109b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 110b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 111b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public String getParameter(String name) throws IOException { 112b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return getParameterMap().get(name); 113b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 114b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 115b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public String getConsumerKey() throws IOException { 116b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return getParameter(OAuth.OAUTH_CONSUMER_KEY); 117b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 118b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 119b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public String getToken() throws IOException { 120b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return getParameter(OAuth.OAUTH_TOKEN); 121b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 122b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 123b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public String getSignatureMethod() throws IOException { 124b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return getParameter(OAuth.OAUTH_SIGNATURE_METHOD); 125b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 126b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 127b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public String getSignature() throws IOException { 128b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return getParameter(OAuth.OAUTH_SIGNATURE); 129b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 130b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 131b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien protected Map<String, String> getParameterMap() throws IOException { 132b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien beforeGetParameter(); 133b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (parameterMap == null) { 134b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien parameterMap = OAuth.newMap(parameters); 135b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 136b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return parameterMap; 137b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 138b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 139b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 140b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * The MIME type of the body of this message. 141b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 142b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @return the MIME type, or null to indicate the type is unknown. 143b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 144b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public String getBodyType() { 145b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return getHeader(HttpMessage.CONTENT_TYPE); 146b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 147b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 148b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 149b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * The character encoding of the body of this message. 150b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 151b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @return the name of an encoding, or "ISO-8859-1" if no charset has been 152b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * specified. 153b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 154b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public String getBodyEncoding() { 155b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return HttpMessage.DEFAULT_CHARSET; 156b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 157b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 158b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 159b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * The value of the last HTTP header with the given name. The name is case 160b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * insensitive. 161b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 162b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @return the value of the last header, or null to indicate that there is 163b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * no such header in this message. 164b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 165b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public final String getHeader(String name) { 166b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String value = null; // no such header 167b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien for (Map.Entry<String, String> header : getHeaders()) { 168b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (name.equalsIgnoreCase(header.getKey())) { 169b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien value = header.getValue(); 170b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 171b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 172b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return value; 173b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 174b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 175b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** All HTTP headers. You can add headers to this list. */ 176b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public final List<Map.Entry<String, String>> getHeaders() { 177b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return headers; 178b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 179b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 180b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 181b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Read the body of the HTTP request or response and convert it to a String. 182b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * This method isn't repeatable, since it consumes and closes getBodyAsStream. 183b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 184b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @return the body, or null to indicate there is no body. 185b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 186b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public final String readBodyAsString() throws IOException 187b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien { 188b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien InputStream body = getBodyAsStream(); 189b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return readAll(body, getBodyEncoding()); 190b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 191b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 192b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 193b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Get a stream from which to read the body of the HTTP request or response. 194b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * This is designed to support efficient streaming of a large message. 195b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * The caller must close the returned stream, to release the underlying 196b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * resources such as the TCP connection for an HTTP response. 197b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 198b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @return a stream from which to read the body, or null to indicate there 199b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * is no body. 200b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 201b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public InputStream getBodyAsStream() throws IOException { 202b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return null; 203b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 204b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 205b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** Construct a verbose description of this message and its origins. */ 206b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public Map<String, Object> getDump() throws IOException { 207b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien Map<String, Object> into = new HashMap<String, Object>(); 208b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien dump(into); 209b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return into; 210b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 211b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 212b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien protected void dump(Map<String, Object> into) throws IOException { 213b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien into.put("URL", URL); 214b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (parametersAreComplete) { 215b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien try { 216b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien into.putAll(getParameterMap()); 217b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } catch (Exception ignored) { 218b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 219b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 220b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 221b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 222b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 223b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Verify that the required parameter names are contained in the actual 224b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * collection. 225b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 226b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws OAuthProblemException 227b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * one or more parameters are absent. 228b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws IOException 229b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 230b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public void requireParameters(String... names) 231b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien throws OAuthProblemException, IOException { 232b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien Set<String> present = getParameterMap().keySet(); 233b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien List<String> absent = new ArrayList<String>(); 234b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien for (String required : names) { 235b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (!present.contains(required)) { 236b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien absent.add(required); 237b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 238b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 239b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (!absent.isEmpty()) { 240b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuthProblemException problem = new OAuthProblemException(OAuth.Problems.PARAMETER_ABSENT); 241b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien problem.setParameter(OAuth.Problems.OAUTH_PARAMETERS_ABSENT, OAuth.percentEncode(absent)); 242b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien throw problem; 243b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 244b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 245b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 246b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 247b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Add some of the parameters needed to request access to a protected 248b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * resource, if they aren't already in the message. 249b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 250b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws IOException 251b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws URISyntaxException 252b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 253b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public void addRequiredParameters(OAuthAccessor accessor) 254b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien throws OAuthException, IOException, URISyntaxException { 255b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien final Map<String, String> pMap = OAuth.newMap(parameters); 256b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (pMap.get(OAuth.OAUTH_TOKEN) == null && accessor.accessToken != null) { 257b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien addParameter(OAuth.OAUTH_TOKEN, accessor.accessToken); 258b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 259b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien final OAuthConsumer consumer = accessor.consumer; 260b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (pMap.get(OAuth.OAUTH_CONSUMER_KEY) == null) { 261b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien addParameter(OAuth.OAUTH_CONSUMER_KEY, consumer.consumerKey); 262b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 263b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String signatureMethod = pMap.get(OAuth.OAUTH_SIGNATURE_METHOD); 264b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (signatureMethod == null) { 265b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien signatureMethod = (String) consumer.getProperty(OAuth.OAUTH_SIGNATURE_METHOD); 266b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (signatureMethod == null) { 267b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien signatureMethod = OAuth.HMAC_SHA1; 268b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 269b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien addParameter(OAuth.OAUTH_SIGNATURE_METHOD, signatureMethod); 270b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 271b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (pMap.get(OAuth.OAUTH_TIMESTAMP) == null) { 272b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien addParameter(OAuth.OAUTH_TIMESTAMP, (System.currentTimeMillis() / 1000) + ""); 273b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 274b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (pMap.get(OAuth.OAUTH_NONCE) == null) { 275b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien addParameter(OAuth.OAUTH_NONCE, System.nanoTime() + ""); 276b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 277b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (pMap.get(OAuth.OAUTH_VERSION) == null) { 278b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien addParameter(OAuth.OAUTH_VERSION, OAuth.VERSION_1_0); 279b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 280b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien this.sign(accessor); 281b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 282b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 283b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 284b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Add a signature to the message. 285b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 286b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws URISyntaxException 287b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 288b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public void sign(OAuthAccessor accessor) throws IOException, 289b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuthException, URISyntaxException { 290b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuthSignatureMethod.newSigner(this, accessor).sign(this); 291b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 292b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 293b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 294b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Check that the message is valid. 295b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 296b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws IOException 297b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws URISyntaxException 298b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 299b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws OAuthProblemException 300b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * the message is invalid 301b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 302b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public void validateMessage(OAuthAccessor accessor, OAuthValidator validator) 303b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien throws OAuthException, IOException, URISyntaxException { 304b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien validator.validateMessage(this, accessor); 305b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 306b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 307b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 308b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Construct a WWW-Authenticate or Authentication header value, containing 309b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * the given realm plus all the parameters whose names begin with "oauth_". 310b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 311b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public String getAuthorizationHeader(String realm) throws IOException { 312b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien StringBuilder into = new StringBuilder(); 313b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (realm != null) { 314b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien into.append(" realm=\"").append(OAuth.percentEncode(realm)).append('"'); 315b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 316b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien beforeGetParameter(); 317b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (parameters != null) { 318b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien for (Map.Entry parameter : parameters) { 319b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String name = toString(parameter.getKey()); 320b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (name.startsWith("oauth_")) { 321b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (into.length() > 0) into.append(","); 322b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien into.append(" "); 323b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien into.append(OAuth.percentEncode(name)).append("=\""); 324b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien into.append(OAuth.percentEncode(toString(parameter.getValue()))).append('"'); 325b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 326b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 327b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 328b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return AUTH_SCHEME + into.toString(); 329b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 330b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 331b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 332b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Read all the data from the given stream, and close it. 333b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 334b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @return null if from is null, or the data from the stream converted to a 335b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * String 336b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 337b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static String readAll(InputStream from, String encoding) throws IOException 338b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien { 339b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (from == null) { 340b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return null; 341b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 342b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien try { 343b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien StringBuilder into = new StringBuilder(); 344b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien Reader r = new InputStreamReader(from, encoding); 345b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien char[] s = new char[512]; 346b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien for (int n; 0 < (n = r.read(s));) { 347b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien into.append(s, 0, n); 348b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 349b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return into.toString(); 350b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } finally { 351b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien from.close(); 352b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 353b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 354b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 355b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 356b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Parse the parameters from an OAuth Authorization or WWW-Authenticate 357b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * header. The realm is included as a parameter. If the given header doesn't 358b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * start with "OAuth ", return an empty list. 359b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 360b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static List<OAuth.Parameter> decodeAuthorization(String authorization) { 361b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien List<OAuth.Parameter> into = new ArrayList<OAuth.Parameter>(); 362b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (authorization != null) { 363b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien Matcher m = AUTHORIZATION.matcher(authorization); 364b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (m.matches()) { 365b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (AUTH_SCHEME.equalsIgnoreCase(m.group(1))) { 366b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien for (String nvp : m.group(2).split("\\s*,\\s*")) { 367b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien m = NVP.matcher(nvp); 368b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (m.matches()) { 369b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String name = OAuth.decodePercent(m.group(1)); 370b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String value = OAuth.decodePercent(m.group(2)); 371b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien into.add(new OAuth.Parameter(name, value)); 372b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 373b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 374b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 375b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 376b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 377b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return into; 378b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 379b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 380b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static final String AUTH_SCHEME = "OAuth"; 381b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 382b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static final String GET = "GET"; 383b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static final String POST = "POST"; 384b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static final String PUT = "PUT"; 385b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static final String DELETE = "DELETE"; 386b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 387b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private static final Pattern AUTHORIZATION = Pattern.compile("\\s*(\\w*)\\s+(.*)"); 388b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private static final Pattern NVP = Pattern.compile("(\\S*)\\s*\\=\\s*\"([^\"]*)\""); 389b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 390b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private static final String toString(Object from) { 391b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return (from == null) ? null : from.toString(); 392b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 393b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 394b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien} 395