source: josm/trunk/src/oauth/signpost/OAuth.java@ 4656

Last change on this file since 4656 was 4231, checked in by stoecker, 13 years ago

add signpost and metadata extractor code to repository directly

File size: 10.5 KB
Line 
1/* Copyright (c) 2008, 2009 Netflix, Matthias Kaeppler
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15package oauth.signpost;
16
17import java.io.BufferedReader;
18import java.io.ByteArrayOutputStream;
19import java.io.IOException;
20import java.io.InputStream;
21import java.io.InputStreamReader;
22import java.io.OutputStream;
23import java.net.URLDecoder;
24import java.util.Collection;
25import java.util.HashMap;
26import java.util.Map;
27
28import oauth.signpost.http.HttpParameters;
29
30import com.google.gdata.util.common.base.PercentEscaper;
31
32public class OAuth {
33
34 public static final String VERSION_1_0 = "1.0";
35
36 public static final String ENCODING = "UTF-8";
37
38 public static final String FORM_ENCODED = "application/x-www-form-urlencoded";
39
40 public static final String HTTP_AUTHORIZATION_HEADER = "Authorization";
41
42 public static final String OAUTH_CONSUMER_KEY = "oauth_consumer_key";
43
44 public static final String OAUTH_TOKEN = "oauth_token";
45
46 public static final String OAUTH_TOKEN_SECRET = "oauth_token_secret";
47
48 public static final String OAUTH_SIGNATURE_METHOD = "oauth_signature_method";
49
50 public static final String OAUTH_SIGNATURE = "oauth_signature";
51
52 public static final String OAUTH_TIMESTAMP = "oauth_timestamp";
53
54 public static final String OAUTH_NONCE = "oauth_nonce";
55
56 public static final String OAUTH_VERSION = "oauth_version";
57
58 public static final String OAUTH_CALLBACK = "oauth_callback";
59
60 public static final String OAUTH_CALLBACK_CONFIRMED = "oauth_callback_confirmed";
61
62 public static final String OAUTH_VERIFIER = "oauth_verifier";
63
64 /**
65 * Pass this value as the callback "url" upon retrieving a request token if
66 * your application cannot receive callbacks (e.g. because it's a desktop
67 * app). This will tell the service provider that verification happens
68 * out-of-band, which basically means that it will generate a PIN code (the
69 * OAuth verifier) and display that to your user. You must obtain this code
70 * from your user and pass it to
71 * {@link OAuthProvider#retrieveAccessToken(OAuthConsumer, String)} in order
72 * to complete the token handshake.
73 */
74 public static final String OUT_OF_BAND = "oob";
75
76 private static final PercentEscaper percentEncoder = new PercentEscaper(
77 "-._~", false);
78
79 public static String percentEncode(String s) {
80 if (s == null) {
81 return "";
82 }
83 return percentEncoder.escape(s);
84 }
85
86 public static String percentDecode(String s) {
87 try {
88 if (s == null) {
89 return "";
90 }
91 return URLDecoder.decode(s, ENCODING);
92 // This implements http://oauth.pbwiki.com/FlexibleDecoding
93 } catch (java.io.UnsupportedEncodingException wow) {
94 throw new RuntimeException(wow.getMessage(), wow);
95 }
96 }
97
98 /**
99 * Construct a x-www-form-urlencoded document containing the given sequence
100 * of name/value pairs. Use OAuth percent encoding (not exactly the encoding
101 * mandated by x-www-form-urlencoded).
102 */
103 public static <T extends Map.Entry<String, String>> void formEncode(Collection<T> parameters,
104 OutputStream into) throws IOException {
105 if (parameters != null) {
106 boolean first = true;
107 for (Map.Entry<String, String> entry : parameters) {
108 if (first) {
109 first = false;
110 } else {
111 into.write('&');
112 }
113 into.write(percentEncode(safeToString(entry.getKey())).getBytes());
114 into.write('=');
115 into.write(percentEncode(safeToString(entry.getValue())).getBytes());
116 }
117 }
118 }
119
120 /**
121 * Construct a x-www-form-urlencoded document containing the given sequence
122 * of name/value pairs. Use OAuth percent encoding (not exactly the encoding
123 * mandated by x-www-form-urlencoded).
124 */
125 public static <T extends Map.Entry<String, String>> String formEncode(Collection<T> parameters)
126 throws IOException {
127 ByteArrayOutputStream b = new ByteArrayOutputStream();
128 formEncode(parameters, b);
129 return new String(b.toByteArray());
130 }
131
132 /** Parse a form-urlencoded document. */
133 public static HttpParameters decodeForm(String form) {
134 HttpParameters params = new HttpParameters();
135 if (isEmpty(form)) {
136 return params;
137 }
138 for (String nvp : form.split("\\&")) {
139 int equals = nvp.indexOf('=');
140 String name;
141 String value;
142 if (equals < 0) {
143 name = percentDecode(nvp);
144 value = null;
145 } else {
146 name = percentDecode(nvp.substring(0, equals));
147 value = percentDecode(nvp.substring(equals + 1));
148 }
149
150 params.put(name, value);
151 }
152 return params;
153 }
154
155 public static HttpParameters decodeForm(InputStream content)
156 throws IOException {
157 BufferedReader reader = new BufferedReader(new InputStreamReader(
158 content));
159 StringBuilder sb = new StringBuilder();
160 String line = reader.readLine();
161 while (line != null) {
162 sb.append(line);
163 line = reader.readLine();
164 }
165
166 return decodeForm(sb.toString());
167 }
168
169 /**
170 * Construct a Map containing a copy of the given parameters. If several
171 * parameters have the same name, the Map will contain the first value,
172 * only.
173 */
174 public static <T extends Map.Entry<String, String>> Map<String, String> toMap(Collection<T> from) {
175 HashMap<String, String> map = new HashMap<String, String>();
176 if (from != null) {
177 for (Map.Entry<String, String> entry : from) {
178 String key = entry.getKey();
179 if (!map.containsKey(key)) {
180 map.put(key, entry.getValue());
181 }
182 }
183 }
184 return map;
185 }
186
187 public static final String safeToString(Object from) {
188 return (from == null) ? null : from.toString();
189 }
190
191 public static boolean isEmpty(String str) {
192 return (str == null) || (str.length() == 0);
193 }
194
195 /**
196 * Appends a list of key/value pairs to the given URL, e.g.:
197 *
198 * <pre>
199 * String url = OAuth.addQueryParameters(&quot;http://example.com?a=1&quot;, b, 2, c, 3);
200 * </pre>
201 *
202 * which yields:
203 *
204 * <pre>
205 * http://example.com?a=1&b=2&c=3
206 * </pre>
207 *
208 * All parameters will be encoded according to OAuth's percent encoding
209 * rules.
210 *
211 * @param url
212 * the URL
213 * @param kvPairs
214 * the list of key/value pairs
215 * @return
216 */
217 public static String addQueryParameters(String url, String... kvPairs) {
218 String queryDelim = url.contains("?") ? "&" : "?";
219 StringBuilder sb = new StringBuilder(url + queryDelim);
220 for (int i = 0; i < kvPairs.length; i += 2) {
221 if (i > 0) {
222 sb.append("&");
223 }
224 sb.append(OAuth.percentEncode(kvPairs[i]) + "="
225 + OAuth.percentEncode(kvPairs[i + 1]));
226 }
227 return sb.toString();
228 }
229
230 public static String addQueryParameters(String url, Map<String, String> params) {
231 String[] kvPairs = new String[params.size() * 2];
232 int idx = 0;
233 for (String key : params.keySet()) {
234 kvPairs[idx] = key;
235 kvPairs[idx + 1] = params.get(key);
236 idx += 2;
237 }
238 return addQueryParameters(url, kvPairs);
239 }
240
241 /**
242 * Builds an OAuth header from the given list of header fields. All
243 * parameters starting in 'oauth_*' will be percent encoded.
244 *
245 * <pre>
246 * String authHeader = OAuth.prepareOAuthHeader(&quot;realm&quot;, &quot;http://example.com&quot;, &quot;oauth_token&quot;, &quot;x%y&quot;);
247 * </pre>
248 *
249 * which yields:
250 *
251 * <pre>
252 * OAuth realm="http://example.com", oauth_token="x%25y"
253 * </pre>
254 *
255 * @param kvPairs
256 * the list of key/value pairs
257 * @return a string eligible to be used as an OAuth HTTP Authorization
258 * header.
259 */
260 public static String prepareOAuthHeader(String... kvPairs) {
261 StringBuilder sb = new StringBuilder("OAuth ");
262 for (int i = 0; i < kvPairs.length; i += 2) {
263 if (i > 0) {
264 sb.append(", ");
265 }
266 String value = kvPairs[i].startsWith("oauth_") ? OAuth
267 .percentEncode(kvPairs[i + 1]) : kvPairs[i + 1];
268 sb.append(OAuth.percentEncode(kvPairs[i]) + "=\"" + value + "\"");
269 }
270 return sb.toString();
271 }
272
273 public static HttpParameters oauthHeaderToParamsMap(String oauthHeader) {
274 HttpParameters params = new HttpParameters();
275 if (oauthHeader == null || !oauthHeader.startsWith("OAuth ")) {
276 return params;
277 }
278 oauthHeader = oauthHeader.substring("OAuth ".length());
279 String[] elements = oauthHeader.split(",");
280 for (String keyValuePair : elements) {
281 String[] keyValue = keyValuePair.split("=");
282 params.put(keyValue[0].trim(), keyValue[1].replace("\"", "").trim());
283 }
284 return params;
285 }
286
287 /**
288 * Helper method to concatenate a parameter and its value to a pair that can
289 * be used in an HTTP header. This method percent encodes both parts before
290 * joining them.
291 *
292 * @param name
293 * the OAuth parameter name, e.g. oauth_token
294 * @param value
295 * the OAuth parameter value, e.g. 'hello oauth'
296 * @return a name/value pair, e.g. oauth_token="hello%20oauth"
297 */
298 public static String toHeaderElement(String name, String value) {
299 return OAuth.percentEncode(name) + "=\"" + OAuth.percentEncode(value) + "\"";
300 }
301
302 public static void debugOut(String key, String value) {
303 if (System.getProperty("debug") != null) {
304 System.out.println("[SIGNPOST] " + key + ": " + value);
305 }
306 }
307}
Note: See TracBrowser for help on using the repository browser.