1b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien/* 2b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Copyright 2007 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.signature; 18b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 19b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.io.IOException; 20b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.net.URI; 21b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.net.URISyntaxException; 22b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.ArrayList; 23b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.Collection; 24b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.Collections; 25b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.List; 26b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.Map; 27b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.concurrent.ConcurrentHashMap; 28b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.OAuth; 29b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.OAuthAccessor; 30b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.OAuthConsumer; 31b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.OAuthException; 32b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.OAuthMessage; 33b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.OAuthProblemException; 3464b058597da6260646ba8dc68fdcfb3982b16bffDan Egnor// BEGIN android-changed 3564b058597da6260646ba8dc68fdcfb3982b16bffDan Egnor// import org.apache.commons.codec.binary.Base64; 36c76276a1d6165cfb502b06f65b1735fef0754d26Doug Zongkerimport android.util.Base64; 3764b058597da6260646ba8dc68fdcfb3982b16bffDan Egnor// END android-changed 38b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 39b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien/** 40b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * A pair of algorithms for computing and verifying an OAuth digital signature. 41b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 42b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @author John Kristian 43b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @hide 44b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 45b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienpublic abstract class OAuthSignatureMethod { 46b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 47b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** Add a signature to the message. 48b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws URISyntaxException 49b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws IOException */ 50b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public void sign(OAuthMessage message) 51b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien throws OAuthException, IOException, URISyntaxException { 52b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien message.addParameter(new OAuth.Parameter("oauth_signature", 53b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien getSignature(message))); 54b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 55b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 56b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 57b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Check whether the message has a valid signature. 58b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws URISyntaxException 59b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 60b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @throws OAuthProblemException 61b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * the signature is invalid 62b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 63b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public void validate(OAuthMessage message) 64b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien throws IOException, OAuthException, URISyntaxException { 65b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien message.requireParameters("oauth_signature"); 66b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String signature = message.getSignature(); 67b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String baseString = getBaseString(message); 68b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (!isValid(signature, baseString)) { 69b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuthProblemException problem = new OAuthProblemException( 70b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien "signature_invalid"); 71b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien problem.setParameter("oauth_signature", signature); 72b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien problem.setParameter("oauth_signature_base_string", baseString); 73b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien problem.setParameter("oauth_signature_method", message 74b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien .getSignatureMethod()); 75b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien throw problem; 76b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 77b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 78b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 79b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien protected String getSignature(OAuthMessage message) 80b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien throws OAuthException, IOException, URISyntaxException { 81b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String baseString = getBaseString(message); 82b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String signature = getSignature(baseString); 83b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien // Logger log = Logger.getLogger(getClass().getName()); 84b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien // if (log.isLoggable(Level.FINE)) { 85b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien // log.fine(signature + "=getSignature(" + baseString + ")"); 86b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien // } 87b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return signature; 88b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 89b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 90b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien protected void initialize(String name, OAuthAccessor accessor) 91b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien throws OAuthException { 92b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String secret = accessor.consumer.consumerSecret; 93b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (name.endsWith(_ACCESSOR)) { 94b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien // This code supports the 'Accessor Secret' extensions 95b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien // described in http://oauth.pbwiki.com/AccessorSecret 96b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien final String key = OAuthConsumer.ACCESSOR_SECRET; 97b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien Object accessorSecret = accessor.getProperty(key); 98b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (accessorSecret == null) { 99b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien accessorSecret = accessor.consumer.getProperty(key); 100b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 101b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (accessorSecret != null) { 102b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien secret = accessorSecret.toString(); 103b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 104b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 105b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (secret == null) { 106b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien secret = ""; 107b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 108b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien setConsumerSecret(secret); 109b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 110b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 111b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static final String _ACCESSOR = "-Accessor"; 112b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 113b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** Compute the signature for the given base string. */ 114b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien protected abstract String getSignature(String baseString) throws OAuthException; 115b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 116b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** Decide whether the signature is valid. */ 117b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien protected abstract boolean isValid(String signature, String baseString) 118b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien throws OAuthException; 119b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 120b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private String consumerSecret; 121b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 122b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private String tokenSecret; 123b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 124b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien protected String getConsumerSecret() { 125b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return consumerSecret; 126b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 127b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 128b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien protected void setConsumerSecret(String consumerSecret) { 129b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien this.consumerSecret = consumerSecret; 130b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 131b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 132b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public String getTokenSecret() { 133b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return tokenSecret; 134b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 135b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 136b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public void setTokenSecret(String tokenSecret) { 137b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien this.tokenSecret = tokenSecret; 138b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 139b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 140b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static String getBaseString(OAuthMessage message) 141b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien throws IOException, URISyntaxException { 142b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien List<Map.Entry<String, String>> parameters; 143b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String url = message.URL; 144b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien int q = url.indexOf('?'); 145b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (q < 0) { 146b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien parameters = message.getParameters(); 147b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } else { 148b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien // Combine the URL query string with the other parameters: 149b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien parameters = new ArrayList<Map.Entry<String, String>>(); 150b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien parameters.addAll(OAuth.decodeForm(message.URL.substring(q + 1))); 151b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien parameters.addAll(message.getParameters()); 152b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien url = url.substring(0, q); 153b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 154b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return OAuth.percentEncode(message.method.toUpperCase()) + '&' 155b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien + OAuth.percentEncode(normalizeUrl(url)) + '&' 156b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien + OAuth.percentEncode(normalizeParameters(parameters)); 157b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 158b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 159b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien protected static String normalizeUrl(String url) throws URISyntaxException { 160b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien URI uri = new URI(url); 161b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String scheme = uri.getScheme().toLowerCase(); 162b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String authority = uri.getAuthority().toLowerCase(); 163b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien boolean dropPort = (scheme.equals("http") && uri.getPort() == 80) 164b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien || (scheme.equals("https") && uri.getPort() == 443); 165b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (dropPort) { 166b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien // find the last : in the authority 167b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien int index = authority.lastIndexOf(":"); 168b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (index >= 0) { 169b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien authority = authority.substring(0, index); 170b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 171b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 172b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String path = uri.getRawPath(); 173b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (path == null || path.length() <= 0) { 174b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien path = "/"; // conforms to RFC 2616 section 3.2.2 175b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 176b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien // we know that there is no query and no fragment here. 177b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return scheme + "://" + authority + path; 178b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 179b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 180b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien protected static String normalizeParameters( 181b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien Collection<? extends Map.Entry> parameters) throws IOException { 182b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (parameters == null) { 183b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return ""; 184b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 185b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien List<ComparableParameter> p = new ArrayList<ComparableParameter>( 186b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien parameters.size()); 187b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien for (Map.Entry parameter : parameters) { 188b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (!"oauth_signature".equals(parameter.getKey())) { 189b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien p.add(new ComparableParameter(parameter)); 190b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 191b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 192b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien Collections.sort(p); 193b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return OAuth.formEncode(getParameters(p)); 194b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 195b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 19664b058597da6260646ba8dc68fdcfb3982b16bffDan Egnor // BEGIN android-changed 197b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static byte[] decodeBase64(String s) { 19864b058597da6260646ba8dc68fdcfb3982b16bffDan Egnor return Base64.decode(s, Base64.DEFAULT); 199b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 200b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 201b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static String base64Encode(byte[] b) { 20264b058597da6260646ba8dc68fdcfb3982b16bffDan Egnor return Base64.encodeToString(b, Base64.DEFAULT); 203b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 20464b058597da6260646ba8dc68fdcfb3982b16bffDan Egnor // END android-changed 205b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 206b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static OAuthSignatureMethod newSigner(OAuthMessage message, 207b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuthAccessor accessor) throws IOException, OAuthException { 208b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien message.requireParameters(OAuth.OAUTH_SIGNATURE_METHOD); 209b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuthSignatureMethod signer = newMethod(message.getSignatureMethod(), 210b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien accessor); 211b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien signer.setTokenSecret(accessor.tokenSecret); 212b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return signer; 213b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 214b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 215b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** The factory for signature methods. */ 216b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static OAuthSignatureMethod newMethod(String name, 217b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuthAccessor accessor) throws OAuthException { 218b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien try { 219b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien Class methodClass = NAME_TO_CLASS.get(name); 220b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (methodClass != null) { 221b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuthSignatureMethod method = (OAuthSignatureMethod) methodClass 222b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien .newInstance(); 223b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien method.initialize(name, accessor); 224b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return method; 225b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 226b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien OAuthProblemException problem = new OAuthProblemException( 227b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien "signature_method_rejected"); 228b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String acceptable = OAuth.percentEncode(NAME_TO_CLASS.keySet()); 229b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (acceptable.length() > 0) { 230b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien problem.setParameter("oauth_acceptable_signature_methods", 231b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien acceptable.toString()); 232b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 233b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien throw problem; 234b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } catch (InstantiationException e) { 235b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien throw new OAuthException(e); 236b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } catch (IllegalAccessException e) { 237b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien throw new OAuthException(e); 238b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 239b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 240b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 241b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 242b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Subsequently, newMethod(name) will attempt to instantiate the given 243b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * class, with no constructor parameters. 244b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 245b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static void registerMethodClass(String name, Class clazz) { 246b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien NAME_TO_CLASS.put(name, clazz); 247b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 248b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 249b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private static final Map<String, Class> NAME_TO_CLASS = new ConcurrentHashMap<String, Class>(); 250b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien static { 251b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien registerMethodClass("HMAC-SHA1", HMAC_SHA1.class); 252b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien registerMethodClass("PLAINTEXT", PLAINTEXT.class); 253b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien registerMethodClass("RSA-SHA1", RSA_SHA1.class); 254b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien registerMethodClass("HMAC-SHA1" + _ACCESSOR, HMAC_SHA1.class); 255b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien registerMethodClass("PLAINTEXT" + _ACCESSOR, PLAINTEXT.class); 256b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 257b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 258b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** An efficiently sortable wrapper around a parameter. */ 259b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private static class ComparableParameter implements 260b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien Comparable<ComparableParameter> { 261b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 262b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien ComparableParameter(Map.Entry value) { 263b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien this.value = value; 264b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String n = toString(value.getKey()); 265b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String v = toString(value.getValue()); 266b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien this.key = OAuth.percentEncode(n) + ' ' + OAuth.percentEncode(v); 267b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien // ' ' is used because it comes before any character 268b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien // that can appear in a percentEncoded string. 269b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 270b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 271b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien final Map.Entry value; 272b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 273b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private final String key; 274b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 275b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private static String toString(Object from) { 276b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return (from == null) ? null : from.toString(); 277b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 278b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 279b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public int compareTo(ComparableParameter that) { 280b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return this.key.compareTo(that.key); 281b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 282b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 283b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien @Override 284b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public String toString() { 285b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return key; 286b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 287b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 288b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 289b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 290b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** Retrieve the original parameters from a sorted collection. */ 291b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private static List<Map.Entry> getParameters( 292b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien Collection<ComparableParameter> parameters) { 293b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (parameters == null) { 294b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return null; 295b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 296b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien List<Map.Entry> list = new ArrayList<Map.Entry>(parameters.size()); 297b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien for (ComparableParameter parameter : parameters) { 298b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien list.add(parameter.value); 299b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 300b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return list; 301b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 302b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 303b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien} 304