summaryrefslogtreecommitdiff
path: root/core/src/main/java/net/oauth/OAuthMessage.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main/java/net/oauth/OAuthMessage.java')
-rwxr-xr-xcore/src/main/java/net/oauth/OAuthMessage.java394
1 files changed, 394 insertions, 0 deletions
diff --git a/core/src/main/java/net/oauth/OAuthMessage.java b/core/src/main/java/net/oauth/OAuthMessage.java
new file mode 100755
index 0000000..e16ca9b
--- /dev/null
+++ b/core/src/main/java/net/oauth/OAuthMessage.java
@@ -0,0 +1,394 @@
+/*
+ * Copyright 2007, 2008 Netflix, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.oauth;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import net.oauth.http.HttpMessage;
+import net.oauth.signature.OAuthSignatureMethod;
+
+/**
+ * A request or response message used in the OAuth protocol.
+ * <p>
+ * The parameters in this class are not percent-encoded. Methods like
+ * OAuthClient.invoke and OAuthResponseMessage.completeParameters are
+ * responsible for percent-encoding parameters before transmission and decoding
+ * them after reception.
+ *
+ * @author John Kristian
+ * @hide
+ */
+public class OAuthMessage {
+
+ public OAuthMessage(String method, String URL,
+ Collection<? extends Map.Entry> parameters) {
+ this.method = method;
+ this.URL = URL;
+ if (parameters == null) {
+ this.parameters = new ArrayList<Map.Entry<String, String>>();
+ } else {
+ this.parameters = new ArrayList<Map.Entry<String, String>>(parameters.size());
+ for (Map.Entry p : parameters) {
+ this.parameters.add(new OAuth.Parameter(
+ toString(p.getKey()), toString(p.getValue())));
+ }
+ }
+ }
+
+ public String method;
+ public String URL;
+
+ private final List<Map.Entry<String, String>> parameters;
+ private Map<String, String> parameterMap;
+ private boolean parametersAreComplete = false;
+ private final List<Map.Entry<String, String>> headers = new ArrayList<Map.Entry<String, String>>();
+
+ public String toString() {
+ return "OAuthMessage(" + method + ", " + URL + ", " + parameters + ")";
+ }
+
+ /** A caller is about to get a parameter. */
+ private void beforeGetParameter() throws IOException {
+ if (!parametersAreComplete) {
+ completeParameters();
+ parametersAreComplete = true;
+ }
+ }
+
+ /**
+ * Finish adding parameters; for example read an HTTP response body and
+ * parse parameters from it.
+ */
+ protected void completeParameters() throws IOException {
+ }
+
+ public List<Map.Entry<String, String>> getParameters() throws IOException {
+ beforeGetParameter();
+ return Collections.unmodifiableList(parameters);
+ }
+
+ public void addParameter(String key, String value) {
+ addParameter(new OAuth.Parameter(key, value));
+ }
+
+ public void addParameter(Map.Entry<String, String> parameter) {
+ parameters.add(parameter);
+ parameterMap = null;
+ }
+
+ public void addParameters(
+ Collection<? extends Map.Entry<String, String>> parameters) {
+ this.parameters.addAll(parameters);
+ parameterMap = null;
+ }
+
+ public String getParameter(String name) throws IOException {
+ return getParameterMap().get(name);
+ }
+
+ public String getConsumerKey() throws IOException {
+ return getParameter(OAuth.OAUTH_CONSUMER_KEY);
+ }
+
+ public String getToken() throws IOException {
+ return getParameter(OAuth.OAUTH_TOKEN);
+ }
+
+ public String getSignatureMethod() throws IOException {
+ return getParameter(OAuth.OAUTH_SIGNATURE_METHOD);
+ }
+
+ public String getSignature() throws IOException {
+ return getParameter(OAuth.OAUTH_SIGNATURE);
+ }
+
+ protected Map<String, String> getParameterMap() throws IOException {
+ beforeGetParameter();
+ if (parameterMap == null) {
+ parameterMap = OAuth.newMap(parameters);
+ }
+ return parameterMap;
+ }
+
+ /**
+ * The MIME type of the body of this message.
+ *
+ * @return the MIME type, or null to indicate the type is unknown.
+ */
+ public String getBodyType() {
+ return getHeader(HttpMessage.CONTENT_TYPE);
+ }
+
+ /**
+ * The character encoding of the body of this message.
+ *
+ * @return the name of an encoding, or "ISO-8859-1" if no charset has been
+ * specified.
+ */
+ public String getBodyEncoding() {
+ return HttpMessage.DEFAULT_CHARSET;
+ }
+
+ /**
+ * The value of the last HTTP header with the given name. The name is case
+ * insensitive.
+ *
+ * @return the value of the last header, or null to indicate that there is
+ * no such header in this message.
+ */
+ public final String getHeader(String name) {
+ String value = null; // no such header
+ for (Map.Entry<String, String> header : getHeaders()) {
+ if (name.equalsIgnoreCase(header.getKey())) {
+ value = header.getValue();
+ }
+ }
+ return value;
+ }
+
+ /** All HTTP headers. You can add headers to this list. */
+ public final List<Map.Entry<String, String>> getHeaders() {
+ return headers;
+ }
+
+ /**
+ * Read the body of the HTTP request or response and convert it to a String.
+ * This method isn't repeatable, since it consumes and closes getBodyAsStream.
+ *
+ * @return the body, or null to indicate there is no body.
+ */
+ public final String readBodyAsString() throws IOException
+ {
+ InputStream body = getBodyAsStream();
+ return readAll(body, getBodyEncoding());
+ }
+
+ /**
+ * Get a stream from which to read the body of the HTTP request or response.
+ * This is designed to support efficient streaming of a large message.
+ * The caller must close the returned stream, to release the underlying
+ * resources such as the TCP connection for an HTTP response.
+ *
+ * @return a stream from which to read the body, or null to indicate there
+ * is no body.
+ */
+ public InputStream getBodyAsStream() throws IOException {
+ return null;
+ }
+
+ /** Construct a verbose description of this message and its origins. */
+ public Map<String, Object> getDump() throws IOException {
+ Map<String, Object> into = new HashMap<String, Object>();
+ dump(into);
+ return into;
+ }
+
+ protected void dump(Map<String, Object> into) throws IOException {
+ into.put("URL", URL);
+ if (parametersAreComplete) {
+ try {
+ into.putAll(getParameterMap());
+ } catch (Exception ignored) {
+ }
+ }
+ }
+
+ /**
+ * Verify that the required parameter names are contained in the actual
+ * collection.
+ *
+ * @throws OAuthProblemException
+ * one or more parameters are absent.
+ * @throws IOException
+ */
+ public void requireParameters(String... names)
+ throws OAuthProblemException, IOException {
+ Set<String> present = getParameterMap().keySet();
+ List<String> absent = new ArrayList<String>();
+ for (String required : names) {
+ if (!present.contains(required)) {
+ absent.add(required);
+ }
+ }
+ if (!absent.isEmpty()) {
+ OAuthProblemException problem = new OAuthProblemException(OAuth.Problems.PARAMETER_ABSENT);
+ problem.setParameter(OAuth.Problems.OAUTH_PARAMETERS_ABSENT, OAuth.percentEncode(absent));
+ throw problem;
+ }
+ }
+
+ /**
+ * Add some of the parameters needed to request access to a protected
+ * resource, if they aren't already in the message.
+ *
+ * @throws IOException
+ * @throws URISyntaxException
+ */
+ public void addRequiredParameters(OAuthAccessor accessor)
+ throws OAuthException, IOException, URISyntaxException {
+ final Map<String, String> pMap = OAuth.newMap(parameters);
+ if (pMap.get(OAuth.OAUTH_TOKEN) == null && accessor.accessToken != null) {
+ addParameter(OAuth.OAUTH_TOKEN, accessor.accessToken);
+ }
+ final OAuthConsumer consumer = accessor.consumer;
+ if (pMap.get(OAuth.OAUTH_CONSUMER_KEY) == null) {
+ addParameter(OAuth.OAUTH_CONSUMER_KEY, consumer.consumerKey);
+ }
+ String signatureMethod = pMap.get(OAuth.OAUTH_SIGNATURE_METHOD);
+ if (signatureMethod == null) {
+ signatureMethod = (String) consumer.getProperty(OAuth.OAUTH_SIGNATURE_METHOD);
+ if (signatureMethod == null) {
+ signatureMethod = OAuth.HMAC_SHA1;
+ }
+ addParameter(OAuth.OAUTH_SIGNATURE_METHOD, signatureMethod);
+ }
+ if (pMap.get(OAuth.OAUTH_TIMESTAMP) == null) {
+ addParameter(OAuth.OAUTH_TIMESTAMP, (System.currentTimeMillis() / 1000) + "");
+ }
+ if (pMap.get(OAuth.OAUTH_NONCE) == null) {
+ addParameter(OAuth.OAUTH_NONCE, System.nanoTime() + "");
+ }
+ if (pMap.get(OAuth.OAUTH_VERSION) == null) {
+ addParameter(OAuth.OAUTH_VERSION, OAuth.VERSION_1_0);
+ }
+ this.sign(accessor);
+ }
+
+ /**
+ * Add a signature to the message.
+ *
+ * @throws URISyntaxException
+ */
+ public void sign(OAuthAccessor accessor) throws IOException,
+ OAuthException, URISyntaxException {
+ OAuthSignatureMethod.newSigner(this, accessor).sign(this);
+ }
+
+ /**
+ * Check that the message is valid.
+ *
+ * @throws IOException
+ * @throws URISyntaxException
+ *
+ * @throws OAuthProblemException
+ * the message is invalid
+ */
+ public void validateMessage(OAuthAccessor accessor, OAuthValidator validator)
+ throws OAuthException, IOException, URISyntaxException {
+ validator.validateMessage(this, accessor);
+ }
+
+ /**
+ * Construct a WWW-Authenticate or Authentication header value, containing
+ * the given realm plus all the parameters whose names begin with "oauth_".
+ */
+ public String getAuthorizationHeader(String realm) throws IOException {
+ StringBuilder into = new StringBuilder();
+ if (realm != null) {
+ into.append(" realm=\"").append(OAuth.percentEncode(realm)).append('"');
+ }
+ beforeGetParameter();
+ if (parameters != null) {
+ for (Map.Entry parameter : parameters) {
+ String name = toString(parameter.getKey());
+ if (name.startsWith("oauth_")) {
+ if (into.length() > 0) into.append(",");
+ into.append(" ");
+ into.append(OAuth.percentEncode(name)).append("=\"");
+ into.append(OAuth.percentEncode(toString(parameter.getValue()))).append('"');
+ }
+ }
+ }
+ return AUTH_SCHEME + into.toString();
+ }
+
+ /**
+ * Read all the data from the given stream, and close it.
+ *
+ * @return null if from is null, or the data from the stream converted to a
+ * String
+ */
+ public static String readAll(InputStream from, String encoding) throws IOException
+ {
+ if (from == null) {
+ return null;
+ }
+ try {
+ StringBuilder into = new StringBuilder();
+ Reader r = new InputStreamReader(from, encoding);
+ char[] s = new char[512];
+ for (int n; 0 < (n = r.read(s));) {
+ into.append(s, 0, n);
+ }
+ return into.toString();
+ } finally {
+ from.close();
+ }
+ }
+
+ /**
+ * Parse the parameters from an OAuth Authorization or WWW-Authenticate
+ * header. The realm is included as a parameter. If the given header doesn't
+ * start with "OAuth ", return an empty list.
+ */
+ public static List<OAuth.Parameter> decodeAuthorization(String authorization) {
+ List<OAuth.Parameter> into = new ArrayList<OAuth.Parameter>();
+ if (authorization != null) {
+ Matcher m = AUTHORIZATION.matcher(authorization);
+ if (m.matches()) {
+ if (AUTH_SCHEME.equalsIgnoreCase(m.group(1))) {
+ for (String nvp : m.group(2).split("\\s*,\\s*")) {
+ m = NVP.matcher(nvp);
+ if (m.matches()) {
+ String name = OAuth.decodePercent(m.group(1));
+ String value = OAuth.decodePercent(m.group(2));
+ into.add(new OAuth.Parameter(name, value));
+ }
+ }
+ }
+ }
+ }
+ return into;
+ }
+
+ public static final String AUTH_SCHEME = "OAuth";
+
+ public static final String GET = "GET";
+ public static final String POST = "POST";
+ public static final String PUT = "PUT";
+ public static final String DELETE = "DELETE";
+
+ private static final Pattern AUTHORIZATION = Pattern.compile("\\s*(\\w*)\\s+(.*)");
+ private static final Pattern NVP = Pattern.compile("(\\S*)\\s*\\=\\s*\"([^\"]*)\"");
+
+ private static final String toString(Object from) {
+ return (from == null) ? null : from.toString();
+ }
+
+}