package org.fluxtream.connectors.misfit;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.message.BasicNameValuePair;
import org.fluxtream.connectors.controllers.ControllerSupport;
import org.fluxtream.core.Configuration;
import org.fluxtream.core.auth.AuthHelper;
import org.fluxtream.core.connectors.Connector;
import org.fluxtream.core.domain.ApiKey;
import org.fluxtream.core.domain.Guest;
import org.fluxtream.core.services.GuestService;
import org.fluxtream.core.utils.HttpUtils;
import org.fluxtream.core.utils.UnexpectedHttpResponseCodeException;
import org.scribe.builder.ServiceBuilder;
import org.scribe.model.Token;
import org.scribe.oauth.OAuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
/**
* Created by candide on 09/02/15.
*/
@Controller
@RequestMapping(value = "/misfit")
public class MisfitOAuthController {
private static final String MISFIT_SERVICE = "misfitService";
private static final Token EMPTY_TOKEN = null;
private static final String MISFIT_RENEWTOKEN_APIKEYID = "misfit.renewtoken.apiKeyId";
@Autowired
Configuration env;
@Autowired
GuestService guestService;
@RequestMapping(value = "/token")
public String getMisfitToken(HttpServletRequest request) throws IOException, ServletException {
OAuthService service = getOAuthService(request);
request.getSession().setAttribute(MISFIT_SERVICE, service);
// Obtain the Authorization URL
String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN);
authorizationUrl += authorizationUrl.indexOf("?")!=-1
? "&scope=public,birthday,email"
: "?scope=public,birthday,email";
String apiKeyIdParameter = request.getParameter("apiKeyId");
if (apiKeyIdParameter != null) {
request.getSession().setAttribute(MISFIT_RENEWTOKEN_APIKEYID, apiKeyIdParameter);
authorizationUrl += authorizationUrl.indexOf("?") != -1
? "&state=" + apiKeyIdParameter
: "?state=" + apiKeyIdParameter;
}
return "redirect:" + authorizationUrl;
}
public OAuthService getOAuthService(HttpServletRequest request) {
return new ServiceBuilder()
.provider(MisfitApi.class)
.apiKey(getConsumerKey())
.apiSecret(getConsumerSecret())
.callback(ControllerSupport.getLocationBase(request, env) + "misfit/upgradeToken")
.build();
}
@RequestMapping(value = "/upgradeToken")
public String upgradeToken(HttpServletRequest request) throws IOException, NoSuchAlgorithmException, UnexpectedHttpResponseCodeException, KeyManagementException {
final String code = request.getParameter("code");
Map<String,String> parameters = new HashMap<String,String>();
parameters.put("grant_type", "authorization_code");
parameters.put("code", code);
parameters.put("redirect_uri", env.get("homeBaseUrl") + "misfit/upgradeToken");
parameters.put("client_id", env.get("misfitConsumerKey"));
parameters.put("client_secret", env.get("misfitConsumerSecret"));
final String json = fetch("https://api.misfitwearables.com/auth/tokens/exchange?grant_type=authorization_code", parameters);
JSONObject token = JSONObject.fromObject(json);
// Create the entry for this new apiKey in the apiKey table and populate
// ApiKeyAttributes with all of the keys fro oauth.properties needed for
// subsequent update of this connector instance.
ApiKey apiKey;
Guest guest = AuthHelper.getGuest();
final Connector connector = Connector.getConnector("misfit");
final String stateParameter = request.getParameter("state");
if (stateParameter !=null&&!StringUtils.isEmpty(stateParameter)) {
long apiKeyId = Long.valueOf(stateParameter);
apiKey = guestService.getApiKey(apiKeyId);
} else {
apiKey = guestService.createApiKey(guest.getId(), connector);
}
guestService.populateApiKey(apiKey.getId());
guestService.setApiKeyAttribute(apiKey,
"accessToken", token.getString("access_token"));
request.getSession().removeAttribute(MISFIT_SERVICE);
if (request.getSession().getAttribute(MISFIT_RENEWTOKEN_APIKEYID) != null) {
request.getSession().removeAttribute(MISFIT_RENEWTOKEN_APIKEYID);
return "redirect:/app/tokenRenewed/misfit";
}
return "redirect:/app/from/misfit";
}
public String fetch(String url, Map<String, String> params) throws UnexpectedHttpResponseCodeException, IOException, KeyManagementException, NoSuchAlgorithmException {
HttpClient client = env.getHttpClient();
if (env.get("development") != null && env.get("development").equals("true")) {
// HttpHost proxy = new HttpHost("127.0.0.1", 8888, "http");
// client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,proxy);
client = HttpUtils.httpClientTrustingAllSSLCerts();
}
String content = "";
try {
HttpPost post = new HttpPost(url);
Iterator<Map.Entry<String, String>> iterator = params.entrySet().iterator();
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(params.size());
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
nameValuePairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
post.setEntity(new UrlEncodedFormEntity(nameValuePairs, "utf-8"));
HttpResponse response = client.execute(post);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
ResponseHandler<String> responseHandler = new BasicResponseHandler();
content = responseHandler.handleResponse(response);
}
else {
throw new UnexpectedHttpResponseCodeException(response.getStatusLine().getStatusCode(),
response.getStatusLine().getReasonPhrase());
}
}
finally {
client.getConnectionManager().shutdown();
}
return content;
}
String getConsumerKey() {
return env.get("misfitConsumerKey");
}
String getConsumerSecret() {
return env.get("misfitConsumerSecret");
}
}