Merge remote-tracking branch 'origin/oauth_login' into oauth_login
[pub/Android/ownCloud.git] / src / com / owncloud / android / authenticator / oauth2 / services / OAuth2GetTokenService.java
1 package com.owncloud.android.authenticator.oauth2.services;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.List;
6 import java.util.Timer;
7 import java.util.TimerTask;
8
9 import org.apache.http.NameValuePair;
10 import org.apache.http.client.entity.UrlEncodedFormEntity;
11 import org.apache.http.message.BasicNameValuePair;
12 import org.json.JSONException;
13 import org.json.JSONObject;
14
15 import android.app.Service;
16 import android.content.Intent;
17 import android.os.Bundle;
18 import android.os.IBinder;
19 import android.util.Log;
20
21 import com.owncloud.android.authenticator.oauth2.OAuth2Context;
22 import com.owncloud.android.authenticator.oauth2.connection.ConnectorOAuth2;
23
24 /**
25 * Service class that implements the second communication with the oAuth2 server:
26 * pooling for the token in an interval. It send a broadcast with the results when are positive;
27 * otherwise, it continues asking to the server.
28 *
29 * @author Solid Gear S.L.
30 *
31 */
32 public class OAuth2GetTokenService extends Service {
33
34 public static final String TOKEN_RECEIVED_MESSAGE = "TOKEN_RECEIVED";
35 public static final String TOKEN_RECEIVED_DATA = "TOKEN_DATA";
36 public static final String TOKEN_URI = "TOKEN_URI";
37 public static final String TOKEN_DEVICE_CODE = "device_code";
38 public static final String TOKEN_INTERVAL = "interval";
39 public static final String TOKEN_RECEIVED_ERROR = "error";
40 public static final String TOKEN_RECEIVED_ERROR_AUTH_TOKEN = "authorization_pending";
41 public static final String TOKEN_RECEIVED_ERROR_SLOW_DOWN = "slow_down";
42 public static final String TOKEN_ACCESS_TOKEN = "access_token";
43 public static final String TOKEN_TOKEN_TYPE = "token_type";
44 public static final String TOKEN_EXPIRES_IN = "expires_in";
45 public static final String TOKEN_REFRESH_TOKEN = "refresh_token";
46
47 private String requestDeviceCode;
48 private int requestInterval = -1;
49 private String requestBaseURI;
50 private ConnectorOAuth2 connectorOAuth2;
51 private static final String TAG = "OAuth2GetTokenService";
52 private Timer timer = new Timer();
53
54 @Override
55 public IBinder onBind(Intent arg0) {
56 return null;
57 }
58
59 @Override
60 public int onStartCommand(Intent intent, int flags, int startId) {
61 Bundle param = intent.getExtras();
62
63 if (param != null) {
64 String mUrl = param.getString(TOKEN_URI);
65 if (!mUrl.startsWith("http://") || !mUrl.startsWith("https://")) {
66 requestBaseURI = "https://" + mUrl;
67 }
68 requestDeviceCode = param.getString(TOKEN_DEVICE_CODE);
69 requestInterval = param.getInt(TOKEN_INTERVAL);
70
71 Log.d(TAG, "onStartCommand -> requestDeviceCode=" + requestDeviceCode);
72 Log.d(TAG, "onStartCommand -> requestInterval=" + requestInterval);
73 } else {
74 Log.e(TAG, "onStartCommand -> params could not be null");
75 }
76 startService();
77 return Service.START_NOT_STICKY;
78 }
79
80 @Override
81 public void onCreate() {
82 super.onCreate();
83 }
84
85 @Override
86 public void onDestroy() {
87 super.onDestroy();
88 shutdownService();
89 }
90
91 private void startService() {
92 final UrlEncodedFormEntity params = prepareComm();
93 timer.scheduleAtFixedRate(
94 new TimerTask() {
95 public void run() {
96 requestToken(params);
97 }
98 }, 0, requestInterval * 1000);
99 Log.d(TAG, "startService -> Timer started");
100 }
101
102 private void shutdownService() {
103 if (timer != null) timer.cancel();
104 Log.d(TAG, "shutdownService -> Timer stopped");
105 }
106
107
108 private UrlEncodedFormEntity prepareComm() {
109
110 UrlEncodedFormEntity params = null;
111 connectorOAuth2 = new ConnectorOAuth2();
112
113 if (requestBaseURI == null || requestBaseURI.trim().equals("")) {
114 Log.e(TAG, "run -> request URI could not be null");
115 postResult(null);
116 }
117
118 if (requestInterval == -1) {
119 Log.e(TAG, "run -> request Interval must have valid positive value");
120 postResult(null);
121 }
122
123 if (requestDeviceCode == null || requestDeviceCode.trim().equals("")) {
124 Log.e(TAG, "run -> request DeviceCode could not be null");
125 postResult(null);
126 }
127
128 try{
129 connectorOAuth2.setConnectorOAuth2Url(requestBaseURI + OAuth2Context.OAUTH2_G_DEVICE_GETTOKEN_URL);
130
131 List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
132 nameValuePairs.add(new BasicNameValuePair("client_id", OAuth2Context.OAUTH2_G_DEVICE_CLIENT_ID));
133 nameValuePairs.add(new BasicNameValuePair("client_secret", OAuth2Context.OAUTH2_G_DEVICE_CLIENT_SECRET));
134 nameValuePairs.add(new BasicNameValuePair("code",requestDeviceCode));
135 nameValuePairs.add(new BasicNameValuePair("grant_type",OAuth2Context.OAUTH_G_DEVICE_GETTOKEN_GRANT_TYPE));
136
137 params = new UrlEncodedFormEntity(nameValuePairs);
138 }
139 catch (Exception ex1){
140 Log.w(TAG, ex1.toString());
141 postResult(null);
142 }
143
144 return params;
145 }
146
147 protected void requestToken(UrlEncodedFormEntity params){
148 JSONObject tokenJson = null;
149 String error = null;
150 HashMap<String, String> resultTokenMap;
151
152 String tokenResponse = connectorOAuth2.connPost(params);
153
154 try {
155 tokenJson = new JSONObject(tokenResponse);
156 } catch (JSONException e) {
157 Log.e(TAG, "Exception converting to Json " + e.toString());
158 }
159
160 try {
161 // We try to get error string.
162 if (tokenJson.has(TOKEN_RECEIVED_ERROR)) {
163 error = tokenJson.getString(TOKEN_RECEIVED_ERROR);
164 Log.d(TAG, "requestToken -> Obtained error "+ error);
165 } else {
166 //We have got the token. Parse the answer.
167 resultTokenMap = parseResult(tokenJson);
168 postResult(resultTokenMap);
169 }
170 } catch (JSONException e) {
171 Log.e(TAG, "Exception converting to Json " + e.toString());
172 }
173 }
174
175 private HashMap<String, String> parseResult (JSONObject tokenJson) {
176 HashMap<String, String> resultTokenMap=new HashMap<String, String>();
177
178 try {
179 resultTokenMap.put(TOKEN_ACCESS_TOKEN, tokenJson.getString(TOKEN_ACCESS_TOKEN));
180 resultTokenMap.put(TOKEN_TOKEN_TYPE, tokenJson.getString(TOKEN_TOKEN_TYPE));
181 resultTokenMap.put(TOKEN_EXPIRES_IN, tokenJson.getString(TOKEN_EXPIRES_IN));
182 resultTokenMap.put(TOKEN_REFRESH_TOKEN, tokenJson.getString(TOKEN_REFRESH_TOKEN));
183 } catch (JSONException e) {
184 Log.e(TAG, "parseResult: Exception converting to Json " + e.toString());
185 }
186 return resultTokenMap;
187 }
188
189 /**
190 * Returns obtained values with a broadcast.
191 *
192 * @param tokenResponse : obtained values.
193 */
194 private void postResult(HashMap<String, String> tokenResponse) {
195 Intent intent = new Intent(TOKEN_RECEIVED_MESSAGE);
196 intent.putExtra(TOKEN_RECEIVED_DATA,tokenResponse);
197 sendBroadcast(intent);
198 shutdownService();
199 }
200 }