Login page updated to get OAuth2 access token
[pub/Android/ownCloud.git] / src / com / owncloud / android / authenticator / oauth2 / services / OAuth2GetTokenService.java
diff --git a/src/com/owncloud/android/authenticator/oauth2/services/OAuth2GetTokenService.java b/src/com/owncloud/android/authenticator/oauth2/services/OAuth2GetTokenService.java
new file mode 100644 (file)
index 0000000..584b20b
--- /dev/null
@@ -0,0 +1,201 @@
+package com.owncloud.android.authenticator.oauth2.services;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.message.BasicNameValuePair;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+
+import com.owncloud.android.authenticator.oauth2.OAuth2Context;
+import com.owncloud.android.authenticator.oauth2.connection.ConnectorOAuth2;
+
+/**
+ * Service class that implements the second communication with the oAuth2 server:
+ * pooling for the token in an interval. It send a broadcast with the results when are positive;
+ * otherwise, it continues asking to the server.
+ * 
+ * @author Solid Gear S.L.
+ *
+ */
+public class OAuth2GetTokenService extends Service {
+
+    public static final String TOKEN_RECEIVED_MESSAGE = "TOKEN_RECEIVED";
+    public static final String TOKEN_RECEIVED_DATA = "TOKEN_DATA";
+    public static final String TOKEN_BASE_URI = "baseURI";
+    public static final String TOKEN_DEVICE_CODE = "device_code";
+    public static final String TOKEN_INTERVAL = "interval";
+    public static final String TOKEN_RECEIVED_ERROR = "error";
+    public static final String TOKEN_RECEIVED_ERROR_AUTH_TOKEN = "authorization_pending";
+    public static final String TOKEN_RECEIVED_ERROR_SLOW_DOWN = "slow_down";
+    public static final String TOKEN_ACCESS_TOKEN = "access_token";
+    public static final String TOKEN_TOKEN_TYPE = "token_type";
+    public static final String TOKEN_EXPIRES_IN = "expires_in";
+    public static final String TOKEN_REFRESH_TOKEN = "refresh_token";   
+    
+    private String requestDeviceCode;
+    private int requestInterval = -1;
+    private String requestBaseURI;
+    private ConnectorOAuth2 connectorOAuth2;
+    private static final String TAG = "OAuth2GetTokenService";
+    private Timer timer = new Timer();
+
+    @Override
+    public IBinder onBind(Intent arg0) {
+        return null;
+    }
+    
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        Bundle param = intent.getExtras();
+
+        if (param != null) {
+            String mUrl = param.getString(TOKEN_BASE_URI);     
+            if (!mUrl.startsWith("http://") || !mUrl.startsWith("https://")) {        
+                requestBaseURI = "https://" + mUrl;            
+            }     
+            requestDeviceCode = param.getString(TOKEN_DEVICE_CODE);
+            requestInterval = param.getInt(TOKEN_INTERVAL);
+            
+            Log.d(TAG, "onBind -> baseURI=" + requestBaseURI);
+            Log.d(TAG, "onBind -> requestDeviceCode=" + requestDeviceCode);
+            Log.d(TAG, "onBind -> requestInterval=" + requestInterval);                  
+        } else  {
+            Log.e(TAG, "onBind -> params could not be null");
+        }
+        startService();
+        return Service.START_NOT_STICKY;
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();       
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        shutdownService();
+    }
+
+    private void startService() {
+        final UrlEncodedFormEntity params = prepareComm();
+        timer.scheduleAtFixedRate(
+                new TimerTask() {
+                    public void run() {
+                        requestToken(params);
+                    }
+                },  0, requestInterval * 1000);
+        Log.d(TAG, "startService -> Timer started");
+    }    
+
+    private void shutdownService() {
+        if (timer != null) timer.cancel();
+        Log.d(TAG, "shutdownService -> Timer stopped");
+    }
+
+
+    private UrlEncodedFormEntity prepareComm() {
+
+        UrlEncodedFormEntity params = null;
+        connectorOAuth2 = new ConnectorOAuth2();
+
+        if (requestBaseURI == null || requestBaseURI.trim().equals("")) {
+            Log.e(TAG, "run -> request URI could not be null");
+            postResult(null);
+        }
+
+        if (requestInterval == -1) {
+            Log.e(TAG, "run -> request Interval must have valid positive value");
+            postResult(null);
+        }
+
+        if (requestDeviceCode == null || requestDeviceCode.trim().equals("")) {
+            Log.e(TAG, "run -> request DeviceCode could not be null");
+            postResult(null);
+        }        
+
+        try{            
+            connectorOAuth2.setConnectorOAuth2Url(requestBaseURI + OAuth2Context.OAUTH2_DEVICE_GETTOKEN_URL);
+
+            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
+            nameValuePairs.add(new BasicNameValuePair("client_id", OAuth2Context.OAUTH2_DEVICE_CLIENT_ID));
+            nameValuePairs.add(new BasicNameValuePair("client_secret", OAuth2Context.OAUTH2_DEVICE_CLIENT_SECRET));
+            nameValuePairs.add(new BasicNameValuePair("code",requestDeviceCode));            
+            nameValuePairs.add(new BasicNameValuePair("grant_type",OAuth2Context.OAUTH_DEVICE_GETTOKEN_GRANT_TYPE));  
+
+            params = new UrlEncodedFormEntity(nameValuePairs);
+        }
+        catch (Exception ex1){
+            Log.w(TAG, ex1.toString());
+            postResult(null);
+        }
+
+        return params;
+    }
+
+    protected void requestToken(UrlEncodedFormEntity params){
+        JSONObject tokenJson = null;
+        String error = null;
+        HashMap<String, String> resultTokenMap;
+
+        String tokenResponse = connectorOAuth2.connPost(params);
+
+        try {
+            tokenJson = new JSONObject(tokenResponse);
+        } catch (JSONException e) {
+            Log.e(TAG, "Exception converting to Json " + e.toString());
+        }        
+
+        try {
+            // We try to get error string.
+            if (tokenJson.has(TOKEN_RECEIVED_ERROR)) {
+                error = tokenJson.getString(TOKEN_RECEIVED_ERROR);
+                Log.d(TAG, "requestToken -> Obtained error "+ error);
+            } else {
+                //We have got the token. Parse the answer.
+                resultTokenMap = parseResult(tokenJson);
+                postResult(resultTokenMap);                
+            }
+        } catch (JSONException e) {
+            Log.e(TAG, "Exception converting to Json " + e.toString());
+        }
+    }
+    
+    private HashMap<String, String> parseResult (JSONObject tokenJson) {
+        HashMap<String, String> resultTokenMap=new HashMap<String, String>();
+        
+        try {
+            resultTokenMap.put(TOKEN_ACCESS_TOKEN, tokenJson.getString(TOKEN_ACCESS_TOKEN)); 
+            resultTokenMap.put(TOKEN_TOKEN_TYPE, tokenJson.getString(TOKEN_TOKEN_TYPE)); 
+            resultTokenMap.put(TOKEN_EXPIRES_IN, tokenJson.getString(TOKEN_EXPIRES_IN)); 
+            resultTokenMap.put(TOKEN_REFRESH_TOKEN, tokenJson.getString(TOKEN_REFRESH_TOKEN));             
+        } catch (JSONException e) {
+            Log.e(TAG, "parseResult: Exception converting to Json " + e.toString());
+        }    
+        return resultTokenMap;      
+    }
+
+    /**
+     * Returns obtained values with a broadcast.
+     * 
+     * @param tokenResponse : obtained values.
+     */
+    private void postResult(HashMap<String, String> tokenResponse) {
+        Intent intent = new Intent(TOKEN_RECEIVED_MESSAGE);       
+        intent.putExtra(TOKEN_RECEIVED_DATA,tokenResponse);
+        sendBroadcast(intent);
+        shutdownService();
+    }
+}