From: David A. Velasco Date: Tue, 18 Dec 2012 10:07:05 +0000 (+0100) Subject: Adding support to OAuth2 'authorization code' grant type [WIP] X-Git-Tag: oc-android-1.4.3~29^2~26 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/5be4bf17e11bfae134f24bbc8501b618304467b4?hp=--cc Adding support to OAuth2 'authorization code' grant type [WIP] --- 5be4bf17e11bfae134f24bbc8501b618304467b4 diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 79397e17..eb8ad28e 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -120,7 +120,16 @@ + android:theme="@style/Theme.ownCloud.noActionBar" + android:launchMode="singleTask"> + + + + + + + + diff --git a/src/com/owncloud/android/authenticator/AccountAuthenticator.java b/src/com/owncloud/android/authenticator/AccountAuthenticator.java index 58919ec2..25142496 100644 --- a/src/com/owncloud/android/authenticator/AccountAuthenticator.java +++ b/src/com/owncloud/android/authenticator/AccountAuthenticator.java @@ -204,8 +204,8 @@ public class AccountAuthenticator extends AbstractAccountAuthenticator { private void setIntentFlags(Intent intent) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); - intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + //intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + //intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); // incompatible with the authorization code grant in OAuth intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); intent.addFlags(Intent.FLAG_FROM_BACKGROUND); } diff --git a/src/com/owncloud/android/authenticator/oauth2/OAuth2Context.java b/src/com/owncloud/android/authenticator/oauth2/OAuth2Context.java index 03189fe2..fbc509d9 100644 --- a/src/com/owncloud/android/authenticator/oauth2/OAuth2Context.java +++ b/src/com/owncloud/android/authenticator/oauth2/OAuth2Context.java @@ -11,10 +11,35 @@ package com.owncloud.android.authenticator.oauth2; public class OAuth2Context { - public static final String OAUTH2_DEVICE_CLIENT_ID = "0000000000000.apps.googleusercontent.com"; - public static final String OAUTH2_DEVICE_CLIENT_SECRET = "XXXXXXXXXXXXXXXXXXXXXXXXX"; - public static final String OAUTH_DEVICE_GETTOKEN_GRANT_TYPE = "http://oauth.net/grant_type/device/1.0"; - public static final String OAUTH2_DEVICE_GETCODE_URL = "/o/oauth2/device/code"; - public static final String OAUTH2_DEVICE_GETTOKEN_URL = "/o/oauth2/token"; - public static final String OAUTH2_DEVICE_GETCODE_SCOPES = "https://www.googleapis.com/auth/userinfo.email"; + public static final String OAUTH2_G_DEVICE_CLIENT_ID = "1044165972576.apps.googleusercontent.com"; + public static final String OAUTH2_G_DEVICE_CLIENT_SECRET = "rwrA86fnIRCC3bZm0tWnKOkV"; + public static final String OAUTH_G_DEVICE_GETTOKEN_GRANT_TYPE = "http://oauth.net/grant_type/device/1.0"; + public static final String OAUTH2_G_DEVICE_GETCODE_URL = "https://accounts.google.com/o/oauth2/device/code"; + public static final String OAUTH2_G_DEVICE_GETTOKEN_URL = "https://accounts.google.com/o/oauth2/token"; + public static final String OAUTH2_G_DEVICE_GETCODE_SCOPES = "https://www.googleapis.com/auth/userinfo.email"; + + public static final String OAUTH2_F_AUTHORIZATION_ENDPOINT_URL = "https://frko.surfnetlabs.nl/workshop/php-oauth/authorize.php"; + public static final String OAUTH2_F_TOKEN_ENDPOINT_URL = "https://frko.surfnetlabs.nl/workshop/php-oauth/token.php"; + public static final String OAUTH2_F_CLIENT_ID = "oc-android-test"; + public static final String OAUTH2_F_SCOPE = "grades"; + + public static final String OAUTH2_AUTH_CODE_GRANT_TYPE = "authorization_code"; + public static final String OAUTH2_CODE_RESPONSE_TYPE = "code"; + + public static final String OAUTH2_TOKEN_RECEIVED_ERROR = "error"; + + public static final String MY_REDIRECT_URI = "oauth-mobile-app://callback"; // THIS CAN'T BE READ DYNAMICALLY; MUST BE DEFINED IN INSTALLATION TIME + + public static final String KEY_ACCESS_TOKEN = "access_token"; + public static final String KEY_TOKEN_TYPE = "token_type"; + public static final String KEY_EXPIRES_IN = "expires_in"; + public static final String KEY_REFRESH_TOKEN = "refresh_token"; + public static final String KEY_SCOPE = "scope"; + public static final String KEY_ERROR = "error"; + public static final String KEY_ERROR_DESCRIPTION = "error_description"; + public static final String KEY_ERROR_URI = "error_uri"; + public static final String KEY_REDIRECT_URI = "redirect_uri"; + public static final String KEY_GRANT_TYPE = "grant_type"; + public static final String KEY_CODE = "code"; + public static final String KEY_CLIENT_ID = "client_id"; } diff --git a/src/com/owncloud/android/authenticator/oauth2/OAuth2GetCodeRunnable.java b/src/com/owncloud/android/authenticator/oauth2/OAuth2GetCodeRunnable.java index a4a563c5..62085b2d 100644 --- a/src/com/owncloud/android/authenticator/oauth2/OAuth2GetCodeRunnable.java +++ b/src/com/owncloud/android/authenticator/oauth2/OAuth2GetCodeRunnable.java @@ -11,7 +11,9 @@ import org.json.JSONException; import org.json.JSONObject; import android.content.Context; +import android.content.Intent; import android.net.ConnectivityManager; +import android.net.Uri; import android.os.Handler; import android.util.Log; @@ -28,17 +30,25 @@ public class OAuth2GetCodeRunnable implements Runnable { public static final String CODE_USER_CODE = "user_code"; public static final String CODE_CLIENT_ID = "client_id"; - public static final String CODE_CLIENT_SCOPE = "scope"; + public static final String CODE_SCOPE = "scope"; public static final String CODE_VERIFICATION_URL = "verification_url"; public static final String CODE_EXPIRES_IN = "expires_in"; public static final String CODE_DEVICE_CODE = "device_code"; public static final String CODE_INTERVAL = "interval"; + private static final String CODE_RESPONSE_TYPE = "response_type"; + private static final String CODE_REDIRECT_URI = "redirect_uri"; + + private String mGrantType = OAuth2Context.OAUTH2_AUTH_CODE_GRANT_TYPE; + private static final String TAG = "OAuth2GetCodeRunnable"; private OnOAuth2GetCodeResultListener mListener; private String mUrl; private Handler mHandler; private Context mContext; + private JSONObject codeResponseJson = null; + ResultOAuthType mLatestResult; + public void setListener(OnOAuth2GetCodeResultListener listener, Handler handler) { mListener = listener; @@ -54,9 +64,6 @@ public class OAuth2GetCodeRunnable implements Runnable { @Override public void run() { - ResultOAuthType mLatestResult; - String targetURI = null; - JSONObject codeResponseJson = null; if (!isOnline()) { postResult(ResultOAuthType.NO_NETWORK_CONNECTION,null); @@ -69,14 +76,41 @@ public class OAuth2GetCodeRunnable implements Runnable { mUrl = "https://" + mUrl; mLatestResult = ResultOAuthType.OK_SSL; } - targetURI = mUrl + OAuth2Context.OAUTH2_DEVICE_GETCODE_URL; - ConnectorOAuth2 connectorOAuth2 = new ConnectorOAuth2(targetURI); + if (mGrantType.equals(OAuth2Context.OAUTH2_AUTH_CODE_GRANT_TYPE)) { + requestBrowserToGetAuthorizationCode(); + + } else if (mGrantType.equals(OAuth2Context.OAUTH_G_DEVICE_GETTOKEN_GRANT_TYPE)) { + getAuthorizationCode(); + } + } + + /// open the authorization endpoint in a web browser! + private void requestBrowserToGetAuthorizationCode() { + Uri uri = Uri.parse(mUrl); + Uri.Builder uriBuilder = uri.buildUpon(); + uriBuilder.appendQueryParameter(CODE_RESPONSE_TYPE, OAuth2Context.OAUTH2_CODE_RESPONSE_TYPE); + uriBuilder.appendQueryParameter(CODE_REDIRECT_URI, OAuth2Context.MY_REDIRECT_URI); + uriBuilder.appendQueryParameter(CODE_CLIENT_ID, OAuth2Context.OAUTH2_F_CLIENT_ID); + uriBuilder.appendQueryParameter(CODE_SCOPE, OAuth2Context.OAUTH2_F_SCOPE); + //uriBuilder.appendQueryParameter(CODE_STATE, whateverwewant); + + uri = uriBuilder.build(); + Log.d(TAG, "Starting browser to view " + uri.toString()); + + Intent i = new Intent(Intent.ACTION_VIEW, uri); + mContext.startActivity(i); + + postResult(mLatestResult, null); + } + + private void getAuthorizationCode() { + ConnectorOAuth2 connectorOAuth2 = new ConnectorOAuth2(mUrl); try { List nameValuePairs = new ArrayList(2); - nameValuePairs.add(new BasicNameValuePair(CODE_CLIENT_ID, OAuth2Context.OAUTH2_DEVICE_CLIENT_ID)); - nameValuePairs.add(new BasicNameValuePair(CODE_CLIENT_SCOPE,OAuth2Context.OAUTH2_DEVICE_GETCODE_SCOPES)); + nameValuePairs.add(new BasicNameValuePair(CODE_CLIENT_ID, OAuth2Context.OAUTH2_G_DEVICE_CLIENT_ID)); + nameValuePairs.add(new BasicNameValuePair(CODE_SCOPE,OAuth2Context.OAUTH2_G_DEVICE_GETCODE_SCOPES)); UrlEncodedFormEntity params = new UrlEncodedFormEntity(nameValuePairs); codeResponseJson = new JSONObject(connectorOAuth2.connPost(params)); } catch (JSONException e) { @@ -90,10 +124,10 @@ public class OAuth2GetCodeRunnable implements Runnable { if (codeResponseJson == null) { mLatestResult = ResultOAuthType.HOST_NOT_AVAILABLE; } - postResult(mLatestResult, codeResponseJson); } + private boolean isOnline() { ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); return cm != null && cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnectedOrConnecting(); diff --git a/src/com/owncloud/android/authenticator/oauth2/services/OAuth2GetTokenService.java b/src/com/owncloud/android/authenticator/oauth2/services/OAuth2GetTokenService.java index 584b20bd..7bfbbfa4 100644 --- a/src/com/owncloud/android/authenticator/oauth2/services/OAuth2GetTokenService.java +++ b/src/com/owncloud/android/authenticator/oauth2/services/OAuth2GetTokenService.java @@ -33,7 +33,7 @@ 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_URI = "TOKEN_URI"; public static final String TOKEN_DEVICE_CODE = "device_code"; public static final String TOKEN_INTERVAL = "interval"; public static final String TOKEN_RECEIVED_ERROR = "error"; @@ -61,18 +61,17 @@ public class OAuth2GetTokenService extends Service { Bundle param = intent.getExtras(); if (param != null) { - String mUrl = param.getString(TOKEN_BASE_URI); + String mUrl = param.getString(TOKEN_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); + Log.d(TAG, "onStartCommand -> requestDeviceCode=" + requestDeviceCode); + Log.d(TAG, "onStartCommand -> requestInterval=" + requestInterval); } else { - Log.e(TAG, "onBind -> params could not be null"); + Log.e(TAG, "onStartCommand -> params could not be null"); } startService(); return Service.START_NOT_STICKY; @@ -127,13 +126,13 @@ public class OAuth2GetTokenService extends Service { } try{ - connectorOAuth2.setConnectorOAuth2Url(requestBaseURI + OAuth2Context.OAUTH2_DEVICE_GETTOKEN_URL); + connectorOAuth2.setConnectorOAuth2Url(requestBaseURI + OAuth2Context.OAUTH2_G_DEVICE_GETTOKEN_URL); List nameValuePairs = new ArrayList(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("client_id", OAuth2Context.OAUTH2_G_DEVICE_CLIENT_ID)); + nameValuePairs.add(new BasicNameValuePair("client_secret", OAuth2Context.OAUTH2_G_DEVICE_CLIENT_SECRET)); nameValuePairs.add(new BasicNameValuePair("code",requestDeviceCode)); - nameValuePairs.add(new BasicNameValuePair("grant_type",OAuth2Context.OAUTH_DEVICE_GETTOKEN_GRANT_TYPE)); + nameValuePairs.add(new BasicNameValuePair("grant_type",OAuth2Context.OAUTH_G_DEVICE_GETTOKEN_GRANT_TYPE)); params = new UrlEncodedFormEntity(nameValuePairs); } diff --git a/src/com/owncloud/android/network/OwnCloudClientUtils.java b/src/com/owncloud/android/network/OwnCloudClientUtils.java index 5cc7a9fb..02e29851 100644 --- a/src/com/owncloud/android/network/OwnCloudClientUtils.java +++ b/src/com/owncloud/android/network/OwnCloudClientUtils.java @@ -22,6 +22,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.net.URL; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.KeyStoreException; @@ -38,6 +39,7 @@ import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier; import org.apache.http.conn.ssl.X509HostnameVerifier; import com.owncloud.android.AccountUtils; +import com.owncloud.android.authenticator.AccountAuthenticator; import eu.alefzero.webdav.WebdavClient; @@ -75,16 +77,22 @@ public class OwnCloudClientUtils { * @return A WebdavClient object ready to be used */ public static WebdavClient createOwnCloudClient (Account account, Context context) { - Log.d(TAG, "Creating WebdavClient associated to " + account.name); + //Log.d(TAG, "Creating WebdavClient associated to " + account.name); Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(context, account)); WebdavClient client = createOwnCloudClient(uri, context); String username = account.name.substring(0, account.name.lastIndexOf('@')); - String password = AccountManager.get(context).getPassword(account); - //String password = am.blockingGetAuthToken(mAccount, AccountAuthenticator.AUTH_TOKEN_TYPE, true); + /*if (ama.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2)) { + // TODO - this is a trap; the OAuth access token shouldn't be saved as the account password + String accessToken = AccountManager.get(context).getPassword(account); + client.setCredentials("bearer", accessToken); - client.setCredentials(username, password); + } else {*/ + String password = AccountManager.get(context).getPassword(account); + //String password = am.blockingGetAuthToken(mAccount, AccountAuthenticator.AUTH_TOKEN_TYPE, true); + client.setCredentials(username, password); + //} return client; } @@ -100,7 +108,7 @@ public class OwnCloudClientUtils { * @return A WebdavClient object ready to be used */ public static WebdavClient createOwnCloudClient(Uri uri, String username, String password, Context context) { - Log.d(TAG, "Creating WebdavClient for " + username + "@" + uri); + //Log.d(TAG, "Creating WebdavClient for " + username + "@" + uri); WebdavClient client = createOwnCloudClient(uri, context); @@ -118,7 +126,7 @@ public class OwnCloudClientUtils { * @return A WebdavClient object ready to be used */ public static WebdavClient createOwnCloudClient(Uri uri, Context context) { - Log.d(TAG, "Creating WebdavClient for " + uri); + //Log.d(TAG, "Creating WebdavClient for " + uri); //allowSelfsignedCertificates(true); try { @@ -270,4 +278,5 @@ public class OwnCloudClientUtils { return mConnManager; } + } diff --git a/src/com/owncloud/android/operations/ExistenceCheckOperation.java b/src/com/owncloud/android/operations/ExistenceCheckOperation.java new file mode 100644 index 00000000..506636f7 --- /dev/null +++ b/src/com/owncloud/android/operations/ExistenceCheckOperation.java @@ -0,0 +1,109 @@ +/* ownCloud Android client application + * Copyright (C) 2012 ownCloud Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.owncloud.android.operations; + +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.methods.HeadMethod; + +import eu.alefzero.webdav.WebdavClient; +import android.content.Context; +import android.net.ConnectivityManager; +import android.util.Log; + +/** + * Operation to check the existence or absence of a path in a remote server. + * + * @author David A. Velasco + */ +public class ExistenceCheckOperation extends RemoteOperation { + + /** Maximum time to wait for a response from the server in MILLISECONDs. */ + public static final int TIMEOUT = 10000; + + private static final String TAG = ExistenceCheckOperation.class.getSimpleName(); + + private String mPath; + private Context mContext; + private boolean mSuccessIfAbsent; + private String mAccessToken; + + + /** + * Simple constructor. Success when the path in the server exists. + * + * @param path Path to append to the URL owned by the client instance. + * @param context Android application context. + * @param accessToken Access token for Bearer Authentication -> TODO: move to other place + */ + public ExistenceCheckOperation(String path, Context context, String accessToken) { + this(path, context, false); + mAccessToken = accessToken; + } + + + /** + * Full constructor. Success of the operation will depend upon the value of successIfAbsent. + * + * @param path Path to append to the URL owned by the client instance. + * @param context Android application context. + * @param successIfAbsent When 'true', the operation finishes in success if the path does NOT exist in the remote server (HTTP 404). + */ + public ExistenceCheckOperation(String path, Context context, boolean successIfAbsent) { + mPath = (path != null) ? path : ""; + mContext = context; + mSuccessIfAbsent = successIfAbsent; + } + + + @Override + protected RemoteOperationResult run(WebdavClient client) { + if (!isOnline()) { + return new RemoteOperationResult(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION); + } + RemoteOperationResult result = null; + HeadMethod head = null; + try { + head = new HeadMethod(client.getBaseUri() + mPath); + head.addRequestHeader("Authorization", "Bearer " + mAccessToken); // TODO put in some general place + + int status = client.executeMethod(head, TIMEOUT, TIMEOUT); + client.exhaustResponse(head.getResponseBodyAsStream()); + boolean success = (status == HttpStatus.SC_OK && !mSuccessIfAbsent) || (status == HttpStatus.SC_NOT_FOUND && mSuccessIfAbsent); + result = new RemoteOperationResult(success, status); + Log.d(TAG, "Existence check for " + client.getBaseUri() + mPath + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + "finished with HTTP status " + status + (!success?"(FAIL)":"")); + + } catch (Exception e) { + result = new RemoteOperationResult(e); + Log.e(TAG, "Existence check for " + client.getBaseUri() + mPath + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + ": " + result.getLogMessage(), result.getException()); + + } finally { + if (head != null) + head.releaseConnection(); + } + return result; + } + + private boolean isOnline() { + ConnectivityManager cm = (ConnectivityManager) mContext + .getSystemService(Context.CONNECTIVITY_SERVICE); + return cm != null && cm.getActiveNetworkInfo() != null + && cm.getActiveNetworkInfo().isConnectedOrConnecting(); + } + +} diff --git a/src/com/owncloud/android/operations/GetOAuth2AccessToken.java b/src/com/owncloud/android/operations/GetOAuth2AccessToken.java new file mode 100644 index 00000000..82de8441 --- /dev/null +++ b/src/com/owncloud/android/operations/GetOAuth2AccessToken.java @@ -0,0 +1,125 @@ +package com.owncloud.android.operations; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.NameValuePair; +import org.json.JSONException; +import org.json.JSONObject; + +import com.owncloud.android.authenticator.oauth2.OAuth2Context; +import com.owncloud.android.operations.RemoteOperationResult.ResultCode; + +import android.util.Log; + +import eu.alefzero.webdav.WebdavClient; + +public class GetOAuth2AccessToken extends RemoteOperation { + + private static final String TAG = GetOAuth2AccessToken.class.getSimpleName(); + + private Map mOAuth2AuthorizationResponse; + private Map mResultTokenMap; + + + public GetOAuth2AccessToken(Map oAuth2AuthorizationResponse) { + mOAuth2AuthorizationResponse = oAuth2AuthorizationResponse; + mResultTokenMap = null; + } + + + public Map getOauth2AutorizationResponse() { + return mOAuth2AuthorizationResponse; + } + + public Map getResultTokenMap() { + return mResultTokenMap; + } + + @Override + protected RemoteOperationResult run(WebdavClient client) { + RemoteOperationResult result = null; + PostMethod postMethod = null; + + try { + NameValuePair[] nameValuePairs = new NameValuePair[5]; + nameValuePairs[0] = new NameValuePair(OAuth2Context.KEY_CLIENT_ID, OAuth2Context.OAUTH2_F_CLIENT_ID); + nameValuePairs[1] = new NameValuePair(OAuth2Context.KEY_CODE, mOAuth2AuthorizationResponse.get(OAuth2Context.KEY_CODE)); + nameValuePairs[2] = new NameValuePair(OAuth2Context.KEY_SCOPE, mOAuth2AuthorizationResponse.get(OAuth2Context.KEY_SCOPE)); + nameValuePairs[3] = new NameValuePair(OAuth2Context.KEY_REDIRECT_URI, OAuth2Context.MY_REDIRECT_URI); + nameValuePairs[4] = new NameValuePair(OAuth2Context.KEY_GRANT_TYPE, OAuth2Context.OAUTH2_AUTH_CODE_GRANT_TYPE); + + postMethod = new PostMethod(client.getBaseUri().toString()); + postMethod.setRequestBody(nameValuePairs); + int status = client.executeMethod(postMethod); + if (status >= 300) { + client.exhaustResponse(postMethod.getResponseBodyAsStream()); + result = new RemoteOperationResult(false, status); + + } else { + JSONObject tokenJson = new JSONObject(postMethod.getResponseBodyAsString()); + parseResult(tokenJson); + if (mResultTokenMap.get(OAuth2Context.OAUTH2_TOKEN_RECEIVED_ERROR) != null) { + result = new RemoteOperationResult(ResultCode.OAUTH2_ERROR); + + } else { + result = new RemoteOperationResult(true, status); + } + } + + } catch (Exception e) { + result = new RemoteOperationResult(e); + + } finally { + if (postMethod != null) + postMethod.releaseConnection(); // let the connection available for other methods + + if (result.isSuccess()) { + Log.i(TAG, "OAuth2 TOKEN REQUEST with code " + mOAuth2AuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage()); + + } else if (result.getException() != null) { + Log.e(TAG, "OAuth2 TOKEN REQUEST with code " + mOAuth2AuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage(), result.getException()); + + } else if (result.getCode() == ResultCode.OAUTH2_ERROR) { + Log.e(TAG, "OAuth2 TOKEN REQUEST with code " + mOAuth2AuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + mResultTokenMap.get(OAuth2Context.OAUTH2_TOKEN_RECEIVED_ERROR)); + + } else { + Log.e(TAG, "OAuth2 TOKEN REQUEST with code " + mOAuth2AuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage()); + } + } + + return result; + } + + + private void parseResult (JSONObject tokenJson) throws JSONException { + mResultTokenMap = new HashMap(); + + if (tokenJson.has(OAuth2Context.KEY_ACCESS_TOKEN)) { + mResultTokenMap.put(OAuth2Context.KEY_ACCESS_TOKEN, tokenJson.getString(OAuth2Context.KEY_ACCESS_TOKEN)); + } + if (tokenJson.has(OAuth2Context.KEY_TOKEN_TYPE)) { + mResultTokenMap.put(OAuth2Context.KEY_TOKEN_TYPE, tokenJson.getString(OAuth2Context.KEY_TOKEN_TYPE)); + } + if (tokenJson.has(OAuth2Context.KEY_EXPIRES_IN)) { + mResultTokenMap.put(OAuth2Context.KEY_EXPIRES_IN, tokenJson.getString(OAuth2Context.KEY_EXPIRES_IN)); + } + if (tokenJson.has(OAuth2Context.KEY_REFRESH_TOKEN)) { + mResultTokenMap.put(OAuth2Context.KEY_REFRESH_TOKEN, tokenJson.getString(OAuth2Context.KEY_REFRESH_TOKEN)); + } + if (tokenJson.has(OAuth2Context.KEY_SCOPE)) { + mResultTokenMap.put(OAuth2Context.KEY_SCOPE, tokenJson.getString(OAuth2Context.KEY_SCOPE)); + } + if (tokenJson.has(OAuth2Context.KEY_ERROR)) { + mResultTokenMap.put(OAuth2Context.KEY_ERROR, tokenJson.getString(OAuth2Context.KEY_ERROR)); + } + if (tokenJson.has(OAuth2Context.KEY_ERROR_DESCRIPTION)) { + mResultTokenMap.put(OAuth2Context.KEY_ERROR_DESCRIPTION, tokenJson.getString(OAuth2Context.KEY_ERROR_DESCRIPTION)); + } + if (tokenJson.has(OAuth2Context.KEY_ERROR_URI)) { + mResultTokenMap.put(OAuth2Context.KEY_ERROR_URI, tokenJson.getString(OAuth2Context.KEY_ERROR_URI)); + } + } + +} diff --git a/src/com/owncloud/android/operations/RemoteOperationResult.java b/src/com/owncloud/android/operations/RemoteOperationResult.java index d8fbe460..f56ac903 100644 --- a/src/com/owncloud/android/operations/RemoteOperationResult.java +++ b/src/com/owncloud/android/operations/RemoteOperationResult.java @@ -45,8 +45,8 @@ import com.owncloud.android.network.CertificateCombinedException; public class RemoteOperationResult implements Serializable { /** Generated - to refresh every time the class changes */ - private static final long serialVersionUID = -7805531062432602444L; - + private static final long serialVersionUID = 5336333154035462033L; + public enum ResultCode { OK, @@ -69,7 +69,8 @@ public class RemoteOperationResult implements Serializable { CANCELLED, INVALID_LOCAL_FILE_NAME, INVALID_OVERWRITE, - CONFLICT + CONFLICT, + OAUTH2_ERROR } private boolean mSuccess = false; diff --git a/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java b/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java index f3d60966..6704bdea 100644 --- a/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java +++ b/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java @@ -21,6 +21,7 @@ package com.owncloud.android.ui.activity; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; +import java.util.Map; import org.json.JSONException; import org.json.JSONObject; @@ -30,14 +31,18 @@ import com.owncloud.android.authenticator.AccountAuthenticator; import com.owncloud.android.authenticator.AuthenticationRunnable; import com.owncloud.android.authenticator.OnAuthenticationResultListener; import com.owncloud.android.authenticator.OnConnectCheckListener; +import com.owncloud.android.authenticator.oauth2.OAuth2Context; import com.owncloud.android.authenticator.oauth2.OAuth2GetCodeRunnable; import com.owncloud.android.authenticator.oauth2.OnOAuth2GetCodeResultListener; import com.owncloud.android.authenticator.oauth2.connection.ConnectorOAuth2; import com.owncloud.android.authenticator.oauth2.services.OAuth2GetTokenService; import com.owncloud.android.ui.dialog.SslValidatorDialog; import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener; +import com.owncloud.android.utils.OwnCloudVersion; import com.owncloud.android.network.OwnCloudClientUtils; import com.owncloud.android.operations.ConnectionCheckOperation; +import com.owncloud.android.operations.ExistenceCheckOperation; +import com.owncloud.android.operations.GetOAuth2AccessToken; import com.owncloud.android.operations.OnRemoteOperationListener; import com.owncloud.android.operations.RemoteOperation; import com.owncloud.android.operations.RemoteOperationResult; @@ -91,15 +96,17 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity private Thread mAuthThread; private AuthenticationRunnable mAuthRunnable; - //private ConnectionCheckerRunnable mConnChkRunnable = null; private ConnectionCheckOperation mConnChkRunnable; + private ExistenceCheckOperation mAuthChkOperation; private final Handler mHandler = new Handler(); private String mBaseUrl; + private OwnCloudVersion mDiscoveredVersion; private static final String STATUS_TEXT = "STATUS_TEXT"; private static final String STATUS_ICON = "STATUS_ICON"; private static final String STATUS_CORRECT = "STATUS_CORRECT"; private static final String IS_SSL_CONN = "IS_SSL_CONN"; + private static final String OC_VERSION = "OC_VERSION"; private int mStatusText, mStatusIcon; private boolean mStatusCorrect, mIsSslConn; private RemoteOperationResult mLastSslUntrustedServerResult; @@ -112,11 +119,9 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity private static final String OAUTH2_STATUS_TEXT = "OAUTH2_STATUS_TEXT"; private static final String OAUTH2_STATUS_ICON = "OAUTH2_STATUS_ICON"; private static final String OAUTH2_CODE_RESULT = "CODE_RESULT"; - private static final String OAUTH2_BASE_URL = "BASE_URL"; private static final String OAUTH2_IS_CHECKED = "OAUTH2_IS_CHECKED"; private Thread mOAuth2GetCodeThread; private OAuth2GetCodeRunnable mOAuth2GetCodeRunnable; - private String oAuth2BaseUrl; private TokenReceiver tokenReceiver; private JSONObject codeResponseJson; private int mOAuth2StatusText, mOAuth2StatusIcon; @@ -125,9 +130,11 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity // Variables used to save the on the state the contents of all fields. private static final String HOST_URL_TEXT = "HOST_URL_TEXT"; - private static final String OAUTH2_URL_TEXT = "OAUTH2_URL_TEXT"; private static final String ACCOUNT_USERNAME = "ACCOUNT_USERNAME"; private static final String ACCOUNT_PASSWORD = "ACCOUNT_PASSWORD"; + + //private boolean mNewRedirectUriCaptured; + private Uri mNewCapturedUriFromOAuth2Redirection; // END of oAuth2 variables. @@ -140,8 +147,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity ImageView iv2 = (ImageView) findViewById(R.id.viewPassword); TextView tv = (TextView) findViewById(R.id.host_URL); TextView tv2 = (TextView) findViewById(R.id.account_password); - // New textview to oAuth2 URL. - TextView tv3 = (TextView) findViewById(R.id.oAuth_URL); + EditText oauth2Url = (EditText)findViewById(R.id.oAuth_URL); + oauth2Url.setText("OWNCLOUD AUTHORIZATION PROVIDER IN TEST"); if (savedInstanceState != null) { mStatusIcon = savedInstanceState.getInt(STATUS_ICON); @@ -153,14 +160,17 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity if (!mStatusCorrect) iv.setVisibility(View.VISIBLE); else - iv.setVisibility(View.INVISIBLE); + iv.setVisibility(View.INVISIBLE); + + String ocVersion = savedInstanceState.getString(OC_VERSION, null); + if (ocVersion != null) + mDiscoveredVersion = new OwnCloudVersion(ocVersion); // Getting the state of oAuth2 components. mOAuth2StatusIcon = savedInstanceState.getInt(OAUTH2_STATUS_ICON); mOAuth2StatusText = savedInstanceState.getInt(OAUTH2_STATUS_TEXT); // We set this to true if the rotation happens when the user is validating oAuth2 user_code. changeViewByOAuth2Check(savedInstanceState.getBoolean(OAUTH2_IS_CHECKED)); - oAuth2BaseUrl = savedInstanceState.getString(OAUTH2_BASE_URL); // We store a JSon object with all the data returned from oAuth2 server when we get user_code. // Is better than store variable by variable. We use String object to serialize from/to it. try { @@ -175,8 +185,6 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity // Getting contents of each field. EditText hostUrl = (EditText)findViewById(R.id.host_URL); hostUrl.setText(savedInstanceState.getString(HOST_URL_TEXT), TextView.BufferType.EDITABLE); - EditText oauth2Url = (EditText)findViewById(R.id.oAuth_URL); - oauth2Url.setText(savedInstanceState.getString(OAUTH2_URL_TEXT), TextView.BufferType.EDITABLE); EditText accountUsername = (EditText)findViewById(R.id.account_username); accountUsername.setText(savedInstanceState.getString(ACCOUNT_USERNAME), TextView.BufferType.EDITABLE); EditText accountPassword = (EditText)findViewById(R.id.account_password); @@ -192,17 +200,32 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity iv2.setOnClickListener(this); tv.setOnFocusChangeListener(this); tv2.setOnFocusChangeListener(this); - // Setting the listener for oAuth2 URL TextView. - tv3.setOnFocusChangeListener(this); - super.onCreate(savedInstanceState); + mNewCapturedUriFromOAuth2Redirection = null; + + Log.d(TAG, "onCreate"); } + + @Override + protected void onNewIntent (Intent intent) { + Uri data = intent.getData(); + //mNewRedirectUriCaptured = (data != null && data.toString().startsWith(OAuth2Context.MY_REDIRECT_URI)); + if (data != null && data.toString().startsWith(OAuth2Context.MY_REDIRECT_URI)) { + mNewCapturedUriFromOAuth2Redirection = data; + } + Log.d(TAG, "onNewIntent()"); + + } + + @Override protected void onSaveInstanceState(Bundle outState) { outState.putInt(STATUS_ICON, mStatusIcon); outState.putInt(STATUS_TEXT, mStatusText); outState.putBoolean(STATUS_CORRECT, mStatusCorrect); + if (mDiscoveredVersion != null) + outState.putString(OC_VERSION, mDiscoveredVersion.toString()); // Saving the state of oAuth2 components. outState.putInt(OAUTH2_STATUS_ICON, mOAuth2StatusIcon); @@ -212,12 +235,10 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity if (codeResponseJson != null){ outState.putString(OAUTH2_CODE_RESULT, codeResponseJson.toString()); } - outState.putString(OAUTH2_BASE_URL, oAuth2BaseUrl); // END of saving the state of oAuth2 components. // Saving contents of each field. outState.putString(HOST_URL_TEXT,((TextView) findViewById(R.id.host_URL)).getText().toString().trim()); - outState.putString(OAUTH2_URL_TEXT,((TextView) findViewById(R.id.oAuth_URL)).getText().toString().trim()); outState.putString(ACCOUNT_USERNAME,((TextView) findViewById(R.id.account_username)).getText().toString().trim()); outState.putString(ACCOUNT_PASSWORD,((TextView) findViewById(R.id.account_password)).getText().toString().trim()); @@ -252,9 +273,13 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity case OAUTH2_LOGIN_PROGRESS: { ProgressDialog working_dialog = new ProgressDialog(this); try { - working_dialog.setMessage(String.format(getString(R.string.oauth_code_validation_message), - codeResponseJson.getString(OAuth2GetCodeRunnable.CODE_VERIFICATION_URL), - codeResponseJson.getString(OAuth2GetCodeRunnable.CODE_USER_CODE))); + if (codeResponseJson != null && codeResponseJson.has(OAuth2GetCodeRunnable.CODE_VERIFICATION_URL)) { + working_dialog.setMessage(String.format(getString(R.string.oauth_code_validation_message), + codeResponseJson.getString(OAuth2GetCodeRunnable.CODE_VERIFICATION_URL), + codeResponseJson.getString(OAuth2GetCodeRunnable.CODE_USER_CODE))); + } else { + working_dialog.setMessage(String.format("Getting authorization")); + } } catch (JSONException e) { Log.e(TAG, "onCreateDialog->JSONException: " + e.toString()); } @@ -307,6 +332,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity switch (id) { case DIALOG_LOGIN_PROGRESS: case DIALOG_CERT_NOT_SAVED: + case OAUTH2_LOGIN_PROGRESS: break; case DIALOG_SSL_VALIDATOR: { ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult); @@ -320,12 +346,19 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity @Override protected void onResume() { Log.d(TAG, "onResume() start"); - // Registering token receiver. We must listening to the service that is pooling to the oAuth server for a token. + // (old oauth code) Registering token receiver. We must listening to the service that is pooling to the oAuth server for a token. if (tokenReceiver == null) { IntentFilter tokenFilter = new IntentFilter(OAuth2GetTokenService.TOKEN_RECEIVED_MESSAGE); tokenReceiver = new TokenReceiver(); this.registerReceiver(tokenReceiver,tokenFilter); } + // (new oauth code) + /*if (mNewRedirectUriCaptured) { + mNewRedirectUriCaptured = false;*/ + if (mNewCapturedUriFromOAuth2Redirection != null) { + getOAuth2AccessTokenFromCapturedRedirection(); + + } super.onResume(); } @@ -382,8 +415,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity accManager.setUserData(account, AccountAuthenticator.KEY_OC_URL, url.toString()); accManager.setUserData(account, - AccountAuthenticator.KEY_OC_VERSION, mConnChkRunnable - .getDiscoveredVersion().toString()); + AccountAuthenticator.KEY_OC_VERSION, mDiscoveredVersion.toString()); accManager.setUserData(account, AccountAuthenticator.KEY_OC_BASE_URL, mBaseUrl); @@ -432,9 +464,25 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity || url.toLowerCase().startsWith("https://")) { prefix = ""; } - continueConnection(prefix); + CheckBox oAuth2Check = (CheckBox) findViewById(R.id.oauth_onOff_check); + if (oAuth2Check != null && oAuth2Check.isChecked()) { + startOauthorization(); + + } else { + continueConnection(prefix); + } } + private void startOauthorization() { + // We start a thread to get an authorization code from the oAuth2 server. + setOAuth2ResultIconAndText(R.drawable.progress_small, R.string.oauth_login_connection); + mOAuth2GetCodeRunnable = new OAuth2GetCodeRunnable(OAuth2Context.OAUTH2_F_AUTHORIZATION_ENDPOINT_URL, this); + //mOAuth2GetCodeRunnable = new OAuth2GetCodeRunnable(OAuth2Context.OAUTH2_G_DEVICE_GETCODE_URL, this); + mOAuth2GetCodeRunnable.setListener(this, mHandler); + mOAuth2GetCodeThread = new Thread(mOAuth2GetCodeRunnable); + mOAuth2GetCodeThread.start(); + } + public void onRegisterClick(View view) { Intent register = new Intent(Intent.ACTION_VIEW, Uri.parse("https://owncloud.com/mobile/new")); setResult(RESULT_CANCELED); @@ -452,8 +500,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity url = url.substring(0, url.length() - 1); URL uri = null; - String webdav_path = AccountUtils.getWebdavPath(mConnChkRunnable - .getDiscoveredVersion()); + mDiscoveredVersion = mConnChkRunnable.getDiscoveredVersion(); + String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion); if (webdav_path == null) { onAuthenticationResult(false, getString(R.string.auth_bad_oc_version_title)); @@ -567,11 +615,12 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity setResultIconAndText(R.drawable.progress_small, R.string.auth_testing_connection); //mConnChkRunnable = new ConnectionCheckerRunnable(uri, this); - mConnChkRunnable = new ConnectionCheckOperation(uri, this); + mConnChkRunnable = new ConnectionCheckOperation(uri, this); //mConnChkRunnable.setListener(this, mHandler); //mAuthThread = new Thread(mConnChkRunnable); //mAuthThread.start(); WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(uri), this); + mDiscoveredVersion = null; mAuthThread = mConnChkRunnable.execute(client, this, mHandler); } else { findViewById(R.id.refreshButton).setVisibility( @@ -593,28 +642,6 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity v.setInputType(input_type); iv.setVisibility(View.INVISIBLE); } - // If the focusChange occurs on the oAuth2 URL field, we do this. - } else if (view.getId() == R.id.oAuth_URL) { - if (!hasFocus) { - TextView tv3 = ((TextView) findViewById(R.id.oAuth_URL)); - // We get the URL of oAuth2 server. - oAuth2BaseUrl = tv3.getText().toString().trim(); - if (oAuth2BaseUrl.length() != 0) { - // We start a thread to get user_code from the oAuth2 server. - setOAuth2ResultIconAndText(R.drawable.progress_small, R.string.oauth_login_connection); - mOAuth2GetCodeRunnable = new OAuth2GetCodeRunnable(oAuth2BaseUrl, this); - mOAuth2GetCodeRunnable.setListener(this, mHandler); - mOAuth2GetCodeThread = new Thread(mOAuth2GetCodeRunnable); - mOAuth2GetCodeThread.start(); - } else { - findViewById(R.id.refreshButton).setVisibility( - View.INVISIBLE); - setOAuth2ResultIconAndText(0, 0); - } - } else { - // avoids that the 'connect' button can be clicked if the test was previously passed - findViewById(R.id.buttonOK).setEnabled(false); - } } } @@ -715,15 +742,18 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity public void onOAuth2GetCodeResult(ResultOAuthType type, JSONObject responseJson) { if ((type == ResultOAuthType.OK_SSL)||(type == ResultOAuthType.OK_NO_SSL)) { codeResponseJson = responseJson; - startOAuth2Authentication(); + if (codeResponseJson != null) { + getOAuth2AccessTokenFromJsonResponse(); + } // else - nothing to do here - wait for callback !!! + } else if (type == ResultOAuthType.HOST_NOT_AVAILABLE) { setOAuth2ResultIconAndText(R.drawable.common_error, R.string.oauth_connection_url_unavailable); } } // If the results of getting the user_code and verification_url are OK, we get the received data and we start - // the pooling service to oAuth2 server to get a valid token. - private void startOAuth2Authentication () { + // the polling service to oAuth2 server to get a valid token. + private void getOAuth2AccessTokenFromJsonResponse() { String deviceCode = null; String verificationUrl = null; String userCode = null; @@ -762,7 +792,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity // Starting the pooling service. try { Intent tokenService = new Intent(this, OAuth2GetTokenService.class); - tokenService.putExtra(OAuth2GetTokenService.TOKEN_BASE_URI, oAuth2BaseUrl); + tokenService.putExtra(OAuth2GetTokenService.TOKEN_URI, OAuth2Context.OAUTH2_G_DEVICE_GETTOKEN_URL); tokenService.putExtra(OAuth2GetTokenService.TOKEN_DEVICE_CODE, deviceCode); tokenService.putExtra(OAuth2GetTokenService.TOKEN_INTERVAL, interval); @@ -771,7 +801,61 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity catch (Exception e) { Log.e(TAG, "tokenService creation problem :", e); } + } + + private void getOAuth2AccessTokenFromCapturedRedirection() { + Map responseValues = new HashMap(); + //String queryParameters = getIntent().getData().getQuery(); + String queryParameters = mNewCapturedUriFromOAuth2Redirection.getQuery(); + mNewCapturedUriFromOAuth2Redirection = null; + + Log.v(TAG, "Queryparameters (Code) = " + queryParameters); + + String[] pairs = queryParameters.split("&"); + Log.v(TAG, "Pairs (Code) = " + pairs.toString()); + + int i = 0; + String key = ""; + String value = ""; + + StringBuilder sb = new StringBuilder(); + + while (pairs.length > i) { + int j = 0; + String[] part = pairs[i].split("="); + + while (part.length > j) { + String p = part[j]; + if (j == 0) { + key = p; + sb.append(key + " = "); + } else if (j == 1) { + value = p; + responseValues.put(key, value); + sb.append(value + "\n"); + } + + Log.v(TAG, "[" + i + "," + j + "] = " + p); + j++; + } + i++; + } + + + // Updating status widget to OK. + setOAuth2ResultIconAndText(R.drawable.ic_ok, R.string.auth_connection_established); + + // Showing the dialog with instructions for the user. + showDialog(OAUTH2_LOGIN_PROGRESS); + + // + RemoteOperation operation = new GetOAuth2AccessToken(responseValues); + WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(OAuth2Context.OAUTH2_F_TOKEN_ENDPOINT_URL), getApplicationContext()); + operation.execute(client, this, mHandler); + } + + // We get data from the oAuth2 token service with this broadcast receiver. private class TokenReceiver extends BroadcastReceiver { @@ -792,7 +876,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity @Override public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) { - if (operation.equals(mConnChkRunnable)) { + if (operation instanceof ConnectionCheckOperation) { mStatusText = mStatusIcon = 0; mStatusCorrect = false; @@ -880,6 +964,128 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity else findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE); findViewById(R.id.buttonOK).setEnabled(mStatusCorrect); + + } else if (operation instanceof GetOAuth2AccessToken) { + + try { + dismissDialog(OAUTH2_LOGIN_PROGRESS); + } catch (IllegalArgumentException e) { + // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens + } + + if (result.isSuccess()) { + + /// time to test the retrieved access token on the ownCloud server + String url = ((TextView) findViewById(R.id.host_URL)).getText() + .toString().trim(); + if (url.endsWith("/")) + url = url.substring(0, url.length() - 1); + + Uri uri = null; + /*String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion); + + if (webdav_path == null) { + onAuthenticationResult(false, getString(R.string.auth_bad_oc_version_title)); + return; + }*/ + + String prefix = ""; + if (mIsSslConn) { + prefix = "https://"; + } else { + prefix = "http://"; + } + if (url.toLowerCase().startsWith("http://") + || url.toLowerCase().startsWith("https://")) { + prefix = ""; + } + + try { + mBaseUrl = prefix + url; + //String url_str = prefix + url + webdav_path; + String url_str = prefix + url + "/remote.php/odav"; + uri = Uri.parse(url_str); + + } catch (Exception e) { + // should never happen + onAuthenticationResult(false, getString(R.string.auth_incorrect_address_title)); + return; + } + + showDialog(DIALOG_LOGIN_PROGRESS); + String accessToken = ((GetOAuth2AccessToken)operation).getResultTokenMap().get(OAuth2Context.KEY_ACCESS_TOKEN); + Log.d(TAG, "ACCESS TOKEN: " + accessToken); + mAuthChkOperation = new ExistenceCheckOperation("", this, accessToken); + WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(uri, getApplicationContext()); + mAuthChkOperation.execute(client, this, mHandler); + + + } else { + TextView tv = (TextView) findViewById(R.id.oAuth_URL); + tv.setError("A valid authorization could not be obtained"); + + } + + } else if (operation instanceof ExistenceCheckOperation) { + + try { + dismissDialog(DIALOG_LOGIN_PROGRESS); + } catch (IllegalArgumentException e) { + // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens + } + + if (result.isSuccess()) { + TextView tv = (TextView) findViewById(R.id.oAuth_URL); + tv.setError("OOOOOKKKKKK"); + Log.d(TAG, "OOOOK!!!!"); + /** + Uri uri = Uri.parse(mBaseUrl); + String username = "OAuth_user" + (new java.util.Random(System.currentTimeMillis())).nextLong(); + String accountName = username + "@" + uri.getHost(); + if (uri.getPort() >= 0) { + accountName += ":" + uri.getPort(); + } + // TODO - check that accountName does not exist + Account account = new Account(accountName, AccountAuthenticator.ACCOUNT_TYPE); + AccountManager accManager = AccountManager.get(this); + /// TODO SAVE THE ACCESS TOKEN, HERE OR IN SOME BETTER PLACE + //accManager.addAccountExplicitly(account, mAccesToken, null); //// IS THIS REALLY NEEDED? IS NOT REDUNDANT WITH SETACCOUNTAUTHENTICATORRESULT? + + // Add this account as default in the preferences, if there is none + Account defaultAccount = AccountUtils.getCurrentOwnCloudAccount(this); + if (defaultAccount == null) { + SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(this).edit(); + editor.putString("select_oc_account", accountName); + editor.commit(); + } + + /// account data to save by the AccountManager + final Intent intent = new Intent(); + intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, AccountAuthenticator.ACCOUNT_TYPE); + intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name); + intent.putExtra(AccountManager.KEY_AUTHTOKEN, AccountAuthenticator.ACCOUNT_TYPE); + intent.putExtra(AccountManager.KEY_USERDATA, username); + intent.putExtra(AccountManager.KEY_AUTHTOKEN, mAccessToken) + + accManager.setUserData(account, AccountAuthenticator.KEY_OC_VERSION, mConnChkRunnable.getDiscoveredVersion().toString()); + accManager.setUserData(account, AccountAuthenticator.KEY_OC_BASE_URL, mBaseUrl); + + setAccountAuthenticatorResult(intent.getExtras()); + setResult(RESULT_OK, intent); + + /// enforce the first account synchronization + Bundle bundle = new Bundle(); + bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); + ContentResolver.requestSync(account, "org.owncloud", bundle); + + finish(); + */ + + } else { + TextView tv = (TextView) findViewById(R.id.oAuth_URL); + tv.setError(result.getLogMessage()); + Log.d(TAG, "NOOOOO " + result.getLogMessage()); + } } } diff --git a/src/eu/alefzero/webdav/WebdavClient.java b/src/eu/alefzero/webdav/WebdavClient.java index 61f16605..e244145b 100644 --- a/src/eu/alefzero/webdav/WebdavClient.java +++ b/src/eu/alefzero/webdav/WebdavClient.java @@ -68,7 +68,7 @@ public class WebdavClient extends HttpClient { getState().setCredentials(AuthScope.ANY, getCredentials(username, password)); } - + private Credentials getCredentials(String username, String password) { if (mCredentials == null) mCredentials = new UsernamePasswordCredentials(username, password);