1
0
mirror of https://github.com/owncloud/android-library.git synced 2025-06-28 10:16:35 +00:00

add dav4droid support part1

This commit is contained in:
DerSchabi 2018-05-17 09:45:54 +02:00 committed by davigonz
parent 9ab1b40682
commit cd3d20db07
40 changed files with 3612 additions and 474 deletions

3
.gitignore vendored
View File

@ -31,3 +31,6 @@ proguard-project.txt
sample_client/proguard-project.txt
tests/proguard-project.txt
tests/test_cases/proguard-project.txt
# setup.xml login credentials
sample_client/res/values/setup.xml

View File

@ -14,12 +14,14 @@ allprojects {
repositories {
google()
jcenter()
maven { url 'https://jitpack.io' }
}
}
dependencies {
api 'org.apache.jackrabbit:jackrabbit-webdav:2.12.4'
api 'com.squareup.okhttp3:okhttp:3.10.0'
api 'com.gitlab.derSchabi:dav4android:dev2'
}
android {
@ -52,4 +54,8 @@ android {
lintOptions {
abortOnError false
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

View File

@ -24,27 +24,22 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.owncloud.android.lib.sampleclient"
android:versionCode="1"
android:versionName="1.0">
<uses-permission android:name="android.permission.INTERNET"/>
package="com.owncloud.android.lib.sampleclient"
android:versionCode="1"
android:versionName="1.0">
<uses-permission android:name="android.permission.INTERNET" />
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="26"/>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.Light.NoTitleBar">
<activity
android:name="MainActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/app_name"
android:screenOrientation="portrait"
>
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
<activity android:name="MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:configChanges="orientation|keyboardHidden"
>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

View File

@ -42,4 +42,8 @@ android {
packagingOptions {
exclude 'META-INF/LICENSE.txt'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

View File

@ -24,150 +24,99 @@
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<EditText
android:id="@+id/server_address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_toLeftOf="@+id/button_check_server"
android:layout_toStartOf="@+id/button_check_server"
android:ems="10"
android:hint="Server address (with http or https)"
android:inputType="textPersonName"/>
<Button
android:id="@+id/button_check_server"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/server_address"
android:layout_alignBottom="@+id/server_address"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:onClick="onClickHandler"
android:text="@string/check_server"/>
<Button
android:id="@+id/button_refresh"
style="@style/ButtonStyle"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="@string/refresh"
android:onClick="onClickHandler"
/>
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_below="@+id/button_refresh"
android:layout_above="@+id/button_upload"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_below="@id/server_address"
android:layout_marginTop="10dp"
android:onClick="onClickHandler"
android:text="@string/refresh"/>
>
</ListView>
<Button
android:id="@+id/button_upload"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/ButtonStyle"
android:layout_alignParentLeft="true"
android:layout_below="@id/button_refresh"
android:layout_marginTop="10dp"
android:layout_above="@+id/frame"
android:text="@string/upload"
android:onClick="onClickHandler"
android:text="@string/upload"/>
/>
<TextView
android:id="@+id/upload_progress"
style="@style/ProgressStyle"
android:layout_below="@id/list_view"
android:layout_above="@id/frame"
android:layout_toRightOf="@id/button_upload"
android:layout_toLeftOf="@+id/button_delete_remote"
android:gravity="center"
android:textSize="14sp"
android:text="0%"
/>
<Button
android:id="@+id/button_download"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@id/button_upload"
android:layout_marginTop="10dp"
android:id="@id/button_delete_remote"
style="@style/ButtonStyle"
android:layout_alignParentRight="true"
android:layout_above="@id/frame"
android:text="@string/delete_remote_file"
android:onClick="onClickHandler"
android:text="@string/download"/>
/>
<FrameLayout
android:id="@id/frame"
android:layout_width="match_parent"
android:layout_height="@dimen/frame_height"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_above="@+id/button_download"
>
</FrameLayout>
<Button
android:id="@+id/button_delete_remote"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@id/button_download"
style="@style/ButtonStyle"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_below="@id/button_download"
android:layout_marginTop="10dp"
android:text="@string/download"
android:onClick="onClickHandler"
android:text="@string/delete_remote_file"/>
/>
<!--<ListView-->
<!--android:id="@+id/list_view"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_alignParentLeft="true"-->
<!--android:layout_alignParentRight="true"-->
<!--android:layout_below="@+id/button_refresh"-->
<!--android:visibility="invisible">-->
<!--</ListView>-->
<TextView
android:id="@+id/download_progress"
style="@style/ProgressStyle"
android:layout_below="@id/frame"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@id/button_download"
android:layout_toLeftOf="@+id/button_delete_local"
android:gravity="center"
android:textSize="14sp"
android:text="0%"
/>
<!--<TextView-->
<!--android:id="@+id/upload_progress"-->
<!--style="@style/ProgressStyle"-->
<!--android:layout_above="@id/frame"-->
<!--android:layout_below="@id/list_view"-->
<!--android:layout_toLeftOf="@+id/button_delete_remote"-->
<!--android:layout_toRightOf="@id/button_upload"-->
<!--android:enabled="false"-->
<!--android:gravity="center"-->
<!--android:text="0%"-->
<!--android:textSize="14sp"-->
<!--android:visibility="invisible"/>-->
<!--<Button-->
<!--android:id="@id/button_delete_remote"-->
<!--style="@style/ButtonStyle"-->
<!--android:layout_above="@id/frame"-->
<!--android:layout_alignParentRight="true"-->
<!--android:enabled="false"-->
<!--android:onClick="onClickHandler"-->
<!--android:text="@string/delete_remote_file"-->
<!--android:visibility="invisible"/>-->
<!--<FrameLayout-->
<!--android:id="@id/frame"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="@dimen/frame_height"-->
<!--android:layout_alignParentLeft="true"-->
<!--android:layout_alignParentRight="true"-->
<!--android:layout_above="@+id/button_download"-->
<!--&gt;-->
<!--</FrameLayout>-->
<!--<Button-->
<!--android:id="@id/button_download"-->
<!--style="@style/ButtonStyle"-->
<!--android:layout_alignParentBottom="true"-->
<!--android:layout_alignParentLeft="true"-->
<!--android:enabled="false"-->
<!--android:onClick="onClickHandler"-->
<!--android:text="@string/download"-->
<!--android:visibility="invisible"/>-->
<!--<TextView-->
<!--android:id="@+id/download_progress"-->
<!--style="@style/ProgressStyle"-->
<!--android:layout_alignParentBottom="true"-->
<!--android:layout_below="@id/frame"-->
<!--android:layout_toLeftOf="@+id/button_delete_local"-->
<!--android:layout_toRightOf="@id/button_download"-->
<!--android:enabled="false"-->
<!--android:gravity="center"-->
<!--android:text="0%"-->
<!--android:textSize="14sp"-->
<!--android:visibility="invisible"/>-->
<!--<Button-->
<!--android:id="@id/button_delete_local"-->
<!--style="@style/ButtonStyle"-->
<!--android:layout_alignParentBottom="true"-->
<!--android:layout_alignParentRight="true"-->
<!--android:enabled="false"-->
<!--android:onClick="onClickHandler"-->
<!--android:text="@string/delete_local_file"-->
<!--android:visibility="invisible"/>-->
<Button
android:id="@id/button_delete_local"
style="@style/ButtonStyle"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:text="@string/delete_local_file"
android:onClick="onClickHandler"
/>
</RelativeLayout>

View File

@ -26,7 +26,6 @@
<resources>
<string name="app_name">ownCloud Sample Client</string>
<string name="refresh">Refresh</string>
<string name="check_server">Check server</string>
<string name="upload">Upload</string>
<string name="delete_remote_file">Delete remote file</string>
<string name="download">Download</string>

View File

@ -1,7 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2018 ownCloud GmbH.
*
* @author David González Verdugo
* Copyright (C) 2016 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -26,35 +24,6 @@
package com.owncloud.android.lib.sampleclient;
import android.app.Activity;
import android.content.res.AssetManager;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.OwnCloudClientFactory;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.resources.files.DownloadRemoteFileOperation;
import com.owncloud.android.lib.resources.files.FileUtils;
import com.owncloud.android.lib.resources.files.ReadRemoteFolderOperation;
import com.owncloud.android.lib.resources.files.RemoteFile;
import com.owncloud.android.lib.resources.files.RemoveRemoteFileOperation;
import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@ -63,31 +32,36 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Credentials;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
import com.owncloud.android.lib.common.OwnCloudClientFactory;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
import com.owncloud.android.lib.resources.files.RemoteFile;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.resources.files.DownloadRemoteFileOperation;
import com.owncloud.android.lib.resources.files.ReadRemoteFolderOperation;
import com.owncloud.android.lib.resources.files.RemoveRemoteFileOperation;
import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation;
import com.owncloud.android.lib.resources.files.FileUtils;
import android.app.Activity;
import android.content.res.AssetManager;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnRemoteOperationListener, OnDatatransferProgressListener {
private static String LOG_TAG = MainActivity.class.getCanonicalName();
private static final String NODE_VERSION = "version";
private static final String WEBDAV_PATH_4_0 = "/remote.php/webdav/";
private static final String NEW_WEBDAV_PATH = "/remote.php/dav/files/";
private static final String OC_TOTAL_LENGTH_HEADER = "OC-Total-Length";
private static final String OC_X_OC_MTIME_HEADER = "X-OC-Mtime";
private static final String AUTHORIZATION_HEADER = "Authorization";
private static final String USER_AGENT_HEADER = "User-Agent";
private static final String CONTENT_TYPE_HEADER = "Content-Type";
private static final String USER_AGENT_VALUE = "Mozilla/5.0 (Android) ownCloud-android/2.7.0";
private static final String CONTENT_TYPE_VALUE = "multipart/form-data";
private Handler mHandler;
private OwnCloudClient mClient;
@ -96,10 +70,6 @@ public class MainActivity extends Activity implements OnRemoteOperationListener,
private View mFrame;
private OkHttpClient mOkHttpClient;
private String mCredentials;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
@ -118,7 +88,7 @@ public class MainActivity extends Activity implements OnRemoteOperationListener,
);
mFilesAdapter = new FilesArrayAdapter(this, R.layout.file_in_list);
// ((ListView)findViewById(R.id.list_view)).setAdapter(mFilesAdapter);
((ListView)findViewById(R.id.list_view)).setAdapter(mFilesAdapter);
// TODO move to background thread or task
AssetManager assets = getAssets();
@ -141,13 +111,7 @@ public class MainActivity extends Activity implements OnRemoteOperationListener,
Log.e(LOG_TAG, getString(R.string.error_copying_sample_file), e);
}
((TextView) findViewById(R.id.server_address)).setText(getString(R.string.server_base_url));
mOkHttpClient = new OkHttpClient();
mCredentials = Credentials.basic(getString(R.string.username), getString(R.string.password));
// mFrame = findViewById(R.id.frame);
mFrame = findViewById(R.id.frame);
}
@ -163,264 +127,63 @@ public class MainActivity extends Activity implements OnRemoteOperationListener,
public void onClickHandler(View button) {
switch (button.getId()) {
case R.id.button_check_server:
startCheck();
break;
case R.id.button_refresh:
startRefresh();
break;
case R.id.button_upload:
startUpload();
break;
case R.id.button_download:
startDownload();
break;
case R.id.button_delete_remote:
startRemoteDeletion();
break;
// case R.id.button_delete_local:
// startLocalDeletion();
// break;
case R.id.button_download:
startDownload();
break;
case R.id.button_delete_local:
startLocalDeletion();
break;
default:
Toast.makeText(this, R.string.youre_doing_it_wrong, Toast.LENGTH_SHORT).show();
}
}
private void startCheck() {
if (!validServerAddress()) return;
Request request = new Request.Builder()
.url(getString(R.string.server_base_url) + "/status.php")
.get()
.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
showMessage("Response not successful with code: " + response.code());
throw new IOException("Unexpected code " + response);
}
try { // Successful response
String jsonData = response.body().string();
JSONObject Jobject = new JSONObject(jsonData);
final String serverVersion = Jobject.get("version").toString();
showMessage("Server with version " + serverVersion + " detected");
} catch (JSONException e) {
e.printStackTrace();
}
Headers responseHeaders = response.headers();
for (int i = 0, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
}
@Override public void onFailure(Call call, final IOException e) {
e.printStackTrace();
showMessage("Something was wrong: " + e.toString());
}
});
}
private void startRefresh() {
// Let's first use OKHttp with the new endpoint without depending on our library operations
// ReadRemoteFolderOperation refreshOperation = new ReadRemoteFolderOperation(FileUtils.PATH_SEPARATOR);
// refreshOperation.execute(mClient, this, mHandler);
if (!validServerAddress()) return;
final Request request = new Request.Builder()
.url(getString(R.string.server_base_url) + NEW_WEBDAV_PATH + getString(R.string.username))
.addHeader(AUTHORIZATION_HEADER, mCredentials)
.addHeader(USER_AGENT_HEADER, USER_AGENT_VALUE)
.method("PROPFIND", null)
.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
showMessage("Response not successful with code: " + response.code());
throw new IOException("Unexpected code " + response);
} else { // Successful response
final String propFindResult = response.body().string();
showMessage(propFindResult);
Headers responseHeaders = response.headers();
for (int i = 0, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
}
}
@Override public void onFailure(Call call, IOException e) {
showMessage("Something was wrong: " + e.toString());
e.printStackTrace();
}
});
}
private void startRefresh() {
ReadRemoteFolderOperation refreshOperation = new ReadRemoteFolderOperation(FileUtils.PATH_SEPARATOR);
refreshOperation.execute(mClient, this, mHandler);
}
private void startUpload() {
File upFolder = new File(getCacheDir(), getString(R.string.upload_folder_path));
final File fileToUpload = upFolder.listFiles()[0];
File fileToUpload = upFolder.listFiles()[0];
String remotePath = FileUtils.PATH_SEPARATOR + fileToUpload.getName();
String mimeType = getString(R.string.sample_file_mimetype);
MediaType mediaType = MediaType.parse(mimeType);
// Get the last modification date of the file from the file system
Long timeStampLong = fileToUpload.lastModified()/1000;
String timeStamp = timeStampLong.toString();
// Let's first use OKHttp with the new endpoint without depending on our library operations
// UploadRemoteFileOperation uploadOperation = new UploadRemoteFileOperation(fileToUpload.getAbsolutePath(), remotePath, mimeType, timeStamp);
// uploadOperation.addDatatransferProgressListener(this);
// uploadOperation.execute(mClient, this, mHandler);
if (!validServerAddress()) return;
RequestBody requestBody = RequestBody.create(mediaType, fileToUpload);
final Request request = new Request.Builder()
.url(getString(R.string.server_base_url) + NEW_WEBDAV_PATH + getString(R.string.username) + remotePath)
.addHeader(AUTHORIZATION_HEADER, mCredentials)
.addHeader(USER_AGENT_HEADER, USER_AGENT_VALUE)
.addHeader(CONTENT_TYPE_HEADER, CONTENT_TYPE_VALUE)
.addHeader(OC_TOTAL_LENGTH_HEADER, String.valueOf(fileToUpload.length()))
.addHeader(OC_X_OC_MTIME_HEADER, timeStamp)
.put(requestBody)
.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
showMessage("Response not successful with code: " + response.code());
throw new IOException("Unexpected code " + response);
} else { // Successful response
showMessage("Successful upload of " + fileToUpload.getName());
}
}
@Override public void onFailure(Call call, IOException e) {
e.printStackTrace();
showMessage("Something was wrong: " + e.toString());
}
});
UploadRemoteFileOperation uploadOperation = new UploadRemoteFileOperation(fileToUpload.getAbsolutePath(), remotePath, mimeType, timeStamp);
uploadOperation.addDatatransferProgressListener(this);
uploadOperation.execute(mClient, this, mHandler);
}
private void startDownload() {
File downFolder = new File(getCacheDir(), getString(R.string.download_folder_path));
downFolder.mkdir();
File upFolder = new File(getCacheDir(), getString(R.string.upload_folder_path));
final File fileToUpload = upFolder.listFiles()[0];
String remotePath = FileUtils.PATH_SEPARATOR + fileToUpload.getName();
// Let's first use OKHttp with the new endpoint without depending on our library operations
// DownloadRemoteFileOperation downloadOperation = new DownloadRemoteFileOperation(remotePath, downFolder.getAbsolutePath());
// downloadOperation.addDatatransferProgressListener(this);
// downloadOperation.execute(mClient, this, mHandler);
if (!validServerAddress()) return;
final Request request = new Request.Builder()
.url(getString(R.string.server_base_url) + NEW_WEBDAV_PATH + getString(R.string.username) + remotePath)
.addHeader(AUTHORIZATION_HEADER, mCredentials)
.addHeader(USER_AGENT_HEADER, USER_AGENT_VALUE)
.get()
.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
showMessage("Response not successful with code: " + response.code());
throw new IOException("Unexpected code " + response);
} else { // Successful response
showMessage("Successful download of " + fileToUpload.getName() + " although local file " +
"won't be created in this stage");
}
}
@Override public void onFailure(Call call, IOException e) {
e.printStackTrace();
showMessage("Something was wrong: " + e.toString());
}
});
}
private void startRemoteDeletion() {
private void startRemoteDeletion() {
File upFolder = new File(getCacheDir(), getString(R.string.upload_folder_path));
final File fileToUpload = upFolder.listFiles()[0];
File fileToUpload = upFolder.listFiles()[0];
String remotePath = FileUtils.PATH_SEPARATOR + fileToUpload.getName();
RemoveRemoteFileOperation removeOperation = new RemoveRemoteFileOperation(remotePath);
removeOperation.execute(mClient, this, mHandler);
}
// Let's first use OKHttp with the new endpoint without depending on our library operations
// RemoveRemoteFileOperation removeOperation = new RemoveRemoteFileOperation(remotePath);
// removeOperation.execute(mClient, this, mHandler);
if (!validServerAddress()) return;
final Request request = new Request.Builder()
.url(getString(R.string.server_base_url) + NEW_WEBDAV_PATH + getString(R.string.username) + remotePath)
.addHeader(AUTHORIZATION_HEADER, mCredentials)
.addHeader(USER_AGENT_HEADER, USER_AGENT_VALUE)
.delete()
.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
showMessage("Response not successful with code: " + response.code());
throw new IOException("Unexpected code " + response);
} else { // Successful response
showMessage("Successful deletion of " + fileToUpload.getName());
}
}
@Override public void onFailure(Call call, IOException e) {
e.printStackTrace();
showMessage("Something was wrong: " + e.toString());
}
});
private void startDownload() {
File downFolder = new File(getCacheDir(), getString(R.string.download_folder_path));
downFolder.mkdir();
File upFolder = new File(getCacheDir(), getString(R.string.upload_folder_path));
File fileToUpload = upFolder.listFiles()[0];
String remotePath = FileUtils.PATH_SEPARATOR + fileToUpload.getName();
DownloadRemoteFileOperation downloadOperation = new DownloadRemoteFileOperation(remotePath, downFolder.getAbsolutePath());
downloadOperation.addDatatransferProgressListener(this);
downloadOperation.execute(mClient, this, mHandler);
}
@SuppressWarnings("deprecation")
@ -430,8 +193,8 @@ public class MainActivity extends Activity implements OnRemoteOperationListener,
if (!downloadedFile.delete() && downloadedFile.exists()) {
Toast.makeText(this, R.string.error_deleting_local_file, Toast.LENGTH_SHORT).show();
} else {
// ((TextView) findViewById(R.id.download_progress)).setText("0%");
// findViewById(R.id.frame).setBackgroundDrawable(null);
((TextView) findViewById(R.id.download_progress)).setText("0%");
findViewById(R.id.frame).setBackgroundDrawable(null);
}
}
@ -480,10 +243,10 @@ public class MainActivity extends Activity implements OnRemoteOperationListener,
private void onSuccessfulRemoteDeletion(RemoveRemoteFileOperation operation, RemoteOperationResult result) {
startRefresh();
// TextView progressView = (TextView) findViewById(R.id.upload_progress);
// if (progressView != null) {
// progressView.setText("0%");
// }
TextView progressView = (TextView) findViewById(R.id.upload_progress);
if (progressView != null) {
progressView.setText("0%");
}
}
@SuppressWarnings("deprecation")
@ -503,11 +266,11 @@ public class MainActivity extends Activity implements OnRemoteOperationListener,
@Override
public void run() {
TextView progressView = null;
// if (upload) {
// progressView = (TextView) findViewById(R.id.upload_progress);
// } else {
// progressView = (TextView) findViewById(R.id.download_progress);
// }
if (upload) {
progressView = (TextView) findViewById(R.id.upload_progress);
} else {
progressView = (TextView) findViewById(R.id.download_progress);
}
if (progressView != null) {
progressView.setText(Long.toString(percentage) + "%");
}
@ -515,32 +278,4 @@ public class MainActivity extends Activity implements OnRemoteOperationListener,
});
}
private boolean validServerAddress() {
String serverAddress = ((TextView) findViewById(R.id.server_address)).getText().toString();
if (serverAddress.equals("") || (!serverAddress.contains("http://") && !serverAddress.contains("https://"))) {
showToastMessage("Introduce a proper server address with http/https");
return false;
}
return true;
}
private void showMessage(final String message) {
runOnUiThread(new Runnable() {
@Override
public void run() {
showToastMessage(message);
}
});
}
private void showToastMessage(String message) {
Toast toast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
}
}

