\r
<WebView\r
android:id="@+id/web_sso_view" \r
- android:layout_width="match_parent"\r
+ android:layout_width="wrap_content"\r
android:layout_height="wrap_content"\r
android:visibility="gone" />\r
\r
public static final String WEBDAV_PATH_2_0 = "/files/webdav.php";\r
public static final String WEBDAV_PATH_4_0 = "/remote.php/webdav";\r
private static final String ODAV_PATH = "/remote.php/odav";\r
- private static final String SAML_SSO_PATH = "/ocShibAuth";\r
+ private static final String SAML_SSO_PATH = "/remote.php/webdav";\r
public static final String CARDDAV_PATH_2_0 = "/apps/contacts/carddav.php";\r
public static final String CARDDAV_PATH_4_0 = "/remote/carddav.php";\r
public static final String STATUS_PATH = "/status.php";\r
import android.accounts.Account;\r
import android.accounts.AccountAuthenticatorActivity;\r
import android.accounts.AccountManager;\r
+import android.annotation.SuppressLint;\r
import android.app.AlertDialog;\r
import android.app.Dialog;\r
import android.app.ProgressDialog;\r
import android.view.View.OnTouchListener;\r
import android.view.Window;\r
import android.view.inputmethod.EditorInfo;\r
+import android.webkit.CookieManager;\r
+import android.webkit.WebSettings;\r
import android.webkit.WebView;\r
import android.widget.CheckBox;\r
import android.widget.EditText;\r
private TextView mOAuthTokenEndpointText;\r
\r
private TextView mAccountNameInput;\r
- private WebView mWebSsoView;\r
+ private WebView mSsoWebView;\r
+ private SsoWebViewClient mWebViewClient;\r
\r
private View mOkButton;\r
\r
mOAuthTokenEndpointText = (TextView)findViewById(R.id.oAuthEntryPoint_2);\r
mOAuth2Check = (CheckBox) findViewById(R.id.oauth_onOff_check);\r
mAccountNameInput = (EditText) findViewById(R.id.account_name);\r
- mWebSsoView = (WebView) findViewById(R.id.web_sso_view);\r
+ mSsoWebView = (WebView) findViewById(R.id.web_sso_view);\r
mOkButton = findViewById(R.id.buttonOK);\r
mAuthStatusLayout = (TextView) findViewById(R.id.auth_status_text); \r
\r
if (mAction == ACTION_UPDATE_TOKEN || !mHostUrlInputEnabled) {\r
checkOcServer(); \r
}\r
-\r
+ \r
} else {\r
/// connection state and info\r
mServerIsValid = savedInstanceState.getBoolean(KEY_SERVER_VALID);\r
\r
// account data, if updating\r
mAccount = savedInstanceState.getParcelable(KEY_ACCOUNT);\r
- mCurrentAuthTokenType = savedInstanceState.getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE, AccountAuthenticator.AUTH_TOKEN_TYPE_PASSWORD);\r
+ mCurrentAuthTokenType = savedInstanceState.getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE);\r
+ if (mCurrentAuthTokenType == null) {\r
+ mCurrentAuthTokenType = AccountAuthenticator.AUTH_TOKEN_TYPE_PASSWORD;\r
+ }\r
\r
// check if server check was interrupted by a configuration change\r
if (savedInstanceState.getBoolean(KEY_SERVER_CHECK_IN_PROGRESS, false)) {\r
\r
mPasswordInput.setText(""); // clean password to avoid social hacking (disadvantage: password in removed if the device is turned aside)\r
\r
- /// bind view elements to listeners\r
+ /// bind view elements to listeners and other friends\r
mHostUrlInput.setOnFocusChangeListener(this);\r
mHostUrlInput.addTextChangedListener(new TextWatcher() {\r
\r
}\r
return true;\r
}\r
- });
+ });\r
+ \r
+ }\r
+ \r
+ @SuppressLint("SetJavaScriptEnabled")\r
+ private void initWebView() {\r
+ CookieManager cookieManager = CookieManager.getInstance();\r
+ cookieManager.setAcceptCookie(true);\r
+ //cookieManager.removeSessionCookie(); \r
+\r
+ mWebViewClient = new SsoWebViewClient(this);\r
+ mSsoWebView.setWebViewClient(mWebViewClient);\r
+ WebSettings webSettings = mSsoWebView.getSettings();\r
+ webSettings.setJavaScriptEnabled(true);\r
+ webSettings.setBuiltInZoomControls(true);\r
+ webSettings.setLoadWithOverviewMode(false);\r
+ webSettings.setSavePassword(false);\r
+ webSettings.setUserAgentString(WebdavClient.USER_AGENT);\r
}\r
\r
private void initAuthorizationMethod() {\r
getString(R.string.oauth2_grant_type),\r
queryParameters);\r
//WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(getString(R.string.oauth2_url_endpoint_access)), getApplicationContext());\r
- WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mOAuthTokenEndpointText.getText().toString().trim()), getApplicationContext());\r
+ WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mOAuthTokenEndpointText.getText().toString().trim()), getApplicationContext(), true);\r
operation.execute(client, this, mHandler);\r
}\r
\r
mServerStatusIcon = R.drawable.progress_small;\r
showServerStatus();\r
mOcServerChkOperation = new OwnCloudServerCheckOperation(uri, this);\r
- WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(uri), this);\r
+ WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(uri), this, true);\r
mOperationThread = mOcServerChkOperation.execute(client, this, mHandler);\r
} else {\r
mServerStatusText = 0;\r
\r
/// test credentials accessing the root folder\r
mAuthCheckOperation = new ExistenceCheckOperation("", this, false);\r
- WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this);\r
+ WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this, true);\r
client.setBasicCredentials(username, password);\r
mOperationThread = mAuthCheckOperation.execute(client, this, mHandler);\r
}\r
* in the server.\r
*/\r
private void startSamlBasedFederatedSingleSignOnAuthorization() {\r
+ // be gentle with the user\r
+ mAuthStatusIcon = R.drawable.progress_small;\r
+ mAuthStatusText = R.string.oauth_login_connection;\r
+ showAuthStatus();\r
+ \r
/// get the path to the root folder through WebDAV from the version server\r
String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, mCurrentAuthTokenType);\r
\r
/// test credentials accessing the root folder\r
mAuthCheckOperation = new ExistenceCheckOperation("", this, false);\r
- WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this);\r
+ WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this, false);\r
mOperationThread = mAuthCheckOperation.execute(client, this, mHandler);\r
}\r
\r
\r
} else if (operation instanceof ExistenceCheckOperation) {\r
if (AccountAuthenticator.AUTH_TOKEN_TYPE_SAML_WEB_SSO_SESSION_COOKIE.equals(mCurrentAuthTokenType)) {\r
- Toast.makeText(this, result.getLogMessage(), Toast.LENGTH_LONG).show();\r
+ if (result.isTemporalRedirection()) {\r
+ String url = result.getRedirectedLocation();\r
+ mWebViewClient.setTargetUrl(mHostBaseUrl + AccountUtils.getWebdavPath(mDiscoveredVersion, mCurrentAuthTokenType));\r
+ mSsoWebView.loadUrl(url);\r
+ }\r
\r
} else {\r
onAuthorizationCheckFinish((ExistenceCheckOperation)operation, result);\r
mOAuthAccessToken = ((OAuth2GetAccessToken)operation).getResultTokenMap().get(OAuth2Constants.KEY_ACCESS_TOKEN);\r
Log_OC.d(TAG, "Got ACCESS TOKEN: " + mOAuthAccessToken);\r
mAuthCheckOperation = new ExistenceCheckOperation("", this, false);\r
- WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this);\r
+ WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this, true);\r
client.setBearerCredentials(mOAuthAccessToken);\r
mAuthCheckOperation.execute(client, this, mHandler);\r
\r
mUsernameInput.setVisibility(View.GONE);\r
mPasswordInput.setVisibility(View.GONE);\r
mAccountNameInput.setVisibility(View.GONE);\r
- mWebSsoView.setVisibility(View.GONE);\r
+ mSsoWebView.setVisibility(View.GONE);\r
\r
} else if (AccountAuthenticator.AUTH_TOKEN_TYPE_SAML_WEB_SSO_SESSION_COOKIE.equals(mCurrentAuthTokenType)) {\r
// SAML-based web Single Sign On\r
mUsernameInput.setVisibility(View.GONE);\r
mPasswordInput.setVisibility(View.GONE);\r
mAccountNameInput.setVisibility(View.VISIBLE);\r
- mWebSsoView.setVisibility(View.VISIBLE);\r
+ mSsoWebView.setVisibility(View.VISIBLE);\r
+ initWebView();\r
\r
} else {\r
// basic HTTP authorization\r
mUsernameInput.setVisibility(View.VISIBLE);\r
mPasswordInput.setVisibility(View.VISIBLE);\r
mAccountNameInput.setVisibility(View.GONE);\r
- mWebSsoView.setVisibility(View.GONE);\r
+ mSsoWebView.setVisibility(View.GONE);\r
}\r
}\r
\r
--- /dev/null
+/* ownCloud Android client application
+ * Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package com.owncloud.android.authentication;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.view.View;
+import android.webkit.CookieManager;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.Toast;
+
+import com.owncloud.android.Log_OC;
+
+/**
+ * Custom {@link WebViewClient} client aimed to catch the end of a single-sign-on process
+ * running in the {@link WebView} that is attached to.
+ *
+ * Assumes that the single-sign-on is kept thanks to a cookie set at the end of the
+ * authentication process.
+ *
+ * @author David A. Velasco
+ */
+public class SsoWebViewClient extends WebViewClient {
+
+ private static final String TAG = SsoWebViewClient.class.getSimpleName();
+
+ private Context mContext;
+ private String mTargetUrl;
+
+ public SsoWebViewClient (Context context) {
+ mContext = context;
+ mTargetUrl = "fake://url.to.be.set";
+ }
+
+ public String getTargetUrl() {
+ return mTargetUrl;
+ }
+
+ public void setTargetUrl(String targetUrl) {
+ mTargetUrl = targetUrl;
+ }
+
+ @Override
+ public void onPageStarted (WebView view, String url, Bitmap favicon) {
+ //Log_OC.e(TAG, "onPageStarted : " + url);
+ if (url.startsWith(mTargetUrl)) {
+ view.setVisibility(View.GONE);
+ CookieManager cookieManager = CookieManager.getInstance();
+ String cookies = cookieManager.getCookie(url);
+ Toast.makeText(mContext, "got cookies: " + cookies, Toast.LENGTH_LONG).show();
+ }
+ }
+
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ //view.loadUrl(url);
+ return false;
+ }
+
+ @Override
+ public void onReceivedError (WebView view, int errorCode, String description, String failingUrl) {
+ Log_OC.e(TAG, "onReceivedError : " + failingUrl);
+ }
+
+ /*
+
+ @Override
+ public void doUpdateVisitedHistory (WebView view, String url, boolean isReload) {
+ Log_OC.e(TAG, "doUpdateVisitedHistory : " + url);
+ }
+
+ @Override
+ public void onPageFinished (WebView view, String url) {
+ Log_OC.e(TAG, "onPageFinished : " + url);
+ }
+
+ @Override
+ public void onReceivedSslError (WebView view, SslErrorHandler handler, SslError error) {
+ Log_OC.e(TAG, "onReceivedSslError : " + error);
+ }
+
+ @Override
+ public void onReceivedHttpAuthRequest (WebView view, HttpAuthHandler handler, String host, String realm) {
+ Log_OC.e(TAG, "onReceivedHttpAuthRequest : " + host);
+ }
+
+ @Override
+ public WebResourceResponse shouldInterceptRequest (WebView view, String url) {
+ Log_OC.e(TAG, "shouldInterceptRequest : " + url);
+ return null;
+ }
+
+ @Override
+ public void onLoadResource (WebView view, String url) {
+ Log_OC.e(TAG, "onLoadResource : " + url);
+ }
+
+ @Override
+ public void onFormResubmission (WebView view, Message dontResend, Message resend) {
+ Log_OC.e(TAG, "onFormResubMission ");
+ super.onFormResubmission(view, dontResend, resend);
+ }
+
+ @Override
+ public void onReceivedLoginRequest (WebView view, String realm, String account, String args) {
+ Log_OC.e(TAG, "onReceivedLoginRequest : " + realm + ", " + account + ", " + args);
+ }
+
+ @Override
+ public void onScaleChanged (WebView view, float oldScale, float newScale) {
+ Log_OC.e(TAG, "onScaleChanged : " + oldScale + " -> " + newScale);
+ }
+
+ @Override
+ public void onUnhandledKeyEvent (WebView view, KeyEvent event) {
+ Log_OC.e(TAG, "onUnhandledKeyEvent : " + event);
+ }
+
+ @Override
+ public boolean shouldOverrideKeyEvent (WebView view, KeyEvent event) {
+ Log_OC.e(TAG, "shouldOverrideKeyEvent : " + event);
+ return false;
+ }
+
+ */
+}
//Log_OC.d(TAG, "Creating WebdavClient associated to " + account.name);
Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(appContext, account));
- WebdavClient client = createOwnCloudClient(uri, appContext);
+ WebdavClient client = createOwnCloudClient(uri, appContext, true);
AccountManager am = AccountManager.get(appContext);
if (am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null) { // TODO avoid a call to getUserData here
String accessToken = am.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, false);
public static WebdavClient createOwnCloudClient (Account account, Context appContext, Activity currentActivity) throws OperationCanceledException, AuthenticatorException, IOException, AccountNotFoundException {
Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(appContext, account));
- WebdavClient client = createOwnCloudClient(uri, appContext);
+ WebdavClient client = createOwnCloudClient(uri, appContext, true);
AccountManager am = AccountManager.get(appContext);
if (am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null) { // TODO avoid a call to getUserData here
AccountManagerFuture<Bundle> future = am.getAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, null, currentActivity, null, null);
* @param context Android context where the WebdavClient is being created.
* @return A WebdavClient object ready to be used
*/
- public static WebdavClient createOwnCloudClient(Uri uri, Context context) {
- //Log_OC.d(TAG, "Creating WebdavClient for " + uri);
-
- //allowSelfsignedCertificates(true);
+ public static WebdavClient createOwnCloudClient(Uri uri, Context context, boolean followRedirects) {
try {
registerAdvancedSslContext(true, context);
} catch (GeneralSecurityException e) {
client.setDefaultTimeouts(DEFAULT_DATA_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT);
client.setBaseUri(uri);
+ client.setFollowRedirects(followRedirects);
return client;
}
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);
+ result = new RemoteOperationResult(success, status, head.getResponseHeaders());
Log_OC.d(TAG, "Existence check for " + client.getBaseUri() + mPath + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + "finished with HTTP status " + status + (!success?"(FAIL)":""));
} catch (Exception e) {
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
+import java.util.Map;
import javax.net.ssl.SSLException;
import org.apache.commons.httpclient.ConnectTimeoutException;
+import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.DavException;
public class RemoteOperationResult implements Serializable {
/** Generated - should be refreshed every time the class changes!! */
- private static final long serialVersionUID = 6106167714625712390L;
+ private static final long serialVersionUID = 3267227833178885664L;
private static final String TAG = "RemoteOperationResult";
private int mHttpCode = -1;
private Exception mException = null;
private ResultCode mCode = ResultCode.UNKNOWN_ERROR;
+ private String mRedirectedLocation;
public RemoteOperationResult(ResultCode code) {
mCode = code;
}
}
}
+
+ public RemoteOperationResult(boolean success, int httpCode, Header[] headers) {
+ this(success, httpCode);
+ if (headers != null) {
+ Header current;
+ for (int i=0; i<headers.length; i++) {
+ current = headers[i];
+ if ("Location".equals(current.getName())) {
+ mRedirectedLocation = current.getValue();
+ break;
+ }
+ }
+ }
+ }
public RemoteOperationResult(Exception e) {
mException = e;
return (mException != null);
}
+ public boolean isTemporalRedirection() {
+ return (mHttpCode == 302 || mHttpCode == 307);
+ }
+
+ public String getRedirectedLocation() {
+ return mRedirectedLocation;
+ }
+
}
package eu.alefzero.webdav;
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.httpclient.Credentials;
-import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.HttpException;
-import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpMethodBase;
-import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.HttpVersion;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthPolicy;
import org.apache.commons.httpclient.auth.AuthScope;
-import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.HeadMethod;
-import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.http.HttpStatus;
import org.apache.http.params.CoreProtocolPNames;
-import org.apache.jackrabbit.webdav.client.methods.DavMethod;
-import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;
import com.owncloud.android.Log_OC;
public class WebdavClient extends HttpClient {
private Uri mUri;
private Credentials mCredentials;
+ private boolean mFollowRedirects;
final private static String TAG = "WebdavClient";
- private static final String USER_AGENT = "Android-ownCloud";
+ public static final String USER_AGENT = "Android-ownCloud";
- private OnDatatransferProgressListener mDataTransferListener;
static private byte[] sExhaustBuffer = new byte[1024];
/**
Log_OC.d(TAG, "Creating WebdavClient");
getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT);
getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
+ mFollowRedirects = true;
}
public void setBearerCredentials(String accessToken) {
public boolean existsFile(String path) throws IOException, HttpException {
HeadMethod head = new HeadMethod(mUri.toString() + WebdavUtils.encodePath(path));
try {
+ head.setFollowRedirects(mFollowRedirects);
int status = executeMethod(head);
Log_OC.d(TAG, "HEAD to " + path + " finished with HTTP status " + status + ((status != HttpStatus.SC_OK)?"(FAIL)":""));
exhaustResponse(head.getResponseBodyAsStream());
if (connectionTimeout >= 0) {
getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);
}
+ method.setFollowRedirects(mFollowRedirects);
return executeMethod(method);
} finally {
getParams().setSoTimeout(oldSoTimeout);
public final Credentials getCredentials() {\r
return mCredentials;\r
+ }
+
+ public void setFollowRedirects(boolean followRedirects) {
+ mFollowRedirects = followRedirects;
}\r
\r
}