Login page updated to get OAuth2 access token
[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_BASE_URI = "baseURI";
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_BASE_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, "onBind -> baseURI=" + requestBaseURI);
72 Log.d(TAG, "onBind -> requestDeviceCode=" + requestDeviceCode);
73 Log.d(TAG, "onBind -> requestInterval=" + requestInterval);
74 } else {
75 Log.e(TAG, "onBind -> params could not be null");
76 }
77 startService();
78 return Service.START_NOT_STICKY;
79 }
80
81 @Override
82 public void onCreate() {
83 super.onCreate();
84 }
85
86 @Override
87 public void onDestroy() {
88 super.onDestroy();
89 shutdownService();
90 }
91
92 private void startService() {
93 final UrlEncodedFormEntity params = prepareComm();
94 timer.scheduleAtFixedRate(
95 new TimerTask() {
96 public void run() {
97 requestToken(params);
98 }
99 }, 0, requestInterval * 1000);
100 Log.d(TAG, "startService -> Timer started");
101 }
102
103 private void shutdownService() {
104 if (timer != null) timer.cancel();
105 Log.d(TAG, "shutdownService -> Timer stopped");
106 }
107
108
109 private UrlEncodedFormEntity prepareComm() {
110
111 UrlEncodedFormEntity params = null;
112 connectorOAuth2 = new ConnectorOAuth2();
113
114 if (requestBaseURI == null || requestBaseURI.trim().equals("")) {
115 Log.e(TAG, "run -> request URI could not be null");
116 postResult(null);
117 }
118
119 if (requestInterval == -1) {
120 Log.e(TAG, "run -> request Interval must have valid positive value");
121 postResult(null);
122 }
123
124 if (requestDeviceCode == null || requestDeviceCode.trim().equals("")) {
125 Log.e(TAG, "run -> request DeviceCode could not be null");
126 postResult(null);
127 }
128
129 try{
130 connectorOAuth2.setConnectorOAuth2Url(requestBaseURI + OAuth2Context.OAUTH2_DEVICE_GETTOKEN_URL);
131
132 List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
133 nameValuePairs.add(new BasicNameValuePair("client_id", OAuth2Context.OAUTH2_DEVICE_CLIENT_ID));
134 nameValuePairs.add(new BasicNameValuePair("client_secret", OAuth2Context.OAUTH2_DEVICE_CLIENT_SECRET));
135 nameValuePairs.add(new BasicNameValuePair("code",requestDeviceCode));
136 nameValuePairs.add(new BasicNameValuePair("grant_type",OAuth2Context.OAUTH_DEVICE_GETTOKEN_GRANT_TYPE));
137
138 params = new UrlEncodedFormEntity(nameValuePairs);
139 }
140 catch (Exception ex1){
141 Log.w(TAG, ex1.toString());
142 postResult(null);
143 }
144
145 return params;
146 }
147
148 protected void requestToken(UrlEncodedFormEntity params){
149 JSONObject tokenJson = null;
150 String error = null;
151 HashMap<String, String> resultTokenMap;
152
153 String tokenResponse = connectorOAuth2.connPost(params);
154
155 try {
156 tokenJson = new JSONObject(tokenResponse);
157 } catch (JSONException e) {
158 Log.e(TAG, "Exception converting to Json " + e.toString());
159 }
160
161 try {
162 // We try to get error string.
163 if (tokenJson.has(TOKEN_RECEIVED_ERROR)) {
164 error = tokenJson.getString(TOKEN_RECEIVED_ERROR);
165 Log.d(TAG, "requestToken -> Obtained error "+ error);
166 } else {
167 //We have got the token. Parse the answer.
168 resultTokenMap = parseResult(tokenJson);
169 postResult(resultTokenMap);
170 }
171 } catch (JSONException e) {
172 Log.e(TAG, "Exception converting to Json " + e.toString());
173 }
174 }
175
176 private HashMap<String, String> parseResult (JSONObject tokenJson) {
177 HashMap<String, String> resultTokenMap=new HashMap<String, String>();
178
179 try {
180 resultTokenMap.put(TOKEN_ACCESS_TOKEN, tokenJson.getString(TOKEN_ACCESS_TOKEN));
181 resultTokenMap.put(TOKEN_TOKEN_TYPE, tokenJson.getString(TOKEN_TOKEN_TYPE));
182 resultTokenMap.put(TOKEN_EXPIRES_IN, tokenJson.getString(TOKEN_EXPIRES_IN));
183 resultTokenMap.put(TOKEN_REFRESH_TOKEN, tokenJson.getString(TOKEN_REFRESH_TOKEN));
184 } catch (JSONException e) {
185 Log.e(TAG, "parseResult: Exception converting to Json " + e.toString());
186 }
187 return resultTokenMap;
188 }
189
190 /**
191 * Returns obtained values with a broadcast.
192 *
193 * @param tokenResponse : obtained values.
194 */
195 private void postResult(HashMap<String, String> tokenResponse) {
196 Intent intent = new Intent(TOKEN_RECEIVED_MESSAGE);
197 intent.putExtra(TOKEN_RECEIVED_DATA,tokenResponse);
198 sendBroadcast(intent);
199 shutdownService();
200 }
201 }