Added HTTP Basic Authentication to ApkDownloader, added Credentials interface
and HttpBasicCredentials implementation to prepare HttpDownloader for other authentication methods.
This commit is contained in:
parent
2067f15b27
commit
a29bf3d9c8
@ -97,6 +97,7 @@ import org.fdroid.fdroid.net.Downloader;
|
||||
import java.io.File;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import org.fdroid.fdroid.data.Credentials;
|
||||
|
||||
interface AppDetailsData {
|
||||
App getApp();
|
||||
@ -855,8 +856,20 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
|
||||
return repo.address;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Credentials getRepoCredentials(Apk apk) {
|
||||
final String[] projection = {RepoProvider.DataColumns.USERNAME, RepoProvider.DataColumns.PASSWORD};
|
||||
Repo repo = RepoProvider.Helper.findById(this, apk.repo, projection);
|
||||
if (repo == null || repo.username == null || repo.password == null) {
|
||||
return null;
|
||||
}
|
||||
return repo.getCredentials();
|
||||
}
|
||||
|
||||
private void startDownload(Apk apk, String repoAddress) {
|
||||
downloadHandler = new ApkDownloader(getBaseContext(), app, apk, repoAddress);
|
||||
downloadHandler.setCredentials(getRepoCredentials(apk));
|
||||
|
||||
localBroadcastManager.registerReceiver(downloaderProgressReceiver,
|
||||
new IntentFilter(Downloader.LOCAL_ACTION_PROGRESS));
|
||||
downloadHandler.setProgressListener(this);
|
||||
|
@ -96,8 +96,7 @@ public class RepoUpdater {
|
||||
try {
|
||||
downloader = DownloaderFactory.create(context,
|
||||
getIndexAddress(), File.createTempFile("index-", "-downloaded", context.getCacheDir()),
|
||||
repo.username,
|
||||
repo.password
|
||||
repo.getCredentials()
|
||||
);
|
||||
downloader.setCacheTag(repo.lastetag);
|
||||
downloader.downloadUninterrupted();
|
||||
|
36
F-Droid/src/org/fdroid/fdroid/data/Credentials.java
Normal file
36
F-Droid/src/org/fdroid/fdroid/data/Credentials.java
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Christian Morgner (christian.morgner@structr.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.fdroid.fdroid.data;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
/**
|
||||
* Credentials to authenticate HTTP requests. Implementations if this interface
|
||||
* should encapsulate the authentication of an HTTP request in the authenticate
|
||||
* method.
|
||||
*/
|
||||
public interface Credentials {
|
||||
|
||||
/**
|
||||
* Implement this method to provide authentication for the given connection.
|
||||
* @param connection the HTTP connection to authenticate
|
||||
*/
|
||||
public void authenticate(final HttpURLConnection connection);
|
||||
}
|
@ -9,6 +9,7 @@ import org.fdroid.fdroid.Utils;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
import org.fdroid.fdroid.net.auth.HttpBasicCredentials;
|
||||
|
||||
public class Repo extends ValueObject {
|
||||
|
||||
@ -148,6 +149,21 @@ public class Repo extends ValueObject {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the credentials for this repo, or null of no authentication
|
||||
* method is configured.
|
||||
* @return the credentials or null
|
||||
*/
|
||||
public Credentials getCredentials() {
|
||||
|
||||
// return the only credentials implementation we have right now
|
||||
if (!TextUtils.isEmpty(username) && !TextUtils.isEmpty(password)) {
|
||||
return new HttpBasicCredentials(username, password);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setValues(ContentValues values) {
|
||||
|
||||
if (values.containsKey(RepoProvider.DataColumns._ID)) {
|
||||
|
@ -39,6 +39,7 @@ import org.fdroid.fdroid.data.SanitizedFile;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import org.fdroid.fdroid.data.Credentials;
|
||||
|
||||
/**
|
||||
* Downloads and verifies (against the Apk.hash) the apk file.
|
||||
@ -77,6 +78,7 @@ public class ApkDownloader implements AsyncDownloader.Listener {
|
||||
|
||||
private ProgressListener listener;
|
||||
private AsyncDownloader dlWrapper;
|
||||
private Credentials credentials;
|
||||
private boolean isComplete;
|
||||
|
||||
private final long id = ++downloadIdCounter;
|
||||
@ -195,7 +197,7 @@ public class ApkDownloader implements AsyncDownloader.Listener {
|
||||
Utils.debugLog(TAG, "Downloading apk from " + remoteAddress + " to " + localFile);
|
||||
|
||||
try {
|
||||
dlWrapper = DownloaderFactory.createAsync(context, remoteAddress, localFile, app.name + " " + curApk.version, curApk.id, this);
|
||||
dlWrapper = DownloaderFactory.createAsync(context, remoteAddress, localFile, app.name + " " + curApk.version, curApk.id, credentials, this);
|
||||
dlWrapper.download();
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
@ -292,4 +294,8 @@ public class ApkDownloader implements AsyncDownloader.Listener {
|
||||
public int getTotalBytes() {
|
||||
return dlWrapper != null ? dlWrapper.getTotalBytes() : 0;
|
||||
}
|
||||
|
||||
public void setCredentials(final Credentials credentials) {
|
||||
this.credentials = credentials;
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import org.fdroid.fdroid.Utils;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import org.fdroid.fdroid.data.Credentials;
|
||||
|
||||
public class DownloaderFactory {
|
||||
|
||||
@ -45,10 +46,10 @@ public class DownloaderFactory {
|
||||
|
||||
public static Downloader create(Context context, URL url, File destFile)
|
||||
throws IOException {
|
||||
return create(context, url, destFile, null, null);
|
||||
return create(context, url, destFile, null);
|
||||
}
|
||||
|
||||
public static Downloader create(Context context, URL url, File destFile, final String username, final String password)
|
||||
public static Downloader create(Context context, URL url, File destFile, Credentials credentials)
|
||||
throws IOException {
|
||||
if (isBluetoothAddress(url)) {
|
||||
String macAddress = url.getHost().replace("-", ":");
|
||||
@ -60,7 +61,7 @@ public class DownloaderFactory {
|
||||
if (isLocalFile(url)) {
|
||||
return new LocalFileDownloader(context, url, destFile);
|
||||
}
|
||||
return new HttpDownloader(context, url, destFile, username, password);
|
||||
return new HttpDownloader(context, url, destFile, credentials);
|
||||
}
|
||||
|
||||
private static boolean isBluetoothAddress(URL url) {
|
||||
@ -71,11 +72,11 @@ public class DownloaderFactory {
|
||||
return "file".equalsIgnoreCase(url.getProtocol());
|
||||
}
|
||||
|
||||
public static AsyncDownloader createAsync(Context context, String urlString, File destFile, String title, String id, AsyncDownloader.Listener listener) throws IOException {
|
||||
return createAsync(context, new URL(urlString), destFile, title, id, listener);
|
||||
public static AsyncDownloader createAsync(Context context, String urlString, File destFile, String title, String id, Credentials credentials, AsyncDownloader.Listener listener) throws IOException {
|
||||
return createAsync(context, new URL(urlString), destFile, title, id, credentials, listener);
|
||||
}
|
||||
|
||||
public static AsyncDownloader createAsync(Context context, URL url, File destFile, String title, String id, AsyncDownloader.Listener listener)
|
||||
public static AsyncDownloader createAsync(Context context, URL url, File destFile, String title, String id, Credentials credentials, AsyncDownloader.Listener listener)
|
||||
throws IOException {
|
||||
// To re-enable, fix the following:
|
||||
// * https://gitlab.com/fdroid/fdroidclient/issues/445
|
||||
@ -85,7 +86,7 @@ public class DownloaderFactory {
|
||||
return new AsyncDownloaderFromAndroid(context, listener, title, id, url.toString(), destFile);
|
||||
}
|
||||
Utils.debugLog(TAG, "Using AsyncDownloadWrapper");
|
||||
return new AsyncDownloadWrapper(create(context, url, destFile), listener);
|
||||
return new AsyncDownloadWrapper(create(context, url, destFile, credentials), listener);
|
||||
}
|
||||
|
||||
static boolean isOnionAddress(URL url) {
|
||||
|
@ -1,10 +1,9 @@
|
||||
package org.fdroid.fdroid.net;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
|
||||
|
||||
import org.apache.commons.net.util.Base64;
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.Preferences;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
@ -22,6 +21,7 @@ import java.net.SocketAddress;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import org.fdroid.fdroid.data.Credentials;
|
||||
|
||||
public class HttpDownloader extends Downloader {
|
||||
private static final String TAG = "HttpDownloader";
|
||||
@ -30,21 +30,19 @@ public class HttpDownloader extends Downloader {
|
||||
protected static final String HEADER_FIELD_ETAG = "ETag";
|
||||
|
||||
protected HttpURLConnection connection;
|
||||
private final String username;
|
||||
private final String password;
|
||||
private Credentials credentials;
|
||||
private int statusCode = -1;
|
||||
|
||||
HttpDownloader(Context context, URL url, File destFile)
|
||||
throws FileNotFoundException, MalformedURLException {
|
||||
this(context, url, destFile, null, null);
|
||||
this(context, url, destFile, null);
|
||||
}
|
||||
|
||||
HttpDownloader(Context context, URL url, File destFile, final String username, final String password)
|
||||
HttpDownloader(Context context, URL url, File destFile, final Credentials credentials)
|
||||
throws FileNotFoundException, MalformedURLException {
|
||||
super(context, url, destFile);
|
||||
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.credentials = credentials;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -100,9 +98,8 @@ public class HttpDownloader extends Downloader {
|
||||
} else {
|
||||
|
||||
connection = (HttpURLConnection) sourceUrl.openConnection();
|
||||
if (!TextUtils.isEmpty(username) && !TextUtils.isEmpty(password)) {
|
||||
// add authorization header from username / password if set
|
||||
connection.setRequestProperty("Authorization", "Basic " + Base64.encodeBase64String((username + ":" + password).getBytes()));
|
||||
if (credentials != null) {
|
||||
credentials.authenticate((HttpURLConnection)connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Christian Morgner (christian.morgner@structr.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.fdroid.fdroid.net.auth;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import java.net.HttpURLConnection;
|
||||
import org.apache.commons.net.util.Base64;
|
||||
import org.fdroid.fdroid.data.Credentials;
|
||||
|
||||
/**
|
||||
* Credentials implementation for HTTP Basic Authentication.
|
||||
*/
|
||||
public class HttpBasicCredentials implements Credentials {
|
||||
|
||||
private final String username;
|
||||
private final String password;
|
||||
|
||||
public HttpBasicCredentials(final String username, final String password) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticate(final HttpURLConnection connection) {
|
||||
|
||||
if (!TextUtils.isEmpty(username) && !TextUtils.isEmpty(password)) {
|
||||
|
||||
// add authorization header from username / password if set
|
||||
connection.setRequestProperty("Authorization", "Basic " + Base64.encodeBase64String((username + ":" + password).getBytes()));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user