Merge request changes

- Moved certificate-related utilities to separate class

- Added settings method to return an entire SSLSettings object; refactored
  methods using separate parameters to take single SSLSettings parameter

- Advanced Settings section on login page now hides / shows along with
  other buttons to prevent it from showing up in front of the loading
  spinner

- Fixed star imports

- Refactored applySslSettings as per code from merge request

- Fixed formatting
This commit is contained in:
Galen Abell
2018-11-08 17:43:12 -05:00
parent 2d14ef1b6f
commit 8e2d90ef50
10 changed files with 274 additions and 209 deletions

View File

@@ -0,0 +1,116 @@
package com.github.gotify.api;
import android.annotation.SuppressLint;
import com.github.gotify.Utils;
import com.github.gotify.log.Log;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Collection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;
public class CertUtils {
public static class SSLSettings {
boolean validateSSL;
String cert;
public SSLSettings(boolean validateSSL, String cert) {
this.validateSSL = validateSSL;
this.cert = cert;
}
}
private static final X509TrustManager trustAll =
new X509TrustManager() {
@SuppressLint("TrustAllX509TrustManager")
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
@SuppressLint("TrustAllX509TrustManager")
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[] {};
}
};
public static Certificate parseCertificate(String cert) {
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
return certificateFactory.generateCertificate(Utils.stringToInputStream(cert));
} catch (Exception e) {
throw new IllegalArgumentException("certificate is invalid");
}
}
public static void applySslSettings(OkHttpClient.Builder builder, SSLSettings settings) {
// Modified from ApiClient.applySslSettings in the client package.
try {
if (!settings.validateSSL) {
SSLContext context = SSLContext.getInstance("TLS");
context.init(
new KeyManager[] {}, new TrustManager[] {trustAll}, new SecureRandom());
builder.sslSocketFactory(context.getSocketFactory(), trustAll);
builder.hostnameVerifier((a, b) -> true);
return;
}
if (settings.cert != null) {
TrustManager[] trustManagers = certToTrustManager(settings.cert);
if (trustManagers != null && trustManagers.length > 0) {
SSLContext context = SSLContext.getInstance("TLS");
context.init(new KeyManager[] {}, trustManagers, new SecureRandom());
builder.sslSocketFactory(
context.getSocketFactory(), (X509TrustManager) trustManagers[0]);
builder.hostnameVerifier((a, b) -> true);
}
}
} catch (Exception e) {
// We shouldn't have issues since the cert is verified on login.
Log.e("Failed to apply SSL settings", e);
}
}
private static TrustManager[] certToTrustManager(String cert) throws GeneralSecurityException {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
Collection<? extends Certificate> certificates =
certificateFactory.generateCertificates(Utils.stringToInputStream(cert));
if (certificates.isEmpty()) {
throw new IllegalArgumentException("expected non-empty set of trusted certificates");
}
KeyStore caKeyStore = newEmptyKeyStore();
int index = 0;
for (Certificate certificate : certificates) {
String certificateAlias = "ca" + Integer.toString(index++);
caKeyStore.setCertificateEntry(certificateAlias, certificate);
}
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(caKeyStore);
return trustManagerFactory.getTrustManagers();
}
private static KeyStore newEmptyKeyStore() throws GeneralSecurityException {
try {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
return keyStore;
} catch (IOException e) {
throw new AssertionError(e);
}
}
}

View File

@@ -9,16 +9,17 @@ import com.github.gotify.client.auth.ApiKeyAuth;
import com.github.gotify.client.auth.HttpBasicAuth;
public class ClientFactory {
public static ApiClient unauthorized(String baseUrl, boolean validateSSL, String cert) {
public static ApiClient unauthorized(String baseUrl, CertUtils.SSLSettings sslSettings) {
ApiClient client = new ApiClient();
client.setVerifyingSsl(validateSSL);
client.setSslCaCert(Utils.stringToInputStream(cert));
client.setVerifyingSsl(sslSettings.validateSSL);
client.setSslCaCert(Utils.stringToInputStream(sslSettings.cert));
client.setBasePath(baseUrl);
return client;
}
public static ApiClient basicAuth(String baseUrl, boolean validateSSL, String cert, String username, String password) {
ApiClient client = unauthorized(baseUrl, validateSSL, cert);
public static ApiClient basicAuth(
String baseUrl, CertUtils.SSLSettings sslSettings, String username, String password) {
ApiClient client = unauthorized(baseUrl, sslSettings);
HttpBasicAuth auth = (HttpBasicAuth) client.getAuthentication("basicAuth");
auth.setUsername(username);
auth.setPassword(password);
@@ -26,18 +27,19 @@ public class ClientFactory {
return client;
}
public static ApiClient clientToken(String baseUrl, boolean validateSSL, String cert, String token) {
ApiClient client = unauthorized(baseUrl, validateSSL, cert);
public static ApiClient clientToken(
String baseUrl, CertUtils.SSLSettings sslSettings, String token) {
ApiClient client = unauthorized(baseUrl, sslSettings);
ApiKeyAuth tokenAuth = (ApiKeyAuth) client.getAuthentication("clientTokenHeader");
tokenAuth.setApiKey(token);
return client;
}
public static VersionApi versionApi(String baseUrl, boolean validateSSL, String cert) {
return new VersionApi(unauthorized(baseUrl, validateSSL, cert));
public static VersionApi versionApi(String baseUrl, CertUtils.SSLSettings sslSettings) {
return new VersionApi(unauthorized(baseUrl, sslSettings));
}
public static UserApi userApiWithToken(Settings settings) {
return new UserApi(clientToken(settings.url(), settings.validateSSL(), settings.cert(), settings.token()));
return new UserApi(clientToken(settings.url(), settings.sslSettings(), settings.token()));
}
}