/*
* Copyright (c) 2005 Aetrion LLC.
*/
package com.googlecode.flickrjandroid.oauth;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.googlecode.flickrjandroid.Flickr;
import com.googlecode.flickrjandroid.FlickrException;
import com.googlecode.flickrjandroid.Parameter;
import com.googlecode.flickrjandroid.REST;
import com.googlecode.flickrjandroid.RequestContext;
import com.googlecode.flickrjandroid.Response;
import com.googlecode.flickrjandroid.Transport;
import com.googlecode.flickrjandroid.auth.Permission;
import com.googlecode.flickrjandroid.people.User;
import com.googlecode.flickrjandroid.util.UrlUtilities;
import com.rafali.common.ToolString;
/**
* Authentication interface for the new Flickr OAuth 1a support: http://www.flickr.com/services/api/auth.oauth.html
*
* @author Toby Yu
*/
public class OAuthInterface {
public static final String METHOD_TEST_LOGIN = "flickr.test.login";
public static final String KEY_OAUTH_CALLBACK_CONFIRMED = "oauth_callback_confirmed";
public static final String KEY_OAUTH_TOKEN = "oauth_token";
public static final String KEY_OAUTH_TOKEN_SECRET = "oauth_token_secret";
public static final String KEY_OAUTH_VERIFIER = "oauth_verifier";
public static final String PATH_OAUTH_REQUEST_TOKEN = "/services/oauth/request_token";
public static final String PATH_OAUTH_ACCESS_TOKEN = "/services/oauth/access_token";
public static final String PATH_REST = "/services/rest";
public static final String URL_REQUEST_TOKEN = "https://" + Flickr.DEFAULT_API_HOST + PATH_OAUTH_REQUEST_TOKEN;
public static final String URL_ACCESS_TOKEN = "https://" + Flickr.DEFAULT_API_HOST + PATH_OAUTH_ACCESS_TOKEN;
public static final String URL_REST = "https://" + Flickr.DEFAULT_API_HOST + PATH_REST;
public static final String PARAM_OAUTH_CONSUMER_KEY = "oauth_consumer_key";
public static final String PARAM_OAUTH_TOKEN = "oauth_token";
private String apiKey;
private String sharedSecret;
private REST oauthTransport;
private static final Logger logger = LoggerFactory.getLogger(OAuthInterface.class);
/**
* Construct the AuthInterface.
*
* @param apiKey
* The API key
* @param transport
* The Transport interface
*/
public OAuthInterface(String apiKey, String sharedSecret, Transport transport) {
this.apiKey = apiKey;
this.sharedSecret = sharedSecret;
this.oauthTransport = (REST) transport;
}
public User testLogin() throws FlickrException, IOException, JSONException {
List<Parameter> parameters = new ArrayList<Parameter>();
parameters.add(new Parameter("method", METHOD_TEST_LOGIN));
parameters.add(new Parameter(OAuthInterface.PARAM_OAUTH_CONSUMER_KEY, apiKey));
OAuthUtils.addOAuthToken(parameters);
Response response = this.oauthTransport.postJSON(this.sharedSecret, parameters);
if (response.isError()) {
throw new FlickrException(response.getErrorCode(), response.getErrorMessage());
}
JSONObject jObj = response.getData();
JSONObject userObj = jObj.getJSONObject("user");
String id = userObj.getString("id");
String name = userObj.getJSONObject("username").getString("_content");
User user = new User();
user.setId(id);
user.setUsername(name);
return user;
}
/**
* Get a request token.
*
* @return the frob
* @throws IOException
* @throws FlickrException
*/
public OAuthToken getRequestToken(String callbackUrl) throws IOException, FlickrException {
if (callbackUrl == null)
callbackUrl = "oob";
List<Parameter> parameters = new ArrayList<Parameter>();
parameters.add(new Parameter("oauth_callback", callbackUrl));
parameters.add(new Parameter(OAuthInterface.PARAM_OAUTH_CONSUMER_KEY, apiKey));
OAuthUtils.addBasicOAuthParams(parameters);
String signature = OAuthUtils.getSignature(OAuthUtils.REQUEST_METHOD_GET, URL_REQUEST_TOKEN, parameters, sharedSecret, null);
// This method call must be signed.
parameters.add(new Parameter("oauth_signature", signature));
logger.info("Getting Request Token " + PATH_OAUTH_REQUEST_TOKEN + " with parameters: {}", parameters);
String token = null;
String token_secret = null;
int retry = 0;
Throwable exc = null;
while (token == null && retry < 5) {
try {
exc = null;
Map<String, String> response = this.oauthTransport.getMapData(true, PATH_OAUTH_REQUEST_TOKEN, parameters);
if (response.isEmpty()) {
exc = new FlickrException("Empty Response", "Empty Response");
}
if (response.containsKey(KEY_OAUTH_CALLBACK_CONFIRMED) == false || Boolean.valueOf(response.get(KEY_OAUTH_CALLBACK_CONFIRMED)) == false) {
exc = new FlickrException("Error", "Invalid response: " + response);
}
logger.info("Response: {}", response);
token = response.get(KEY_OAUTH_TOKEN);
token_secret = response.get(KEY_OAUTH_TOKEN_SECRET);
} catch (Throwable e) {
exc = e;
} finally {
retry++;
if (exc != null) {
try {
logger.warn("sleeping a bit, retry=" + retry + ", exc=" + ToolString.stack2string(exc));
Thread.sleep(retry * 1000L);
} catch (InterruptedException e) {
}
}
}
}
if (token == null && exc != null) {
if (exc instanceof FlickrException)
throw (FlickrException) exc;
else if (exc instanceof RuntimeException)
throw (RuntimeException) exc;
else if (exc instanceof IOException)
throw (IOException) exc;
else
throw new RuntimeException(exc);
}
OAuth oauth = new OAuth();
oauth.setToken(new OAuthToken(token, token_secret));
// RequestContext.getRequestContext().setOAuth(oauth);
return oauth.getToken();
}
/**
* @param requestToken
* @param tokenSecret
* @param oauthVerifier
* @throws IOException
* @throws FlickrException
*/
public OAuth getAccessToken(String token, String tokenSecret, String oauthVerifier) throws IOException, FlickrException {
List<Parameter> parameters = new ArrayList<Parameter>();
parameters.add(new Parameter(OAuthInterface.PARAM_OAUTH_CONSUMER_KEY, apiKey));
parameters.add(new OAuthTokenParameter(token));
parameters.add(new Parameter(KEY_OAUTH_VERIFIER, oauthVerifier));
OAuthUtils.addBasicOAuthParams(parameters);
// OAuthUtils.signPost(sharedSecret, URL_ACCESS_TOKEN, parameters);
String signature = OAuthUtils.getSignature(OAuthUtils.REQUEST_METHOD_POST, URL_ACCESS_TOKEN, parameters, sharedSecret, tokenSecret);
// This method call must be signed.
parameters.add(new Parameter("oauth_signature", signature));
// OAuthUtils.addOAuthParams(this.sharedSecret, URL_ACCESS_TOKEN, parameters);
int retry = 0;
Throwable exc = null;
OAuth result = null;
while (result == null && retry < 5) {
try {
exc = null;
result = null;
Map<String, String> response = this.oauthTransport.getMapData(false, PATH_OAUTH_ACCESS_TOKEN, parameters);
logger.info("Response: {}", response);
if (response.isEmpty()) {
exc = new FlickrException("Empty Response", "Empty Response");
}
if (response.containsKey("oauth_token") == false) {
exc = new FlickrException("Error", "Invalid response: " + response);
}
if (exc == null) {
result = new OAuth();
User user = new User();
user.setId(response.get("user_nsid"));
user.setUsername(response.get("username"));
user.setRealName(response.get("fullname"));
result.setUser(user);
result.setToken(new OAuthToken(response.get("oauth_token"), response.get("oauth_token_secret")));
RequestContext.getRequestContext().setOAuth(result);
}
} catch (Throwable e) {
exc = e;
} finally {
retry++;
if (exc != null) {
try {
logger.warn("sleeping a bit, retry=" + retry + ", exc=" + ToolString.stack2string(exc));
Thread.sleep(retry * 1000L);
} catch (InterruptedException e) {
}
}
}
}
if (token == null && exc != null) {
if (exc instanceof FlickrException)
throw (FlickrException) exc;
else if (exc instanceof RuntimeException)
throw (RuntimeException) exc;
else if (exc instanceof IOException)
throw (IOException) exc;
else
throw new RuntimeException(exc);
}
return result;
}
/**
* Build the authentication URL using the given permission and frob.
*
* The hostname used here is www.flickr.com. It differs from the api-default api.flickr.com.
*
* @param permission
* The Permission
* @param frob
* The frob returned from getFrob()
* @return The URL
* @throws MalformedURLException
*/
public URL buildAuthenticationUrl(Permission permission, OAuthToken oauthToken) throws MalformedURLException {
List<Parameter> parameters = new ArrayList<Parameter>();
parameters.add(new Parameter(PARAM_OAUTH_TOKEN, oauthToken.getOauthToken()));
if (permission != null) {
parameters.add(new Parameter("perms", permission.toString()));
}
int port = oauthTransport.getPort();
String path = "/services/oauth/authorize";
return UrlUtilities.buildUrl(Flickr.DEFAULT_API_HOST, port, path, parameters);
}
}