/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.shindig.social.core.oauth;
import com.google.common.collect.Lists;
import net.oauth.OAuth;
import net.oauth.OAuthAccessor;
import net.oauth.OAuthConsumer;
import net.oauth.OAuthMessage;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shindig.auth.OAuthConstants;
import org.apache.shindig.common.testing.FakeHttpServletRequest;
import org.apache.shindig.common.uri.Uri;
import org.apache.shindig.common.uri.UriBuilder;
import org.apache.shindig.common.util.CharsetUtil;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* This is largely a copy of OAuthCommandLine with some tweaks for FakeHttpServletRequest
*/
public class FakeOAuthRequest {
public static enum BodySigning {
NONE,
HASH,
LEGACY
}
public static enum OAuthParamLocation {
AUTH_HEADER,
POST_BODY,
URI_QUERY
}
public static final String CONSUMER_KEY = "gadget:12345";
public static final String CONSUMER_SECRET = "secret";
public static final String REQUESTOR = "requestor12345";
final String method;
final String url;
final String body;
final String contentType;
public FakeOAuthRequest(String method, String url, String body, String contentType) {
this.method = method;
this.url = url;
this.body = body;
this.contentType = contentType;
}
public FakeHttpServletRequest sign(String token, OAuthParamLocation paramLocationEnum,
BodySigning bodySigning)
throws Exception {
return sign(CONSUMER_KEY, CONSUMER_SECRET, REQUESTOR, token,
(token == null) ? null :CONSUMER_SECRET,
paramLocationEnum, bodySigning);
}
public FakeHttpServletRequest sign(String consumerKey, String consumerSecret, String requestor,
String token, String tokenSecret, OAuthParamLocation paramLocationEnum,
BodySigning bodySigning)
throws Exception {
FakeHttpServletRequest request = new FakeHttpServletRequest(url);
List<OAuth.Parameter> oauthParams = Lists.newArrayList();
UriBuilder target = new UriBuilder(Uri.parse(url));
String query = target.getQuery();
target.setQuery(null);
oauthParams.addAll(OAuth.decodeForm(query));
if (body != null) {
if (OAuth.isFormEncoded(contentType)) {
oauthParams.addAll(OAuth.decodeForm(body));
} else if (bodySigning == BodySigning.LEGACY) {
oauthParams.add(new OAuth.Parameter(body, ""));
} else if (bodySigning == BodySigning.HASH) {
oauthParams.add(
new OAuth.Parameter(OAuthConstants.OAUTH_BODY_HASH,
new String(Base64.encodeBase64(DigestUtils.sha(body.getBytes())), "UTF-8")));
}
}
oauthParams.add(new OAuth.Parameter(OAuth.OAUTH_CONSUMER_KEY, consumerKey));
oauthParams.add(new OAuth.Parameter("xoauth_requestor_id", requestor));
OAuthConsumer consumer = new OAuthConsumer(null,consumerKey,consumerSecret, null);
OAuthAccessor accessor = new OAuthAccessor(consumer);
if (!StringUtils.isEmpty(token)) {
accessor.accessToken = token;
accessor.tokenSecret = tokenSecret;
}
OAuthMessage message = accessor.newRequestMessage(method, target.toString(), oauthParams);
List<Map.Entry<String, String>> entryList = selectOAuthParams(message);
switch (paramLocationEnum) {
case AUTH_HEADER:
request.setHeader("Authorization", getAuthorizationHeader(entryList));
break;
case POST_BODY:
if (!OAuth.isFormEncoded(contentType)) {
throw new RuntimeException(
"OAuth param location can only be post_body if post body is of " +
"type x-www-form-urlencoded");
}
// All message params should be added if oauth params are added to body
for (Map.Entry<String, String> param : message.getParameters()) {
request.setParameter(param.getKey(), true, param.getValue());
}
String oauthData = OAuth.formEncode(message.getParameters());
request.setPostData(CharsetUtil.getUtf8Bytes(oauthData));
break;
case URI_QUERY:
request.setQueryString(Uri.parse(OAuth.addParameters(url, entryList)).getQuery());
break;
}
if (body != null && paramLocationEnum != OAuthParamLocation.POST_BODY) {
request.setContentType(contentType);
request.setPostData(body, "UTF-8");
if (contentType.contains(OAuth.FORM_ENCODED)) {
List<OAuth.Parameter> bodyParams = OAuth.decodeForm(body);
for (OAuth.Parameter bodyParam : bodyParams) {
request.setParameter(bodyParam.getKey(), bodyParam.getValue());
}
}
}
request.setMethod(method);
return request;
}
private static String getAuthorizationHeader(List<Map.Entry<String, String>> oauthParams) {
StringBuilder result = new StringBuilder("OAuth ");
boolean first = true;
for (Map.Entry<String, String> parameter : oauthParams) {
if (!first) {
result.append(", ");
} else {
first = false;
}
result.append(OAuth.percentEncode(parameter.getKey()))
.append("=\"")
.append(OAuth.percentEncode(parameter.getValue()))
.append('"');
}
return result.toString();
}
private static List<Map.Entry<String, String>> selectOAuthParams(OAuthMessage message)
throws IOException {
List<Map.Entry<String, String>> result = Lists.newArrayList();
for (Map.Entry<String, String> param : message.getParameters()) {
if (isContainerInjectedParameter(param.getKey())) {
result.add(param);
}
}
return result;
}
private static boolean isContainerInjectedParameter(String key) {
key = key.toLowerCase();
return key.startsWith("oauth") || key.startsWith("xoauth") || key.startsWith("opensocial");
}
}