View File

@ -39,6 +39,8 @@ import com.owncloud.android.lib.common.utils.Log_OC;
import java.io.IOException;
import okhttp3.OkHttpClient;
/**
* Operation which execution involves one or several interactions with an ownCloud server.
@ -77,6 +79,11 @@ public abstract class RemoteOperation implements Runnable {
*/
private OwnCloudClient mClient = null;
/**
* Object to interact with the remote server
*/
private OkHttpClient mHttpClient = null;
/**
* Callback object to notify about the execution of the remote operation
*/
@ -142,6 +149,25 @@ public abstract class RemoteOperation implements Runnable {
return runOperation();
}
/**
* Synchronously executes the remote operation
*
* Do not call this method from the main thread.
*
* @param client Client object to reach an ownCloud server during the execution of
* the operation.
* @return Result of the operation.
*/
public RemoteOperationResult execute(OkHttpClient client, Context context) {
if (client == null)
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " +
"OwnCloudClient");
mHttpClient = client;
mContext = context;
return runOperation();
}
/**
* Asynchronously executes the remote operation

View File

@ -0,0 +1,212 @@
package com.owncloud.android.lib.refactor;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import android.util.Log;
public class Log_OC {
private static final String SIMPLE_DATE_FORMAT = "yyyy/MM/dd HH:mm:ss";
private static final String LOG_FOLDER_NAME = "log";
private static final long MAX_FILE_SIZE = 1000000; // 1MB
private static String mOwncloudDataFolderLog = "owncloud_log";
private static File mLogFile;
private static File mFolder;
private static BufferedWriter mBuf;
private static String[] mLogFileNames = {"currentLog.txt", "olderLog.txt"};
private static boolean isMaxFileSizeReached = false;
private static boolean isEnabled = false;
public static void setLogDataFolder(String logFolder){
mOwncloudDataFolderLog = logFolder;
}
public static void i(String TAG, String message){
Log.i(TAG, message);
appendLog(TAG+" : "+ message);
}
public static void d(String TAG, String message){
Log.d(TAG, message);
appendLog(TAG + " : " + message);
}
public static void d(String TAG, String message, Exception e) {
Log.d(TAG, message, e);
appendLog(TAG + " : " + message + " Exception : "+ e.getStackTrace());
}
public static void e(String TAG, String message){
Log.e(TAG, message);
appendLog(TAG + " : " + message);
}
public static void e(String TAG, String message, Throwable e) {
Log.e(TAG, message, e);
appendLog(TAG+" : " + message +" Exception : " + e.getStackTrace());
}
public static void v(String TAG, String message){
Log.v(TAG, message);
appendLog(TAG+" : "+ message);
}
public static void w(String TAG, String message) {
Log.w(TAG, message);
appendLog(TAG+" : "+ message);
}
public static void wtf(String TAG, String message) {
Log.wtf(TAG, message);
appendLog(TAG+" : "+ message);
}
/**
* Start doing logging
* @param storagePath : directory for keeping logs
*/
synchronized public static void startLogging(String storagePath) {
String logPath = storagePath + File.separator +
mOwncloudDataFolderLog + File.separator + LOG_FOLDER_NAME;
mFolder = new File(logPath);
mLogFile = new File(mFolder + File.separator + mLogFileNames[0]);
boolean isFileCreated = false;
if (!mFolder.exists()) {
mFolder.mkdirs();
isFileCreated = true;
Log.d("LOG_OC", "Log file created");
}
try {
// Create the current log file if does not exist
mLogFile.createNewFile();
mBuf = new BufferedWriter(new FileWriter(mLogFile, true));
isEnabled = true;
if (isFileCreated) {
appendPhoneInfo();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(mBuf != null) {
try {
mBuf.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
}
synchronized public static void stopLogging() {
try {
if (mBuf != null)
mBuf.close();
isEnabled = false;
mLogFile = null;
mFolder = null;
mBuf = null;
isMaxFileSizeReached = false;
isEnabled = false;
} catch (IOException e) {
// Because we are stopping logging, we only log to Android console.
Log.e("OC_Log", "Closing log file failed: ", e);
} catch (Exception e) {
// This catch should never fire because we do null check on mBuf.
// But just for the sake of stability let's log this odd situation.
// Because we are stopping logging, we only log to Android console.
Log.e("OC_Log", "Stopping logging failed: ", e);
}
}
/**
* Delete history logging
*/
public static void deleteHistoryLogging() {
File folderLogs = new File(mFolder + File.separator);
if(folderLogs.isDirectory()){
String[] myFiles = folderLogs.list();
for (int i=0; i<myFiles.length; i++) {
File myFile = new File(folderLogs, myFiles[i]);
myFile.delete();
}
}
}
/**
* Append the info of the device
*/
private static void appendPhoneInfo() {
appendLog("Model : " + android.os.Build.MODEL);
appendLog("Brand : " + android.os.Build.BRAND);
appendLog("Product : " + android.os.Build.PRODUCT);
appendLog("Device : " + android.os.Build.DEVICE);
appendLog("Version-Codename : " + android.os.Build.VERSION.CODENAME);
appendLog("Version-Release : " + android.os.Build.VERSION.RELEASE);
}
/**
* Append to the log file the info passed
* @param text : text for adding to the log file
*/
synchronized private static void appendLog(String text) {
if (isEnabled) {
if (isMaxFileSizeReached) {
// Move current log file info to another file (old logs)
File olderFile = new File(mFolder + File.separator + mLogFileNames[1]);
if (mLogFile.exists()) {
mLogFile.renameTo(olderFile);
}
// Construct a new file for current log info
mLogFile = new File(mFolder + File.separator + mLogFileNames[0]);
isMaxFileSizeReached = false;
}
String timeStamp = new SimpleDateFormat(SIMPLE_DATE_FORMAT).format(Calendar.getInstance().getTime());
try {
mBuf = new BufferedWriter(new FileWriter(mLogFile, true));
mBuf.newLine();
mBuf.write(timeStamp);
mBuf.newLine();
mBuf.write(text);
mBuf.newLine();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
mBuf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// Check if current log file size is bigger than the max file size defined
if (mLogFile.length() > MAX_FILE_SIZE) {
isMaxFileSizeReached = true;
}
}
}
public static String[] getLogFileNames() {
return mLogFileNames;
}
}

View File

@ -0,0 +1,50 @@
package com.owncloud.android.lib.refactor;
import android.net.Uri;
import com.owncloud.android.lib.refactor.authentication.OwnCloudCredentials;
public class OwnCloudContext {
private static final String TAG = OwnCloudContext.class.toString();
public static final String WEBDAV_PATH_4_0 = "/remote.php/dav";
public static final String STATUS_PATH = "/status.php";
public static final String FILES_WEB_PATH = "/index.php/apps/files";
private static final int MAX_REDIRECTIONS_COUNT = 3;
private static final int MAX_REPEAT_COUNT_WITH_FRESH_CREDENTIALS = 1;
private static final String PARAM_SINGLE_COOKIE_HEADER = "http.protocol.single-cookie-header";
private static final boolean PARAM_SINGLE_COOKIE_HEADER_VALUE = true;
private static final String PARAM_PROTOCOL_VERSION = "http.protocol.version";
private OwnCloudCredentials mCredentials = null;
private Uri mBaseUri;
public class Builder {
OwnCloudContext ocContext = new OwnCloudContext();
public Builder setCredentials(OwnCloudCredentials credentials) {
ocContext.mCredentials = credentials;
return this;
}
public Builder setBaseUri(Uri baseUri) {
ocContext.mBaseUri = baseUri;
return this;
}
public OwnCloudContext build() {
return ocContext;
}
}
public OwnCloudCredentials getCredentials() {
return mCredentials;
}
public Uri getBaseUri() {
return mBaseUri;
}
}

View File

@ -0,0 +1,50 @@
package com.owncloud.android.lib.refactor;
import com.owncloud.android.lib.refactor.RemoteOperation;
import java.util.Map;
import okhttp3.OkHttpClient;
import okhttp3.Request;
public abstract class RemoteOperation {
private final OwnCloudContext mContext;
private static OkHttpClient httpClient = null;
protected RemoteOperation(OwnCloudContext context) {
mContext = context;
if(httpClient == null) {
httpClient = new OkHttpClient.Builder()
.followRedirects(false)
.build();
}
}
public abstract RemoteOperationResult exec();
public OwnCloudContext getOCContext() {
return mContext;
}
public OkHttpClient getClient() {
return httpClient;
}
public Request.Builder getRequestBuilder() {
Request.Builder builder = new Request.Builder();
for(Map.Entry<String, String> header
: mContext.getCredentials().getCredentialHeaders().entrySet()) {
builder.addHeader(header.getKey(), header.getValue());
}
//TODO: Remove this part once SAML is obsolet
final String credentialCookie = mContext.getCredentials().getCredentialCookie();
if(credentialCookie == null) {
builder.addHeader("Cookie", credentialCookie);
}
return builder;
}
}

View File

@ -0,0 +1,523 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor;
import android.accounts.Account;
import android.accounts.AccountsException;
import com.owncloud.android.lib.refactor.utils.AccountUtils;
import com.owncloud.android.lib.refactor.exceptions.CertificateCombinedException;
import com.owncloud.android.lib.refactor.exceptions.OperationCancelledException;
import com.owncloud.android.lib.refactor.utils.ErrorMessageParser;
import com.owncloud.android.lib.refactor.utils.InvalidCharacterExceptionParser;
import org.apache.commons.httpclient.HttpStatus;
import org.json.JSONException;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.net.ssl.SSLException;
import at.bitfire.dav4android.exception.DavException;
import at.bitfire.dav4android.exception.HttpException;
import okhttp3.Headers;
import okhttp3.Request;
import okhttp3.Response;
/**
* The result of a remote operation required to an ownCloud server.
* <p/>
* Provides a common classification of remote operation results for all the
* application.
*
* @author David A. Velasco
*/
public class RemoteOperationResult implements Serializable {
/**
* Generated - should be refreshed every time the class changes!!
*/
private static final long serialVersionUID = 4968939884332372230L;
private static final String TAG = RemoteOperationResult.class.getSimpleName();
public enum ResultCode {
OK,
OK_SSL,
OK_NO_SSL,
UNHANDLED_HTTP_CODE,
UNAUTHORIZED,
FILE_NOT_FOUND,
INSTANCE_NOT_CONFIGURED,
UNKNOWN_ERROR,
WRONG_CONNECTION,
TIMEOUT,
INCORRECT_ADDRESS,
HOST_NOT_AVAILABLE,
NO_NETWORK_CONNECTION,
SSL_ERROR,
SSL_RECOVERABLE_PEER_UNVERIFIED,
BAD_OC_VERSION,
CANCELLED,
INVALID_LOCAL_FILE_NAME,
INVALID_OVERWRITE,
CONFLICT,
OAUTH2_ERROR,
SYNC_CONFLICT,
LOCAL_STORAGE_FULL,
LOCAL_STORAGE_NOT_MOVED,
LOCAL_STORAGE_NOT_COPIED,
OAUTH2_ERROR_ACCESS_DENIED,
QUOTA_EXCEEDED,
ACCOUNT_NOT_FOUND,
ACCOUNT_EXCEPTION,
ACCOUNT_NOT_NEW,
ACCOUNT_NOT_THE_SAME,
INVALID_CHARACTER_IN_NAME,
SHARE_NOT_FOUND,
LOCAL_STORAGE_NOT_REMOVED,
FORBIDDEN,
SHARE_FORBIDDEN,
SPECIFIC_FORBIDDEN,
OK_REDIRECT_TO_NON_SECURE_CONNECTION,
INVALID_MOVE_INTO_DESCENDANT,
INVALID_COPY_INTO_DESCENDANT,
PARTIAL_MOVE_DONE,
PARTIAL_COPY_DONE,
SHARE_WRONG_PARAMETER,
WRONG_SERVER_RESPONSE,
INVALID_CHARACTER_DETECT_IN_SERVER,
DELAYED_FOR_WIFI,
LOCAL_FILE_NOT_FOUND,
SERVICE_UNAVAILABLE,
SPECIFIC_SERVICE_UNAVAILABLE,
SPECIFIC_UNSUPPORTED_MEDIA_TYPE
}
private boolean mSuccess = false;
private int mHttpCode = -1;
private String mHttpPhrase = null;
private Exception mException = null;
private ResultCode mCode = ResultCode.UNKNOWN_ERROR;
private String mRedirectedLocation;
private ArrayList<String> mAuthenticate = new ArrayList<>();
private String mLastPermanentLocation = null;
private ArrayList<Object> mData;
/**
* Public constructor from result code.
*
* To be used when the caller takes the responsibility of interpreting the result of a {@link RemoteOperation}
*
* @param code {@link ResultCode} decided by the caller.
*/
public RemoteOperationResult(ResultCode code) {
mCode = code;
mSuccess = (code == ResultCode.OK || code == ResultCode.OK_SSL ||
code == ResultCode.OK_NO_SSL ||
code == ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION);
mData = null;
}
/**
* Public constructor from exception.
*
* To be used when an exception prevented the end of the {@link RemoteOperation}.
*
* Determines a {@link ResultCode} depending on the type of the exception.
*
* @param e Exception that interrupted the {@link RemoteOperation}
*/
public RemoteOperationResult(Exception e) {
mException = e;
if (e instanceof OperationCancelledException) {
mCode = ResultCode.CANCELLED;
} else if (e instanceof SocketException) {
mCode = ResultCode.WRONG_CONNECTION;
} else if (e instanceof SocketTimeoutException) {
mCode = ResultCode.TIMEOUT;
} else if (e instanceof SocketTimeoutException) {
mCode = ResultCode.TIMEOUT;
} else if (e instanceof MalformedURLException) {
mCode = ResultCode.INCORRECT_ADDRESS;
} else if (e instanceof UnknownHostException) {
mCode = ResultCode.HOST_NOT_AVAILABLE;
} else if (e instanceof AccountUtils.AccountNotFoundException) {
mCode = ResultCode.ACCOUNT_NOT_FOUND;
} else if (e instanceof AccountsException) {
mCode = ResultCode.ACCOUNT_EXCEPTION;
} else if (e instanceof SSLException || e instanceof RuntimeException) {
CertificateCombinedException se = getCertificateCombinedException(e);
if (se != null) {
mException = se;
if (se.isRecoverable()) {
mCode = ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED;
}
} else if (e instanceof RuntimeException) {
mCode = ResultCode.HOST_NOT_AVAILABLE;
} else {
mCode = ResultCode.SSL_ERROR;
}
} else if (e instanceof FileNotFoundException) {
mCode = ResultCode.LOCAL_FILE_NOT_FOUND;
} else {
mCode = ResultCode.UNKNOWN_ERROR;
}
}
/**
* Public constructor from separate elements of an HTTP or DAV response.
*
* To be used when the result needs to be interpreted from the response of an HTTP/DAV method.
*
* Determines a {@link ResultCode} from the already executed method received as a parameter. Generally,
* will depend on the HTTP code and HTTP response headers received. In some cases will inspect also the
* response body
*
* @param success
* @param request
* @param response
* @throws IOException
*/
public RemoteOperationResult(boolean success, Request request, Response response) throws IOException {
this(success, response.code(), HttpStatus.getStatusText(response.code()), response.headers());
if (mHttpCode == HttpStatus.SC_BAD_REQUEST) { // 400
String bodyResponse = response.body().string();
// do not get for other HTTP codes!; could not be available
if (bodyResponse != null && bodyResponse.length() > 0) {
InputStream is = new ByteArrayInputStream(bodyResponse.getBytes());
InvalidCharacterExceptionParser xmlParser = new InvalidCharacterExceptionParser();
try {
if (xmlParser.parseXMLResponse(is)) {
mCode = ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER;
}
} catch (Exception e) {
Log_OC.w(TAG, "Error reading exception from server: " + e.getMessage());
// mCode stays as set in this(success, httpCode, headers)
}
}
}
// before
switch (mHttpCode) {
case HttpStatus.SC_FORBIDDEN:
parseErrorMessageAndSetCode(request, response, ResultCode.SPECIFIC_FORBIDDEN);
break;
case HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE:
parseErrorMessageAndSetCode(request, response, ResultCode.SPECIFIC_UNSUPPORTED_MEDIA_TYPE);
break;
case HttpStatus.SC_SERVICE_UNAVAILABLE:
parseErrorMessageAndSetCode(request, response, ResultCode.SPECIFIC_SERVICE_UNAVAILABLE);
break;
default:
break;
}
}
/**
* Parse the error message included in the body response, if any, and set the specific result
* code
*/
/**
* Parse the error message included in the body response, if any, and set the specific result
* code
*
* @param request okHttp request
* @param response okHttp respnse
* @param resultCode our own custom result code
* @throws IOException
*/
private void parseErrorMessageAndSetCode(Request request, Response response, ResultCode resultCode)
throws IOException {
String bodyResponse = response.body().string();
if (bodyResponse != null && bodyResponse.length() > 0) {
InputStream is = new ByteArrayInputStream(bodyResponse.getBytes());
ErrorMessageParser xmlParser = new ErrorMessageParser();
try {
String errorMessage = xmlParser.parseXMLResponse(is);
if (errorMessage != "" && errorMessage != null) {
mCode = resultCode;
mHttpPhrase = errorMessage;
}
} catch (Exception e) {
Log_OC.w(TAG, "Error reading exception from server: " + e.getMessage());
// mCode stays as set in this(success, httpCode, headers)
}
}
}
/**
* Public constructor from separate elements of an HTTP or DAV response.
*
* To be used when the result needs to be interpreted from HTTP response elements that could come from
* different requests (WARNING: black magic, try to avoid).
*
* Determines a {@link ResultCode} depending on the HTTP code and HTTP response headers received.
*
* @param success The operation was considered successful or not.
* @param httpCode HTTP status code returned by an HTTP/DAV method.
* @param httpPhrase HTTP status line phrase returned by an HTTP/DAV method
* @param headers HTTP response header returned by an HTTP/DAV method
*/
public RemoteOperationResult(boolean success, int httpCode, String httpPhrase, Headers headers) {
this(success, httpCode, httpPhrase);
for (Map.Entry<String, List<String>> header : headers.toMultimap().entrySet()) {
if ("location".equals(header.getKey().toLowerCase())) {
mRedirectedLocation = header.getValue().get(0);
continue;
}
if ("www-authenticate".equals(header.getKey().toLowerCase())) {
mAuthenticate.add(header.getValue().get(0).toLowerCase());
}
}
if (isIdPRedirection()) {
mCode = ResultCode.UNAUTHORIZED; // overrides default ResultCode.UNKNOWN
}
}
/**
* Private constructor for results built interpreting a HTTP or DAV response.
*
* Determines a {@link ResultCode} depending of the type of the exception.
*
* @param success Operation was successful or not.
* @param httpCode HTTP status code returned by the HTTP/DAV method.
* @param httpPhrase HTTP status line phrase returned by the HTTP/DAV method
*/
private RemoteOperationResult(boolean success, int httpCode, String httpPhrase) {
mSuccess = success;
mHttpCode = httpCode;
mHttpPhrase = httpPhrase;
mCode = success
? ResultCode.OK
: getCodeFromStatus(httpCode);
}
private ResultCode getCodeFromStatus(int status) {
switch (status) {
case HttpStatus.SC_UNAUTHORIZED: return ResultCode.UNAUTHORIZED;
case HttpStatus.SC_FORBIDDEN: return ResultCode.FORBIDDEN;
case HttpStatus.SC_NOT_FOUND: return ResultCode.FILE_NOT_FOUND;
case HttpStatus.SC_CONFLICT: return ResultCode.CONFLICT;
case HttpStatus.SC_INTERNAL_SERVER_ERROR: return ResultCode.INSTANCE_NOT_CONFIGURED;
case HttpStatus.SC_SERVICE_UNAVAILABLE: return ResultCode.SERVICE_UNAVAILABLE;
case HttpStatus.SC_INSUFFICIENT_STORAGE: return ResultCode.QUOTA_EXCEEDED;
default:
Log_OC.d(TAG,
"RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " +
mHttpCode + " " + mHttpPhrase
);
return ResultCode.UNHANDLED_HTTP_CODE;
}
}
public void setData(ArrayList<Object> files) {
mData = files;
}
public ArrayList<Object> getData() {
return mData;
}
public boolean isSuccess() {
return mSuccess;
}
public boolean isCancelled() {
return mCode == ResultCode.CANCELLED;
}
public int getHttpCode() {
return mHttpCode;
}
public String getHttpPhrase() {
return mHttpPhrase;
}
public ResultCode getCode() {
return mCode;
}
public Exception getException() {
return mException;
}
public boolean isSslRecoverableException() {
return mCode == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED;
}
public boolean isRedirectToNonSecureConnection() {
return mCode == ResultCode.OK_REDIRECT_TO_NON_SECURE_CONNECTION;
}
private CertificateCombinedException getCertificateCombinedException(Exception e) {
CertificateCombinedException result = null;
if (e instanceof CertificateCombinedException) {
return (CertificateCombinedException) e;
}
Throwable cause = mException.getCause();
Throwable previousCause = null;
while (cause != null && cause != previousCause &&
!(cause instanceof CertificateCombinedException)) {
previousCause = cause;
cause = cause.getCause();
}
if (cause != null && cause instanceof CertificateCombinedException) {
result = (CertificateCombinedException) cause;
}
return result;
}
public String getLogMessage() {
if (mException != null) {
if(mException instanceof OperationCancelledException)
return "Operation cancelled by the caller";
if(mException instanceof SocketException) return "Socket exception";
if(mException instanceof SocketTimeoutException) return "Socket timeout exception";
if(mException instanceof MalformedURLException) return "Malformed URL exception";
if(mException instanceof UnknownHostException) return "Unknown host exception";
if(mException instanceof CertificateCombinedException) {
if (((CertificateCombinedException) mException).isRecoverable())
return "SSL recoverable exception";
else
return "SSL exception";
}
if(mException instanceof SSLException) return "SSL exception";
if(mException instanceof DavException) return "Unexpected WebDAV exception";
if(mException instanceof HttpException) return "HTTP violation";
if(mException instanceof IOException) return "Unrecovered transport exception";
if(mException instanceof AccountUtils.AccountNotFoundException) {
Account failedAccount =
((AccountUtils.AccountNotFoundException) mException).getFailedAccount();
return mException.getMessage() + " (" +
(failedAccount != null ? failedAccount.name : "NULL") + ")";
}
if (mException instanceof AccountsException) return "Exception while using account";
if (mException instanceof JSONException) return "JSON exception";
return "Unexpected exception";
}
if(mCode == ResultCode.INSTANCE_NOT_CONFIGURED)
return "The ownCloud server is not configured!";
if(mCode == ResultCode.NO_NETWORK_CONNECTION) return "No network connection";
if(mCode == ResultCode.BAD_OC_VERSION)
return "No valid ownCloud version was found at the server";
if(mCode == ResultCode.LOCAL_STORAGE_FULL) return "Local storage full";
if(mCode == ResultCode.LOCAL_STORAGE_NOT_MOVED)
return "Error while moving file to final directory";
if(mCode == ResultCode.ACCOUNT_NOT_NEW)
return "Account already existing when creating a new one";
if(mCode == ResultCode.INVALID_CHARACTER_IN_NAME)
return "The file name contains an forbidden character";
if(mCode == ResultCode.FILE_NOT_FOUND) return "Local file does not exist";
if(mCode == ResultCode.SYNC_CONFLICT) return "Synchronization conflict";
return "Operation finished with HTTP status code " + mHttpCode + " (" +
(isSuccess() ? "success" : "fail") + ")";
}
public boolean isServerFail() {
return (mHttpCode >= HttpStatus.SC_INTERNAL_SERVER_ERROR);
}
public boolean isException() {
return (mException != null);
}
public boolean isTemporalRedirection() {
return (mHttpCode == 302 || mHttpCode == 307);
}
public String getRedirectedLocation() {
return mRedirectedLocation;
}
public boolean isIdPRedirection() {
return (mRedirectedLocation != null &&
(mRedirectedLocation.toUpperCase().contains("SAML") ||
mRedirectedLocation.toLowerCase().contains("wayf")));
}
/**
* Checks if is a non https connection
*
* @return boolean true/false
*/
public boolean isNonSecureRedirection() {
return (mRedirectedLocation != null && !(mRedirectedLocation.toLowerCase().startsWith("https://")));
}
public ArrayList<String> getAuthenticateHeaders() {
return mAuthenticate;
}
public String getLastPermanentLocation() {
return mLastPermanentLocation;
}
public void setLastPermanentLocation(String lastPermanentLocation) {
mLastPermanentLocation = lastPermanentLocation;
}
}

View File

@ -0,0 +1,44 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.authentication;
import java.util.HashMap;
import java.util.Map;
public interface OwnCloudCredentials {
Map<String, String> getCredentialHeaders();
//TODO: Remove this once SAML is obsolet
default String getCredentialCookie() {
return null;
}
String getUsername();
String getAuthToken();
boolean authTokenCanBeRefreshed();
}

View File

@ -0,0 +1,29 @@
package com.owncloud.android.lib.refactor.authentication.credentials;
import com.owncloud.android.lib.refactor.authentication.OwnCloudCredentials;
import java.util.HashMap;
import java.util.Map;
public class OwnCloudAnonymousCredentials implements OwnCloudCredentials {
@Override
public Map<String, String> getCredentialHeaders() {
return new HashMap<>(0);
}
@Override
public String getUsername() {
return "";
}
@Override
public String getAuthToken() {
return null;
}
@Override
public boolean authTokenCanBeRefreshed() {
return false;
}
}

View File

@ -0,0 +1,66 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.authentication.credentials;
import com.owncloud.android.lib.refactor.authentication.OwnCloudCredentials;
import java.util.HashMap;
import java.util.Map;
import okhttp3.Authenticator;
import okhttp3.Credentials;
public class OwnCloudBasicCredentials implements OwnCloudCredentials {
private String mUsername;
private String mPassword;
public OwnCloudBasicCredentials(String username, String password) {
mUsername = username != null ? username : "";
mPassword = password != null ? password : "";
}
@Override
public Map<String, String> getCredentialHeaders() {
HashMap<String, String> header = new HashMap<>(1);
header.put("Authorization", Credentials.basic(mUsername, mPassword));
return header;
}
@Override
public String getUsername() {
return mUsername;
}
@Override
public String getAuthToken() {
return mPassword;
}
@Override
public boolean authTokenCanBeRefreshed() {
return false;
}
}

View File

@ -0,0 +1,69 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.authentication.credentials;
import com.owncloud.android.lib.refactor.authentication.OwnCloudCredentials;
import java.util.HashMap;
import java.util.Map;
import okhttp3.Authenticator;
public class OwnCloudBearerCredentials implements OwnCloudCredentials {
private String mUsername;
private String mAccessToken;
public OwnCloudBearerCredentials(String username, String accessToken) {
mUsername = username != null ? username : "";
mAccessToken = accessToken != null ? accessToken : "";
}
@Override
public Map<String, String> getCredentialHeaders() {
HashMap<String, String> header = new HashMap<>(1);
header.put("Authorization", "Bearer " + mAccessToken);
return header;
}
@Override
public String getUsername() {
// not relevant for authentication, but relevant for informational purposes
return mUsername;
}
@Override
public String getAuthToken() {
return mAccessToken;
}
@Override
public boolean authTokenCanBeRefreshed() {
return true;
}
}

View File

@ -0,0 +1,90 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.authentication.credentials;
import android.net.Uri;
import com.owncloud.android.lib.refactor.authentication.OwnCloudCredentials;
import org.apache.commons.httpclient.Cookie;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class OwnCloudSamlSsoCredentials implements OwnCloudCredentials {
private final String mUsername;
private final String mSessionCookie;
private final Uri mBaseUrl;
public OwnCloudSamlSsoCredentials(String username, String sessionCookie, Uri baseUrl) {
mUsername = username != null ? username : "";
mSessionCookie = sessionCookie != null ? sessionCookie : "";
mBaseUrl = baseUrl;
}
@Override
public String getCredentialCookie() {
String[] rawCookies = mSessionCookie.split(";");
StringBuilder processedCookies = new StringBuilder();
Cookie cookie = null;
for (final String rawCookie : rawCookies) {
int equalPos = rawCookie.indexOf('=');
if (equalPos >= 0) {
cookie = new Cookie();
cookie.setName(rawCookie.substring(0, equalPos));
cookie.setValue(rawCookie.substring(equalPos + 1));
cookie.setDomain(mBaseUrl.getHost()); // VERY IMPORTANT
cookie.setPath(mBaseUrl.getPath()); // VERY IMPORTANT
processedCookies.append(cookie.toExternalForm() + ";");
}
}
return processedCookies.toString();
}
@Override
public Map<String, String> getCredentialHeaders() {
return new HashMap<>(0);
}
@Override
public String getUsername() {
// not relevant for authentication, but relevant for informational purposes
return mUsername;
}
@Override
public String getAuthToken() {
return mSessionCookie;
}
@Override
public boolean authTokenCanBeRefreshed() {
return false;
}
}

View File

@ -0,0 +1,261 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.authentication.oauth;
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.auth.AuthChallengeParser;
import org.apache.commons.httpclient.auth.AuthScheme;
import org.apache.commons.httpclient.auth.AuthenticationException;
import org.apache.commons.httpclient.auth.InvalidCredentialsException;
import org.apache.commons.httpclient.auth.MalformedChallengeException;
import java.util.Map;
/**
* Bearer authentication scheme as defined in RFC 6750.
*
* @author David A. Velasco
*/
public class BearerAuthScheme implements AuthScheme /*extends RFC2617Scheme*/ {
private static final String TAG = BearerAuthScheme.class.getSimpleName();
public static final String AUTH_POLICY = "Bearer";
/** Whether the bearer authentication process is complete */
private boolean mComplete;
/** Authentication parameter map */
@SuppressWarnings("rawtypes")
private Map mParams = null;
/**
* Default constructor for the bearer authentication scheme.
*/
public BearerAuthScheme() {
mComplete = false;
}
/**
* Constructor for the basic authentication scheme.
*
* @param challenge Authentication challenge
*
* @throws MalformedChallengeException Thrown if the authentication challenge is malformed
*/
public BearerAuthScheme(final String challenge) throws MalformedChallengeException {
processChallenge(challenge);
mComplete = true;
}
/**
* Returns textual designation of the bearer authentication scheme.
*
* @return "Bearer"
*/
public String getSchemeName() {
return "bearer";
}
/**
* Processes the Bearer challenge.
*
* @param challenge The challenge string
*
* @throws MalformedChallengeException Thrown if the authentication challenge is malformed
*/
public void processChallenge(String challenge) throws MalformedChallengeException {
String s = AuthChallengeParser.extractScheme(challenge);
if (!s.equalsIgnoreCase(getSchemeName())) {
throw new MalformedChallengeException(
"Invalid " + getSchemeName() + " challenge: " + challenge);
}
mParams = AuthChallengeParser.extractParams(challenge);
mComplete = true;
}
/**
* Tests if the Bearer authentication process has been completed.
*
* @return 'true' if Bearer authorization has been processed, 'false' otherwise.
*/
public boolean isComplete() {
return this.mComplete;
}
/**
* Produces bearer authorization string for the given set of
* {@link Credentials}.
*
* @param credentials The set of credentials to be used for authentication
* @param method Method name is ignored by the bearer authentication scheme
* @param uri URI is ignored by the bearer authentication scheme
* @throws InvalidCredentialsException If authentication credentials are not valid or not applicable
* for this authentication scheme
* @throws AuthenticationException If authorization string cannot be generated due to an authentication failure
* @return A bearer authorization string
*/
public String authenticate(Credentials credentials, String method, String uri) throws AuthenticationException {
BearerCredentials bearer;
try {
bearer = (BearerCredentials) credentials;
} catch (ClassCastException e) {
throw new InvalidCredentialsException(
"Credentials cannot be used for bearer authentication: "
+ credentials.getClass().getName());
}
return BearerAuthScheme.authenticate(bearer);
}
/**
* Returns 'false'. Bearer authentication scheme is request based.
*
* @return 'false'.
*/
public boolean isConnectionBased() {
return false;
}
/**
* Produces bearer authorization string for the given set of {@link Credentials}.
*
* @param credentials The set of credentials to be used for authentication
* @param method The method being authenticated
* @throws InvalidCredentialsException If authentication credentials are not valid or not applicable for this authentication
* scheme.
* @throws AuthenticationException If authorization string cannot be generated due to an authentication failure.
*
* @return a basic authorization string
*/
public String authenticate(Credentials credentials, HttpMethod method) throws AuthenticationException {
if (method == null) {
throw new IllegalArgumentException("Method may not be null");
}
BearerCredentials bearer = null;
try {
bearer = (BearerCredentials) credentials;
} catch (ClassCastException e) {
throw new InvalidCredentialsException(
"Credentials cannot be used for bearer authentication: "
+ credentials.getClass().getName());
}
return BearerAuthScheme.authenticate(
bearer,
method.getParams().getCredentialCharset());
}
/**
* Returns a bearer Authorization header value for the given
* {@link BearerCredentials}.
*
* @param credentials The credentials to encode.
*
* @return A bearer authorization string
*/
public static String authenticate(BearerCredentials credentials) {
return authenticate(credentials, "ISO-8859-1");
}
/**
* Returns a bearer Authorization header value for the given
* {@link BearerCredentials} and charset.
*
* @param credentials The credentials to encode.
* @param charset The charset to use for encoding the credentials
*
* @return A bearer authorization string
*
* @since 3.0
*/
public static String authenticate(BearerCredentials credentials, String charset) {
if (credentials == null) {
throw new IllegalArgumentException("Credentials may not be null");
}
if (charset == null || charset.length() == 0) {
throw new IllegalArgumentException("charset may not be null or empty");
}
StringBuffer buffer = new StringBuffer();
buffer.append(credentials.getAccessToken());
return "Bearer " + buffer.toString();
}
/**
* Returns a String identifying the authentication challenge. This is
* used, in combination with the host and port to determine if
* authorization has already been attempted or not. Schemes which
* require multiple requests to complete the authentication should
* return a different value for each stage in the request.
*
* Additionally, the ID should take into account any changes to the
* authentication challenge and return a different value when appropriate.
* For example when the realm changes in basic authentication it should be
* considered a different authentication attempt and a different value should
* be returned.
*
* This method simply returns the realm for the challenge.
*
* @return String a String identifying the authentication challenge.
*/
@Override
public String getID() {
return getRealm();
}
/**
* Returns authentication parameter with the given name, if available.
*
* @param name The name of the parameter to be returned
*
* @return The parameter with the given name
*/
@Override
public String getParameter(String name) {
if (name == null) {
throw new IllegalArgumentException("Parameter name may not be null");
}
if (mParams == null) {
return null;
}
return (String) mParams.get(name.toLowerCase());
}
/**
* Returns authentication realm. The realm may not be null.
*
* @return The authentication realm
*/
@Override
public String getRealm() {
return getParameter("realm");
}
}

View File

@ -0,0 +1,102 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.authentication.oauth;
import org.apache.commons.httpclient.util.LangUtils;
/**
*
* @author David A. Velasco
*/
public class BearerCredentials {
private String mAccessToken;
/**
* The constructor with the bearer token
*
* @param token The bearer token
*/
public BearerCredentials(String token) {
/*if (token == null) {
throw new IllegalArgumentException("Bearer token may not be null");
}*/
mAccessToken = (token == null) ? "" : token;
}
/**
* Returns the access token
*
* @return The access token
*/
public String getAccessToken() {
return mAccessToken;
}
/**
* Get this object string.
*
* @return The access token
*/
public String toString() {
return mAccessToken;
}
/**
* Does a hash of the access token.
*
* @return The hash code of the access token
*/
public int hashCode() {
int hash = LangUtils.HASH_SEED;
hash = LangUtils.hashCode(hash, mAccessToken);
return hash;
}
/**
* These credentials are assumed equal if accessToken is the same.
*
* @param o The other object to compare with.
*
* @return 'True' if the object is equivalent.
*/
public boolean equals(Object o) {
if (o == null) return false;
if (this == o) return true;
if (this.getClass().equals(o.getClass())) {
BearerCredentials that = (BearerCredentials) o;
if (LangUtils.equals(mAccessToken, that.mAccessToken)) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,55 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.authentication.oauth;
public class OAuth2ClientConfiguration {
private String mClientId;
private String mClientSecret;
private String mRedirectUri;
public OAuth2ClientConfiguration(String clientId, String clientSecret, String redirectUri) {
mClientId = (clientId == null) ? "" : clientId;
mClientSecret = (clientSecret == null) ? "" : clientSecret;
mRedirectUri = (redirectUri == null) ? "" : redirectUri;
}
public String getClientId() {
return mClientId;
}
public String getClientSecret() {
return mClientSecret;
}
public String getRedirectUri() {
return mRedirectUri;
}
}

View File

@ -0,0 +1,68 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.authentication.oauth;
/**
* Constant values for OAuth 2 protocol.
*
* Includes required and optional parameter NAMES used in the 'authorization code' grant type.
*/
public class OAuth2Constants {
/// Parameters to send to the Authorization Endpoint
public static final String KEY_RESPONSE_TYPE = "response_type";
public static final String KEY_REDIRECT_URI = "redirect_uri";
public static final String KEY_CLIENT_ID = "client_id";
public static final String KEY_SCOPE = "scope";
public static final String KEY_STATE = "state";
/// Additional parameters to send to the Token Endpoint
public static final String KEY_GRANT_TYPE = "grant_type";
public static final String KEY_CODE = "code";
// Used to get the Access Token using Refresh Token
public static final String OAUTH2_REFRESH_TOKEN_GRANT_TYPE = "refresh_token";
/// Parameters received in an OK response from the Token Endpoint
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";
/// Parameters in an ERROR response
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 VALUE_ERROR_ACCESS_DENIED = "access_denied";
/// Extra not standard
public static final String KEY_USER_ID = "user_id";
/// Depends on oauth2 grant type
public static final String OAUTH2_RESPONSE_TYPE_CODE = "code";
}

View File

@ -0,0 +1,46 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.authentication.oauth;
public enum OAuth2GrantType {
AUTHORIZATION_CODE("authorization_code"),
IMPLICIT("implicit"),
PASSWORD("password"),
CLIENT_CREDENTIAL("client_credentials"),
REFRESH_TOKEN("refresh_token") // not a grant type conceptually, but used as such to refresh access tokens
;
private String mValue;
OAuth2GrantType(String value) {
mValue = value;
}
public String getValue() {
return mValue;
}
}

View File

@ -0,0 +1,66 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.authentication.oauth;
public interface OAuth2Provider {
/**
* {@link OAuth2RequestBuilder} implementation for this provider.
*
* @return {@link OAuth2RequestBuilder} implementation.
*/
OAuth2RequestBuilder getOperationBuilder();
/**
* Set configuration of the client that will use this {@link OAuth2Provider}
* @param oAuth2ClientConfiguration Configuration of the client that will use this {@link OAuth2Provider}
*/
void setClientConfiguration(OAuth2ClientConfiguration oAuth2ClientConfiguration);
/**
* Configuration of the client that is using this {@link OAuth2Provider}
* return Configuration of the client that is usinng this {@link OAuth2Provider}
*/
OAuth2ClientConfiguration getClientConfiguration();
/**
* Set base URI to authorization server.
*
* @param authorizationServerUri Set base URL to authorization server.
*/
void setAuthorizationServerUri(String authorizationServerUri);
/**
* base URI to authorization server.
*
* @return Base URL to authorization server.
*/
String getAuthorizationServerUri();
}

View File

@ -0,0 +1,122 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.authentication.oauth;
import java.util.HashMap;
import java.util.Map;
public class OAuth2ProvidersRegistry {
private Map<String, OAuth2Provider> mProviders = new HashMap<>();
private OAuth2Provider mDefaultProvider = null;
private OAuth2ProvidersRegistry () {
}
/**
* See https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom
*/
private static class LazyHolder {
private static final OAuth2ProvidersRegistry INSTANCE = new OAuth2ProvidersRegistry();
}
/**
* Singleton accesor.
*
* @return Singleton isntance of {@link OAuth2ProvidersRegistry}
*/
public static OAuth2ProvidersRegistry getInstance() {
return LazyHolder.INSTANCE;
}
/**
* Register an {@link OAuth2Provider} with the name passed as parameter.
*
* @param name Name to bind 'oAuthProvider' in the registry.
* @param oAuth2Provider An {@link OAuth2Provider} instance to keep in the registry.
* @throws IllegalArgumentException if 'name' or 'oAuthProvider' are null.
*/
public void registerProvider(String name, OAuth2Provider oAuth2Provider) {
if (name == null) {
throw new IllegalArgumentException("Name must not be NULL");
}
if (oAuth2Provider == null) {
throw new IllegalArgumentException("oAuth2Provider must not be NULL");
}
mProviders.put(name, oAuth2Provider);
if (mProviders.size() == 1) {
mDefaultProvider = oAuth2Provider;
}
}
public OAuth2Provider unregisterProvider(String name) {
OAuth2Provider unregisteredProvider = mProviders.remove(name);
if (mProviders.size() == 0) {
mDefaultProvider = null;
} else if (unregisteredProvider != null && unregisteredProvider == mDefaultProvider) {
mDefaultProvider = mProviders.values().iterator().next();
}
return unregisteredProvider;
}
/**
* Get default {@link OAuth2Provider}.
*
* @return Default provider, or NULL if there is no provider.
*/
public OAuth2Provider getProvider() {
return mDefaultProvider;
}
/**
* Get {@link OAuth2Provider} registered with the name passed as parameter.
*
* @param name Name used to register the desired {@link OAuth2Provider}
* @return {@link OAuth2Provider} registered with the name 'name'
*/
public OAuth2Provider getProvider(String name) {
return mProviders.get(name);
}
/**
* Sets the {@link OAuth2Provider} registered with the name passed as parameter as the default provider
*
* @param name Name used to register the {@link OAuth2Provider} to set as default.
* @return {@link OAuth2Provider} set as default, or NULL if no provider was registered with 'name'.
*/
public OAuth2Provider setDefaultProvider(String name) {
OAuth2Provider toDefault = mProviders.get(name);
if (toDefault != null) {
mDefaultProvider = toDefault;
}
return toDefault;
}
}

View File

@ -0,0 +1,75 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.authentication.oauth;
import com.owncloud.android.lib.refactor.Log_OC;
import java.util.HashMap;
import java.util.Map;
public class OAuth2QueryParser {
private static final String TAG = OAuth2QueryParser.class.getName();
private Map<String, String> mOAuth2ParsedAuthorizationResponse;
public OAuth2QueryParser() {
mOAuth2ParsedAuthorizationResponse = new HashMap<>();
}
public Map<String, String> parse(String query) {
mOAuth2ParsedAuthorizationResponse.clear();
if (query != null) {
String[] pairs = query.split("&");
int i = 0;
String key = "";
String value;
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;
} else if (j == 1) {
value = p;
mOAuth2ParsedAuthorizationResponse.put(key, value);
}
Log_OC.v(TAG, "[" + i + "," + j + "] = " + p);
j++;
}
i++;
}
}
return mOAuth2ParsedAuthorizationResponse;
}
}

View File

@ -0,0 +1,48 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.authentication.oauth;
import com.owncloud.android.lib.refactor.RemoteOperation;
public interface OAuth2RequestBuilder {
enum OAuthRequest {
GET_AUTHORIZATION_CODE, CREATE_ACCESS_TOKEN, REFRESH_ACCESS_TOKEN
}
void setRequest(OAuthRequest operation);
void setGrantType(OAuth2GrantType grantType);
void setAuthorizationCode(String code);
void setRefreshToken(String refreshToken);
RemoteOperation buildOperation();
String buildUri();
}

View File

@ -0,0 +1,77 @@
/**
* ownCloud Android client application
*
* @author David A. Velasco
*
* Copyright (C) 2017 ownCloud GmbH.
*
* 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.lib.refactor.authentication.oauth;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
public class OAuth2ResponseParser {
public Map<String, String> parseAccessTokenResult(JSONObject tokenJson) throws JSONException {
Map<String, String> resultTokenMap = new HashMap<>();
if (tokenJson.has(OAuth2Constants.KEY_ACCESS_TOKEN)) {
resultTokenMap.put(OAuth2Constants.KEY_ACCESS_TOKEN, tokenJson.
getString(OAuth2Constants.KEY_ACCESS_TOKEN));
}
if (tokenJson.has(OAuth2Constants.KEY_TOKEN_TYPE)) {
resultTokenMap.put(OAuth2Constants.KEY_TOKEN_TYPE, tokenJson.
getString(OAuth2Constants.KEY_TOKEN_TYPE));
}
if (tokenJson.has(OAuth2Constants.KEY_EXPIRES_IN)) {
resultTokenMap.put(OAuth2Constants.KEY_EXPIRES_IN, tokenJson.
getString(OAuth2Constants.KEY_EXPIRES_IN));
}
if (tokenJson.has(OAuth2Constants.KEY_REFRESH_TOKEN)) {
resultTokenMap.put(OAuth2Constants.KEY_REFRESH_TOKEN, tokenJson.
getString(OAuth2Constants.KEY_REFRESH_TOKEN));
}
if (tokenJson.has(OAuth2Constants.KEY_SCOPE)) {
resultTokenMap.put(OAuth2Constants.KEY_SCOPE, tokenJson.
getString(OAuth2Constants.KEY_SCOPE));
}
if (tokenJson.has(OAuth2Constants.KEY_ERROR)) {
resultTokenMap.put(OAuth2Constants.KEY_ERROR, tokenJson.
getString(OAuth2Constants.KEY_ERROR));
}
if (tokenJson.has(OAuth2Constants.KEY_ERROR_DESCRIPTION)) {
resultTokenMap.put(OAuth2Constants.KEY_ERROR_DESCRIPTION, tokenJson.
getString(OAuth2Constants.KEY_ERROR_DESCRIPTION));
}
if (tokenJson.has(OAuth2Constants.KEY_ERROR_URI)) {
resultTokenMap.put(OAuth2Constants.KEY_ERROR_URI, tokenJson.
getString(OAuth2Constants.KEY_ERROR_URI));
}
if (tokenJson.has(OAuth2Constants.KEY_USER_ID)) { // not standard
resultTokenMap.put(OAuth2Constants.KEY_USER_ID, tokenJson.
getString(OAuth2Constants.KEY_USER_ID));
}
return resultTokenMap;
}
}

View File

@ -0,0 +1,94 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.authentication.oauth;
import com.owncloud.android.lib.refactor.Log_OC;
public class OwnCloudOAuth2Provider implements OAuth2Provider {
public static final String NAME = OAuth2Provider.class.getName();
public static final String ACCESS_TOKEN_ENDPOINT_PATH = "index.php/apps/oauth2/api/v1/token";
private static final String AUTHORIZATION_CODE_ENDPOINT_PATH = "index.php/apps/oauth2/authorize";
private String mAuthorizationServerUrl = "";
private String mAccessTokenEndpointPath = ACCESS_TOKEN_ENDPOINT_PATH;
private String mAuthorizationCodeEndpointPath = AUTHORIZATION_CODE_ENDPOINT_PATH;
private OAuth2ClientConfiguration mClientConfiguration;
@Override
public OAuth2RequestBuilder getOperationBuilder() {
return new OwnCloudOAuth2RequestBuilder(this);
}
@Override
public void setClientConfiguration(OAuth2ClientConfiguration oAuth2ClientConfiguration) {
mClientConfiguration = oAuth2ClientConfiguration;
}
@Override
public OAuth2ClientConfiguration getClientConfiguration() {
return mClientConfiguration;
}
@Override
public void setAuthorizationServerUri(String authorizationServerUri) {
mAuthorizationServerUrl = authorizationServerUri;
}
@Override
public String getAuthorizationServerUri() {
return mAuthorizationServerUrl;
}
public String getAccessTokenEndpointPath() {
return mAccessTokenEndpointPath;
}
public void setAccessTokenEndpointPath(String accessTokenEndpointPath) {
if (accessTokenEndpointPath == null || accessTokenEndpointPath.length() <= 0) {
Log_OC.w(NAME, "Setting invalid access token endpoint path, going on with default");
mAccessTokenEndpointPath = ACCESS_TOKEN_ENDPOINT_PATH;
} else {
mAccessTokenEndpointPath = accessTokenEndpointPath;
}
}
public String getAuthorizationCodeEndpointPath() {
return mAuthorizationCodeEndpointPath;
}
public void setAuthorizationCodeEndpointPath(String authorizationCodeEndpointPath) {
if (authorizationCodeEndpointPath == null || authorizationCodeEndpointPath.length() <= 0) {
Log_OC.w(NAME, "Setting invalid authorization code endpoint path, going on with default");
mAuthorizationCodeEndpointPath = AUTHORIZATION_CODE_ENDPOINT_PATH;
} else {
mAuthorizationCodeEndpointPath = authorizationCodeEndpointPath;
}
}
}

View File

@ -0,0 +1,153 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.authentication.oauth;
import android.net.Uri;
import com.owncloud.android.lib.refactor.OwnCloudContext;
import com.owncloud.android.lib.refactor.RemoteOperation;
import com.owncloud.android.lib.refactor.authentication.oauth.operations.OAuth2GetAccessTokenOperation;
import com.owncloud.android.lib.refactor.authentication.oauth.operations.OAuth2RefreshAccessTokenOperation;
public class OwnCloudOAuth2RequestBuilder implements OAuth2RequestBuilder {
private OwnCloudContext ocContext;
private OwnCloudOAuth2Provider mOAuth2Provider;
private OAuthRequest mRequest;
private OAuth2GrantType mGrantType = OAuth2GrantType.AUTHORIZATION_CODE;
private String mCode;
private String mRefreshToken;
public OwnCloudOAuth2RequestBuilder(OwnCloudOAuth2Provider ownCloudOAuth2Provider) {
mOAuth2Provider = ownCloudOAuth2Provider;
}
@Override
public void setRequest(OAuthRequest request) {
mRequest = request;
}
@Override
public void setGrantType(OAuth2GrantType grantType) {
mGrantType = grantType;
}
@Override
public void setAuthorizationCode(String code) {
mCode = code;
}
@Override
public void setRefreshToken(String refreshToken) {
mRefreshToken = refreshToken;
}
public void setOcContext(OwnCloudContext ocContext) {
this.ocContext = ocContext;
}
@Override
public RemoteOperation buildOperation() {
if (mGrantType != OAuth2GrantType.AUTHORIZATION_CODE &&
mGrantType != OAuth2GrantType.REFRESH_TOKEN) {
throw new UnsupportedOperationException(
"Unsupported grant type. Only " +
OAuth2GrantType.AUTHORIZATION_CODE.getValue() + " and " +
OAuth2GrantType.REFRESH_TOKEN + " are supported");
}
OAuth2ClientConfiguration clientConfiguration = mOAuth2Provider.getClientConfiguration();
switch(mRequest) {
case CREATE_ACCESS_TOKEN:
return new OAuth2GetAccessTokenOperation(
ocContext,
mGrantType.getValue(),
mCode,
clientConfiguration.getClientId(),
clientConfiguration.getClientSecret(),
clientConfiguration.getRedirectUri(),
mOAuth2Provider.getAccessTokenEndpointPath());
case REFRESH_ACCESS_TOKEN:
return new OAuth2RefreshAccessTokenOperation(
ocContext,
clientConfiguration.getClientId(),
clientConfiguration.getClientSecret(),
mRefreshToken,
mOAuth2Provider.getAccessTokenEndpointPath());
default:
throw new UnsupportedOperationException("Unsupported request");
}
}
@Override
public String buildUri() {
if (OAuth2GrantType.AUTHORIZATION_CODE != mGrantType) {
throw new UnsupportedOperationException(
"Unsupported grant type. Only " +
OAuth2GrantType.AUTHORIZATION_CODE.getValue() + " is supported by this provider"
);
}
OAuth2ClientConfiguration clientConfiguration = mOAuth2Provider.getClientConfiguration();
Uri uri;
Uri.Builder uriBuilder;
switch(mRequest) {
case GET_AUTHORIZATION_CODE:
uri = Uri.parse(mOAuth2Provider.getAuthorizationServerUri());
uriBuilder = uri.buildUpon();
uriBuilder.appendEncodedPath(mOAuth2Provider.getAuthorizationCodeEndpointPath());
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_RESPONSE_TYPE, OAuth2Constants.OAUTH2_RESPONSE_TYPE_CODE);
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_REDIRECT_URI, clientConfiguration.getRedirectUri());
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_CLIENT_ID, clientConfiguration.getClientId());
uri = uriBuilder.build();
return uri.toString();
case CREATE_ACCESS_TOKEN:
uri = Uri.parse(mOAuth2Provider.getAuthorizationServerUri());
uriBuilder = uri.buildUpon();
uriBuilder.appendEncodedPath(mOAuth2Provider.getAccessTokenEndpointPath());
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_RESPONSE_TYPE, OAuth2Constants.OAUTH2_RESPONSE_TYPE_CODE);
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_REDIRECT_URI, clientConfiguration.getRedirectUri());
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_CLIENT_ID, clientConfiguration.getClientId());
uri = uriBuilder.build();
return uri.toString();
default:
throw new UnsupportedOperationException("Unsupported request");
}
}
}

View File

@ -0,0 +1,136 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.authentication.oauth.operations;
import android.net.Uri;
import com.owncloud.android.lib.refactor.OwnCloudContext;
import com.owncloud.android.lib.refactor.RemoteOperationResult;
import com.owncloud.android.lib.refactor.authentication.oauth.OAuth2Constants;
import com.owncloud.android.lib.refactor.authentication.oauth.OAuth2ResponseParser;
import com.owncloud.android.lib.refactor.authentication.oauth.OwnCloudOAuth2Provider;
import com.owncloud.android.lib.refactor.RemoteOperation;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Map;
import okhttp3.MultipartBody;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class OAuth2GetAccessTokenOperation extends RemoteOperation {
private final String mGrantType;
private final String mCode;
private final String mClientId;
private final String mClientSecret;
private final String mRedirectUri;
private final String mAccessTokenEndpointPath;
private final OAuth2ResponseParser mResponseParser;
public OAuth2GetAccessTokenOperation(
OwnCloudContext context,
String grantType,
String code,
String clientId,
String secretId,
String redirectUri,
String accessTokenEndpointPath) {
super(context);
mClientId = clientId;
mClientSecret = secretId;
mRedirectUri = redirectUri;
mGrantType = grantType;
mCode = code;
mAccessTokenEndpointPath =
accessTokenEndpointPath != null
? accessTokenEndpointPath
: OwnCloudOAuth2Provider.ACCESS_TOKEN_ENDPOINT_PATH;
mResponseParser = new OAuth2ResponseParser();
}
@Override
public RemoteOperationResult exec() {
try {
final Uri uri = getOCContext()
.getBaseUri()
.buildUpon()
.appendEncodedPath(mAccessTokenEndpointPath)
.build();
final RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(OAuth2Constants.KEY_GRANT_TYPE, mGrantType)
.addFormDataPart(OAuth2Constants.KEY_CODE, mCode)
.addFormDataPart(OAuth2Constants.KEY_REDIRECT_URI, mRedirectUri)
.addFormDataPart(OAuth2Constants.KEY_CLIENT_ID, mClientId)
.build();
final Request request = getRequestBuilder()
.url(uri.toString())
.method("POST", requestBody)
.build();
final Response response = getClient()
.newCall(request)
.execute();
final String responseData = response.body().string();
if (responseData != null && responseData.length() > 0) {
JSONObject tokenJson = new JSONObject(responseData);
Map<String, String> accessTokenResult =
mResponseParser.parseAccessTokenResult(tokenJson);
if (accessTokenResult.get(OAuth2Constants.KEY_ERROR) != null ||
accessTokenResult.get(OAuth2Constants.KEY_ACCESS_TOKEN) == null) {
return new RemoteOperationResult(RemoteOperationResult.ResultCode.OAUTH2_ERROR);
} else {
final RemoteOperationResult result = new RemoteOperationResult(true, request, response);
ArrayList<Object> data = new ArrayList<>();
data.add(accessTokenResult);
result.setData(data);
return result;
}
} else {
return new RemoteOperationResult(false, request, response);
}
} catch (Exception e) {
return new RemoteOperationResult(e);
}
}
}

View File

@ -0,0 +1,134 @@
/**
* ownCloud Android client application
*
* @author David González Verdugo
*
* Copyright (C) 2017 ownCloud GmbH.
*
* 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.lib.refactor.authentication.oauth.operations;
import com.owncloud.android.lib.refactor.OwnCloudContext;
import com.owncloud.android.lib.refactor.RemoteOperationResult;
import com.owncloud.android.lib.refactor.Log_OC;
import com.owncloud.android.lib.refactor.RemoteOperation;
import com.owncloud.android.lib.refactor.authentication.credentials.OwnCloudBasicCredentials;
import com.owncloud.android.lib.refactor.authentication.OwnCloudCredentials;
import com.owncloud.android.lib.refactor.authentication.oauth.OAuth2Constants;
import com.owncloud.android.lib.refactor.authentication.oauth.OAuth2GrantType;
import com.owncloud.android.lib.refactor.authentication.oauth.OAuth2ResponseParser;
import com.owncloud.android.lib.refactor.authentication.oauth.OwnCloudOAuth2Provider;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Map;
import okhttp3.MultipartBody;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class OAuth2RefreshAccessTokenOperation extends RemoteOperation {
private static final String TAG = OAuth2RefreshAccessTokenOperation.class.getSimpleName();
private String mClientId;
private String mClientSecret;
private String mRefreshToken;
private final String mAccessTokenEndpointPath;
private final OAuth2ResponseParser mResponseParser;
public OAuth2RefreshAccessTokenOperation(
OwnCloudContext ocContext,
String clientId,
String secretId,
String refreshToken,
String accessTokenEndpointPath
) {
super(ocContext);
mClientId = clientId;
mClientSecret = secretId;
mRefreshToken = refreshToken;
mAccessTokenEndpointPath =
accessTokenEndpointPath != null ?
accessTokenEndpointPath :
OwnCloudOAuth2Provider.ACCESS_TOKEN_ENDPOINT_PATH
;
mResponseParser = new OAuth2ResponseParser();
}
@Override
public RemoteOperationResult exec() {
try {
final RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(OAuth2Constants.KEY_GRANT_TYPE,
OAuth2GrantType.REFRESH_TOKEN.getValue())
.addFormDataPart(OAuth2Constants.KEY_CLIENT_ID, mClientId)
.addFormDataPart(OAuth2Constants.KEY_REFRESH_TOKEN, mRefreshToken)
.build();
final Request request = getRequestBuilder()
.url(getOCContext().getBaseUri().buildUpon()
.appendEncodedPath(mAccessTokenEndpointPath)
.build()
.toString())
.method("POST", requestBody)
.build();
OwnCloudCredentials oauthCredentials = new OwnCloudBasicCredentials(
mClientId,
mClientSecret
);
final Response response = getClient().newCall(request).execute();
final String responseData = response.body().string();
Log_OC.d(TAG, "OAUTH2: raw response from POST TOKEN: " + responseData);
if (responseData != null && responseData.length() > 0) {
JSONObject tokenJson = new JSONObject(responseData);
Map<String, String> accessTokenResult =
mResponseParser.parseAccessTokenResult(tokenJson);
if (accessTokenResult.get(OAuth2Constants.KEY_ERROR) != null ||
accessTokenResult.get(OAuth2Constants.KEY_ACCESS_TOKEN) == null) {
return new RemoteOperationResult(RemoteOperationResult.ResultCode.OAUTH2_ERROR);
} else {
final RemoteOperationResult result = new RemoteOperationResult(true, request, response);
ArrayList<Object> data = new ArrayList<>();
data.add(accessTokenResult);
result.setData(data);
return result;
}
} else {
return new RemoteOperationResult(false, request, response);
}
} catch (Exception e) {
return new RemoteOperationResult(e);
}
}
}

View File

@ -0,0 +1,140 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.exceptions;
import com.owncloud.android.lib.common.network.AdvancedSslSocketFactory;
import com.owncloud.android.lib.common.network.AdvancedX509TrustManager;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLPeerUnverifiedException;
/**
* Exception joining all the problems that {@link AdvancedX509TrustManager} can find in
* a certificate chain for a server.
*
* This was initially created as an extension of CertificateException, but some
* implementations of the SSL socket layer in existing devices are REPLACING the CertificateException
* instances thrown by {@link javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[], String)}
* with SSLPeerUnverifiedException FORGETTING THE CAUSING EXCEPTION instead of wrapping it.
*
* Due to this, extending RuntimeException is necessary to get that the CertificateCombinedException
* instance reaches {@link AdvancedSslSocketFactory#verifyPeerIdentity}.
*
* BE CAREFUL. As a RuntimeException extensions, Java compilers do not require to handle it
* in client methods. Be sure to use it only when you know exactly where it will go.
*
* @author David A. Velasco
*/
public class CertificateCombinedException extends RuntimeException {
/** Generated - to refresh every time the class changes */
private static final long serialVersionUID = -8875782030758554999L;
private X509Certificate mServerCert = null;
private String mHostInUrl;
private CertificateExpiredException mCertificateExpiredException = null;
private CertificateNotYetValidException mCertificateNotYetValidException = null;
private CertPathValidatorException mCertPathValidatorException = null;
private CertificateException mOtherCertificateException = null;
private SSLPeerUnverifiedException mSslPeerUnverifiedException = null;
public CertificateCombinedException(X509Certificate x509Certificate) {
mServerCert = x509Certificate;
}
public X509Certificate getServerCertificate() {
return mServerCert;
}
public String getHostInUrl() {
return mHostInUrl;
}
public void setHostInUrl(String host) {
mHostInUrl = host;
}
public CertificateExpiredException getCertificateExpiredException() {
return mCertificateExpiredException;
}
public void setCertificateExpiredException(CertificateExpiredException c) {
mCertificateExpiredException = c;
}
public CertificateNotYetValidException getCertificateNotYetValidException() {
return mCertificateNotYetValidException;
}
public void setCertificateNotYetException(CertificateNotYetValidException c) {
mCertificateNotYetValidException = c;
}
public CertPathValidatorException getCertPathValidatorException() {
return mCertPathValidatorException;
}
public void setCertPathValidatorException(CertPathValidatorException c) {
mCertPathValidatorException = c;
}
public CertificateException getOtherCertificateException() {
return mOtherCertificateException;
}
public void setOtherCertificateException(CertificateException c) {
mOtherCertificateException = c;
}
public SSLPeerUnverifiedException getSslPeerUnverifiedException() {
return mSslPeerUnverifiedException ;
}
public void setSslPeerUnverifiedException(SSLPeerUnverifiedException s) {
mSslPeerUnverifiedException = s;
}
public boolean isException() {
return (mCertificateExpiredException != null ||
mCertificateNotYetValidException != null ||
mCertPathValidatorException != null ||
mOtherCertificateException != null ||
mSslPeerUnverifiedException != null);
}
public boolean isRecoverable() {
return (mCertificateExpiredException != null ||
mCertificateNotYetValidException != null ||
mCertPathValidatorException != null ||
mSslPeerUnverifiedException != null);
}
}

View File

@ -0,0 +1,34 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.exceptions;
public class OperationCancelledException extends Exception {
/**
* Generated serial version - to avoid Java warning
*/
private static final long serialVersionUID = -6350981497740424983L;
}

View File

@ -0,0 +1,18 @@
package com.owncloud.android.lib.refactor.operations;
import com.owncloud.android.lib.refactor.OwnCloudContext;
import com.owncloud.android.lib.refactor.RemoteOperation;
import com.owncloud.android.lib.refactor.RemoteOperationResult;
public class PropfindOperation extends RemoteOperation {
public PropfindOperation(OwnCloudContext context) {
super(context);
}
@Override
public RemoteOperationResult exec() {
return null;
}
}

View File

@ -0,0 +1,49 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.utils;
/**
* @author masensio
* @author David A. Velasco
*/
public class AccountTypeUtils {
public static String getAuthTokenTypePass(String accountType) {
return accountType + ".password";
}
public static String getAuthTokenTypeAccessToken(String accountType) {
return accountType + ".oauth2.access_token";
}
public static String getAuthTokenTypeRefreshToken(String accountType) {
return accountType + ".oauth2.refresh_token";
}
public static String getAuthTokenTypeSamlSessionCookie(String accountType) {
return accountType + ".saml.web_sso.session_cookie";
}
}

View File

@ -0,0 +1,321 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2017 ownCloud GmbH.
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.utils;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountsException;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.accounts.AccountTypeUtils;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import org.apache.commons.httpclient.Cookie;
import java.io.IOException;
public class AccountUtils {
private static final String TAG = AccountUtils.class.getSimpleName();
/**
* Constructs full url to host and webdav resource basing on host version
*
* @param context Valid Android {@link Context}, needed to access the {@link AccountManager}
* @param account A stored ownCloud {@link Account}
* @return Full URL to WebDAV endpoint in the server corresponding to 'account'.
* @throws AccountNotFoundException When 'account' is unknown for the AccountManager
*/
public static String getWebDavUrlForAccount(Context context, Account account)
throws AccountNotFoundException {
return getBaseUrlForAccount(context, account) + OwnCloudClient.WEBDAV_PATH_4_0;
}
/**
* Extracts url server from the account
*
* @param context Valid Android {@link Context}, needed to access the {@link AccountManager}
* @param account A stored ownCloud {@link Account}
* @return Full URL to the server corresponding to 'account', ending in the base path
* common to all API endpoints.
* @throws AccountNotFoundException When 'account' is unknown for the AccountManager
*/
public static String getBaseUrlForAccount(Context context, Account account)
throws AccountNotFoundException {
AccountManager ama = AccountManager.get(context.getApplicationContext());
String baseurl = ama.getUserData(account, Constants.KEY_OC_BASE_URL);
if (baseurl == null)
throw new AccountNotFoundException(account, "Account not found", null);
return baseurl;
}
/**
* Get the username corresponding to an OC account.
*
* @param account An OC account
* @return Username for the given account, extracted from the account.name
*/
public static String getUsernameForAccount(Account account) {
String username = null;
try {
username = account.name.substring(0, account.name.lastIndexOf('@'));
} catch (Exception e) {
Log_OC.e(TAG, "Couldn't get a username for the given account", e);
}
return username;
}
/**
* Get the stored server version corresponding to an OC account.
*
* @param account An OC account
* @param context Application context
* @return Version of the OC server, according to last check
*/
public static OwnCloudVersion getServerVersionForAccount(Account account, Context context) {
AccountManager ama = AccountManager.get(context);
OwnCloudVersion version = null;
try {
String versionString = ama.getUserData(account, Constants.KEY_OC_VERSION);
version = new OwnCloudVersion(versionString);
} catch (Exception e) {
Log_OC.e(TAG, "Couldn't get a the server version for an account", e);
}
return version;
}
/**
* @return
* @throws IOException
* @throws AuthenticatorException
* @throws OperationCanceledException
*/
public static OwnCloudCredentials getCredentialsForAccount(Context context, Account account)
throws OperationCanceledException, AuthenticatorException, IOException {
OwnCloudCredentials credentials = null;
AccountManager am = AccountManager.get(context);
String supportsOAuth2 = am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_OAUTH2);
boolean isOauth2 = supportsOAuth2 != null && supportsOAuth2.equals("TRUE");
String supportsSamlSSo = am.getUserData(account,
AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO);
boolean isSamlSso = supportsSamlSSo != null && supportsSamlSSo.equals("TRUE");
String username = AccountUtils.getUsernameForAccount(account);
OwnCloudVersion version = new OwnCloudVersion(am.getUserData(account, Constants.KEY_OC_VERSION));
if (isOauth2) {
String accessToken = am.blockingGetAuthToken(
account,
AccountTypeUtils.getAuthTokenTypeAccessToken(account.type),
false);
credentials = OwnCloudCredentialsFactory.newBearerCredentials(username, accessToken);
} else if (isSamlSso) {
String accessToken = am.blockingGetAuthToken(
account,
AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type),
false);
credentials = OwnCloudCredentialsFactory.newSamlSsoCredentials(username, accessToken);
} else {
String password = am.blockingGetAuthToken(
account,
AccountTypeUtils.getAuthTokenTypePass(account.type),
false);
credentials = OwnCloudCredentialsFactory.newBasicCredentials(
username,
password,
version.isPreemptiveAuthenticationPreferred()
);
}
return credentials;
}
public static String buildAccountNameOld(Uri serverBaseUrl, String username) {
if (serverBaseUrl.getScheme() == null) {
serverBaseUrl = Uri.parse("https://" + serverBaseUrl.toString());
}
String accountName = username + "@" + serverBaseUrl.getHost();
if (serverBaseUrl.getPort() >= 0) {
accountName += ":" + serverBaseUrl.getPort();
}
return accountName;
}
public static String buildAccountName(Uri serverBaseUrl, String username) {
if (serverBaseUrl.getScheme() == null) {
serverBaseUrl = Uri.parse("https://" + serverBaseUrl.toString());
}
// Remove http:// or https://
String url = serverBaseUrl.toString();
if (url.contains("://")) {
url = url.substring(serverBaseUrl.toString().indexOf("://") + 3);
}
String accountName = username + "@" + url;
return accountName;
}
public static void saveClient(OwnCloudClient client, Account savedAccount, Context context) {
// Account Manager
AccountManager ac = AccountManager.get(context.getApplicationContext());
if (client != null) {
String cookiesString = client.getCookiesString();
if (!"".equals(cookiesString)) {
ac.setUserData(savedAccount, Constants.KEY_COOKIES, cookiesString);
// Log_OC.d(TAG, "Saving Cookies: "+ cookiesString );
}
}
}
/**
* Restore the client cookies persisted in an account stored in the system AccountManager.
*
* @param account Stored account.
* @param client Client to restore cookies in.
* @param context Android context used to access the system AccountManager.
*/
public static void restoreCookies(Account account, OwnCloudClient client, Context context) {
if (account == null) {
Log_OC.d(TAG, "Cannot restore cookie for null account");
} else {
Log_OC.d(TAG, "Restoring cookies for " + account.name);
// Account Manager
AccountManager am = AccountManager.get(context.getApplicationContext());
Uri serverUri = (client.getBaseUri() != null) ? client.getBaseUri() : client.getWebdavUri();
String cookiesString = am.getUserData(account, Constants.KEY_COOKIES);
if (cookiesString != null) {
String[] cookies = cookiesString.split(";");
if (cookies.length > 0) {
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = new Cookie();
int equalPos = cookies[i].indexOf('=');
cookie.setName(cookies[i].substring(0, equalPos));
cookie.setValue(cookies[i].substring(equalPos + 1));
cookie.setDomain(serverUri.getHost()); // VERY IMPORTANT
cookie.setPath(serverUri.getPath()); // VERY IMPORTANT
client.getState().addCookie(cookie);
}
}
}
}
}
public static class AccountNotFoundException extends AccountsException {
/**
* Generated - should be refreshed every time the class changes!!
*/
private static final long serialVersionUID = -1684392454798508693L;
private Account mFailedAccount;
public AccountNotFoundException(Account failedAccount, String message, Throwable cause) {
super(message, cause);
mFailedAccount = failedAccount;
}
public Account getFailedAccount() {
return mFailedAccount;
}
}
public static class Constants {
/**
* Version should be 3 numbers separated by dot so it can be parsed by
* {@link OwnCloudVersion}
*/
public static final String KEY_OC_VERSION = "oc_version";
/**
* Base url should point to owncloud installation without trailing / ie:
* http://server/path or https://owncloud.server
*/
public static final String KEY_OC_BASE_URL = "oc_base_url";
/**
* Flag signaling if the ownCloud server can be accessed with OAuth2 access tokens.
*/
public static final String KEY_SUPPORTS_OAUTH2 = "oc_supports_oauth2";
/**
* Flag signaling if the ownCloud server can be accessed with session cookies from SAML-based web single-sign-on.
*/
public static final String KEY_SUPPORTS_SAML_WEB_SSO = "oc_supports_saml_web_sso";
/**
* OC account cookies
*/
public static final String KEY_COOKIES = "oc_account_cookies";
/**
* OC account version
*/
public static final String KEY_OC_ACCOUNT_VERSION = "oc_account_version";
/**
* User's display name
*/
public static final String KEY_DISPLAY_NAME = "oc_display_name";
/**
* OAuth2 refresh token
**/
public static final String KEY_OAUTH2_REFRESH_TOKEN = "oc_oauth2_refresh_token";
}
}

View File

@ -0,0 +1,138 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.utils;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.IOException;
import java.io.InputStream;
/**
* Parser for server exceptions
* @author davidgonzalez
*/
public class ErrorMessageParser {
// No namespaces
private static final String ns = null;
// Nodes for XML Parser
private static final String NODE_ERROR = "d:error";
private static final String NODE_MESSAGE = "s:message";
/**
* Parse exception response
* @param is
* @return errorMessage for an exception
* @throws XmlPullParserException
* @throws IOException
*/
public String parseXMLResponse(InputStream is) throws XmlPullParserException,
IOException {
String errorMessage = "";
try {
// XMLPullParser
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser parser = Xml.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(is, null);
parser.nextTag();
errorMessage = readError(parser);
} finally {
is.close();
}
return errorMessage;
}
/**
* Parse OCS node
* @param parser
* @return reason for exception
* @throws XmlPullParserException
* @throws IOException
*/
private String readError (XmlPullParser parser) throws XmlPullParserException, IOException {
String errorMessage = "";
parser.require(XmlPullParser.START_TAG, ns , NODE_ERROR);
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) {
continue;
}
String name = parser.getName();
// read NODE_MESSAGE
if (name.equalsIgnoreCase(NODE_MESSAGE)) {
errorMessage = readText(parser);
} else {
skip(parser);
}
}
return errorMessage;
}
/**
* Skip tags in parser procedure
* @param parser
* @throws XmlPullParserException
* @throws IOException
*/
private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
if (parser.getEventType() != XmlPullParser.START_TAG) {
throw new IllegalStateException();
}
int depth = 1;
while (depth != 0) {
switch (parser.next()) {
case XmlPullParser.END_TAG:
depth--;
break;
case XmlPullParser.START_TAG:
depth++;
break;
}
}
}
/**
* Read the text from a node
* @param parser
* @return Text of the node
* @throws IOException
* @throws XmlPullParserException
*/
private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
String result = "";
if (parser.next() == XmlPullParser.TEXT) {
result = parser.getText();
parser.nextTag();
}
return result;
}
}

View File

@ -0,0 +1,144 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.refactor.utils;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.IOException;
import java.io.InputStream;
/**
* Parser for Invalid Character server exception
* @author masensio
*/
public class InvalidCharacterExceptionParser {
private static final String EXCEPTION_STRING = "OC\\Connector\\Sabre\\Exception\\InvalidPath";
private static final String EXCEPTION_UPLOAD_STRING = "OCP\\Files\\InvalidPathException";
// No namespaces
private static final String ns = null;
// Nodes for XML Parser
private static final String NODE_ERROR = "d:error";
private static final String NODE_EXCEPTION = "s:exception";
/**
* Parse is as an Invalid Path Exception
* @param is
* @return if The exception is an Invalid Char Exception
* @throws XmlPullParserException
* @throws IOException
*/
public boolean parseXMLResponse(InputStream is) throws XmlPullParserException,
IOException {
boolean result = false;
try {
// XMLPullParser
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser parser = Xml.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(is, null);
parser.nextTag();
result = readError(parser);
} finally {
is.close();
}
return result;
}
/**
* Parse OCS node
* @param parser
* @return List of ShareRemoteFiles
* @throws XmlPullParserException
* @throws IOException
*/
private boolean readError (XmlPullParser parser) throws XmlPullParserException, IOException {
String exception = "";
parser.require(XmlPullParser.START_TAG, ns , NODE_ERROR);
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) {
continue;
}
String name = parser.getName();
// read NODE_EXCEPTION
if (name.equalsIgnoreCase(NODE_EXCEPTION)) {
exception = readText(parser);
} else {
skip(parser);
}
}
return exception.equalsIgnoreCase(EXCEPTION_STRING) ||
exception.equalsIgnoreCase(EXCEPTION_UPLOAD_STRING);
}
/**
* Skip tags in parser procedure
* @param parser
* @throws XmlPullParserException
* @throws IOException
*/
private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
if (parser.getEventType() != XmlPullParser.START_TAG) {
throw new IllegalStateException();
}
int depth = 1;
while (depth != 0) {
switch (parser.next()) {
case XmlPullParser.END_TAG:
depth--;
break;
case XmlPullParser.START_TAG:
depth++;
break;
}
}
}
/**
* Read the text from a node
* @param parser
* @return Text of the node
* @throws IOException
* @throws XmlPullParserException
*/
private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
String result = "";
if (parser.next() == XmlPullParser.TEXT) {
result = parser.getText();
parser.nextTag();
}
return result;
}
}

View File

@ -38,6 +38,8 @@ import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import at.bitfire.dav4android.DavResource;
/**
* Remote operation performing the read of remote file or folder in the ownCloud server.
*
@ -72,6 +74,7 @@ public class ReadRemoteFolderOperation extends RemoteOperation {
PropFindMethod query = null;
try {
// remote request
query = new PropFindMethod(client.getWebdavUri() + WebdavUtils.encodePath(mRemotePath),
WebdavUtils.getAllPropSet(), // PropFind Properties

View File

@ -43,4 +43,8 @@ android {
packagingOptions {
exclude 'META-INF/LICENSE.txt'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}