From 62ad5b1d348f10e7cf1a5a317a25b5effe1e4779 Mon Sep 17 00:00:00 2001
From: Loic Blot
Date: Tue, 20 Dec 2016 22:17:44 +0100
Subject: [PATCH] Import some sources from legacy HTTP Client to permit using
self signed certificates like before
It's not the perfect solution but this works
Rename HTTPRequestBuilder to OCHttpClient & make it child of HttpClient
---
.../activities/LoginActivity.java | 4 +-
...PRequestBuilder.java => OCHttpClient.java} | 28 ++-
.../engine/OCSMSOwnCloudClient.java | 4 +-
.../ssl/EasySSLProtocolSocketFactory.java | 224 ++++++++++++++++++
.../contrib/ssl/EasyX509TrustManager.java | 103 ++++++++
5 files changed, 348 insertions(+), 15 deletions(-)
rename src/main/java/fr/unix_experience/owncloud_sms/engine/{HTTPRequestBuilder.java => OCHttpClient.java} (74%)
create mode 100644 src/main/java/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java
create mode 100644 src/main/java/org/apache/commons/httpclient/contrib/ssl/EasyX509TrustManager.java
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/activities/LoginActivity.java b/src/main/java/fr/unix_experience/owncloud_sms/activities/LoginActivity.java
index 3799e1d..a5ca51c 100644
--- a/src/main/java/fr/unix_experience/owncloud_sms/activities/LoginActivity.java
+++ b/src/main/java/fr/unix_experience/owncloud_sms/activities/LoginActivity.java
@@ -48,7 +48,7 @@ import java.io.IOException;
import fr.unix_experience.owncloud_sms.R;
import fr.unix_experience.owncloud_sms.defines.DefaultPrefs;
-import fr.unix_experience.owncloud_sms.engine.HTTPRequestBuilder;
+import fr.unix_experience.owncloud_sms.engine.OCHttpClient;
/**
* A login screen that offers login via email/password.
@@ -241,7 +241,7 @@ public class LoginActivity extends AppCompatActivity {
@Override
protected Boolean doInBackground(Void... params) {
_returnCode = 0;
- HTTPRequestBuilder http = new HTTPRequestBuilder(_serverURI, _login, _password);
+ OCHttpClient http = new OCHttpClient(_serverURI, _login, _password);
GetMethod testMethod = http.getVersion();
try {
_returnCode = http.execute(testMethod);
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/engine/HTTPRequestBuilder.java b/src/main/java/fr/unix_experience/owncloud_sms/engine/OCHttpClient.java
similarity index 74%
rename from src/main/java/fr/unix_experience/owncloud_sms/engine/HTTPRequestBuilder.java
rename to src/main/java/fr/unix_experience/owncloud_sms/engine/OCHttpClient.java
index 0ba2a74..8d05d49 100644
--- a/src/main/java/fr/unix_experience/owncloud_sms/engine/HTTPRequestBuilder.java
+++ b/src/main/java/fr/unix_experience/owncloud_sms/engine/OCHttpClient.java
@@ -23,15 +23,19 @@ import android.util.Log;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
+import org.apache.commons.httpclient.contrib.ssl.EasySSLProtocolSocketFactory;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
+import org.apache.commons.httpclient.protocol.Protocol;
+import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import java.io.IOException;
-public class HTTPRequestBuilder {
+public class OCHttpClient extends HttpClient {
- private static final String TAG = HTTPRequestBuilder.class.getCanonicalName();
+ private static final String TAG = OCHttpClient.class.getCanonicalName();
private final Uri _serverURI;
private final String _username;
private final String _password;
@@ -48,47 +52,49 @@ public class HTTPRequestBuilder {
private static final String OC_V2_GET_MESSAGES_PHONE ="/index.php/apps/ocsms/api/v2/messages/[PHONENUMBER]/[START]/[LIMIT]?format=json";
private static final String OC_V2_GET_MESSAGES_SENDQUEUE = "/index.php/apps/ocsms/api/v2/messages/sendqueue?format=json";
- public HTTPRequestBuilder(Uri serverURI, String accountName, String accountPassword) {
+ public OCHttpClient(Uri serverURI, String accountName, String accountPassword) {
+ super(new MultiThreadedHttpConnectionManager());
+ Protocol easyhttps = new Protocol("https", (ProtocolSocketFactory)new EasySSLProtocolSocketFactory(), 443);
+ Protocol.registerProtocol("https", easyhttps);
_serverURI = serverURI;
_username = accountName;
_password = accountPassword;
}
private GetMethod get(String oc_call) {
- Log.i(HTTPRequestBuilder.TAG, "Create GET " + _serverURI + oc_call);
+ Log.i(OCHttpClient.TAG, "Create GET " + _serverURI + oc_call);
return new GetMethod(_serverURI.toString() + oc_call);
}
GetMethod getAllSmsIds() {
- return get(HTTPRequestBuilder.OC_GET_ALL_SMS_IDS);
+ return get(OCHttpClient.OC_GET_ALL_SMS_IDS);
}
public GetMethod getVersion() {
- return get(HTTPRequestBuilder.OC_GET_VERSION);
+ return get(OCHttpClient.OC_GET_VERSION);
}
PostMethod pushSms(StringRequestEntity ent) {
- PostMethod post = new PostMethod(_serverURI.toString() + HTTPRequestBuilder.OC_PUSH_ROUTE);
+ PostMethod post = new PostMethod(_serverURI.toString() + OCHttpClient.OC_PUSH_ROUTE);
post.setRequestEntity(ent);
return post;
}
GetMethod getPhoneList() {
- return get(HTTPRequestBuilder.OC_V2_GET_PHONELIST);
+ return get(OCHttpClient.OC_V2_GET_PHONELIST);
}
GetMethod getMessages(Long start, Integer limit) {
- return get(HTTPRequestBuilder.OC_V2_GET_MESSAGES.
+ return get(OCHttpClient.OC_V2_GET_MESSAGES.
replace("[START]", start.toString()).replace("[LIMIT]", limit.toString()));
}
public int execute(HttpMethod req) throws IOException {
- HttpClient http = new HttpClient();
String basicAuth = "Basic " +
Base64.encodeToString((_username + ":" + _password).getBytes(), Base64.NO_WRAP);
//req.setFollowRedirects(true); // App is SIGKILLED by android when doing this... WTF
req.setDoAuthentication(true);
req.addRequestHeader("Authorization", basicAuth);
- return http.executeMethod(req);
+ return executeMethod(req);
}
}
diff --git a/src/main/java/fr/unix_experience/owncloud_sms/engine/OCSMSOwnCloudClient.java b/src/main/java/fr/unix_experience/owncloud_sms/engine/OCSMSOwnCloudClient.java
index 517462c..2a58aed 100644
--- a/src/main/java/fr/unix_experience/owncloud_sms/engine/OCSMSOwnCloudClient.java
+++ b/src/main/java/fr/unix_experience/owncloud_sms/engine/OCSMSOwnCloudClient.java
@@ -56,7 +56,7 @@ public class OCSMSOwnCloudClient {
}
Uri serverURI = Uri.parse(ocURI);
- _http = new HTTPRequestBuilder(serverURI, accountManager.getUserData(account, "ocLogin"),
+ _http = new OCHttpClient(serverURI, accountManager.getUserData(account, "ocLogin"),
accountManager.getPassword(account));
_connectivityMonitor = new ConnectivityMonitor(_context);
}
@@ -369,7 +369,7 @@ public class OCSMSOwnCloudClient {
private static final int maximumHttpReqTries = 3;
- private final HTTPRequestBuilder _http;
+ private final OCHttpClient _http;
private final Context _context;
private final ConnectivityMonitor _connectivityMonitor;
diff --git a/src/main/java/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java b/src/main/java/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java
new file mode 100644
index 0000000..beb95c3
--- /dev/null
+++ b/src/main/java/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java
@@ -0,0 +1,224 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+package org.apache.commons.httpclient.contrib.ssl;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.UnknownHostException;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+
+import org.apache.commons.httpclient.ConnectTimeoutException;
+import org.apache.commons.httpclient.HttpClientError;
+import org.apache.commons.httpclient.params.HttpConnectionParams;
+import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
+
+/**
+ *
+ * EasySSLProtocolSocketFactory can be used to creats SSL {@link Socket}s
+ * that accept self-signed certificates.
+ *
+ *
+ * This socket factory SHOULD NOT be used for productive systems
+ * due to security reasons, unless it is a concious decision and
+ * you are perfectly aware of security implications of accepting
+ * self-signed certificates
+ *
+ *
+ *
+ * Example of using custom protocol socket factory for a specific host:
+ *
+ * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
+ *
+ * URI uri = new URI("https://localhost/", true);
+ * // use relative url only
+ * GetMethod httpget = new GetMethod(uri.getPathQuery());
+ * HostConfiguration hc = new HostConfiguration();
+ * hc.setHost(uri.getHost(), uri.getPort(), easyhttps);
+ * HttpClient client = new HttpClient();
+ * client.executeMethod(hc, httpget);
+ *
+ *
+ *
+ * Example of using custom protocol socket factory per default instead of the standard one:
+ *
+ * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
+ * Protocol.registerProtocol("https", easyhttps);
+ *
+ * HttpClient client = new HttpClient();
+ * GetMethod httpget = new GetMethod("https://localhost/");
+ * client.executeMethod(httpget);
+ *
+ *
+ *
+ * @author Oleg Kalnichevski
+ *
+ *
+ * DISCLAIMER: HttpClient developers DO NOT actively support this component.
+ * The component is provided as a reference material, which may be inappropriate
+ * for use without additional customization.
+ *
+ */
+
+public class EasySSLProtocolSocketFactory implements SecureProtocolSocketFactory {
+
+ private SSLContext sslcontext = null;
+
+ /**
+ * Constructor for EasySSLProtocolSocketFactory.
+ */
+ public EasySSLProtocolSocketFactory() {
+ super();
+ }
+
+ private static SSLContext createEasySSLContext() {
+ try {
+ SSLContext context = SSLContext.getInstance("SSL");
+ context.init(
+ null,
+ new TrustManager[] {new EasyX509TrustManager(null)},
+ null);
+ return context;
+ } catch (Exception e) {
+ throw new HttpClientError(e.toString());
+ }
+ }
+
+ private SSLContext getSSLContext() {
+ if (this.sslcontext == null) {
+ this.sslcontext = createEasySSLContext();
+ }
+ return this.sslcontext;
+ }
+
+ /**
+ * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int)
+ */
+ public Socket createSocket(
+ String host,
+ int port,
+ InetAddress clientHost,
+ int clientPort)
+ throws IOException, UnknownHostException {
+
+ return getSSLContext().getSocketFactory().createSocket(
+ host,
+ port,
+ clientHost,
+ clientPort
+ );
+ }
+
+ /**
+ * Attempts to get a new socket connection to the given host within the given time limit.
+ *
+ * To circumvent the limitations of older JREs that do not support connect timeout a
+ * controller thread is executed. The controller thread attempts to create a new socket
+ * within the given limit of time. If socket constructor does not return until the
+ * timeout expires, the controller terminates and throws an {@link ConnectTimeoutException}
+ *
+ *
+ * @param host the host name/IP
+ * @param port the port on the host
+ * @param params {@link HttpConnectionParams Http connection parameters}
+ *
+ * @return Socket a new socket
+ *
+ * @throws IOException if an I/O error occurs while creating the socket
+ * @throws UnknownHostException if the IP address of the host cannot be
+ * determined
+ */
+ public Socket createSocket(
+ final String host,
+ final int port,
+ final InetAddress localAddress,
+ final int localPort,
+ final HttpConnectionParams params
+ ) throws IOException, UnknownHostException, ConnectTimeoutException {
+ if (params == null) {
+ throw new IllegalArgumentException("Parameters may not be null");
+ }
+ int timeout = params.getConnectionTimeout();
+ SocketFactory socketfactory = getSSLContext().getSocketFactory();
+ if (timeout == 0) {
+ return socketfactory.createSocket(host, port, localAddress, localPort);
+ } else {
+ Socket socket = socketfactory.createSocket();
+ SocketAddress localaddr = new InetSocketAddress(localAddress, localPort);
+ SocketAddress remoteaddr = new InetSocketAddress(host, port);
+ socket.bind(localaddr);
+ socket.connect(remoteaddr, timeout);
+ return socket;
+ }
+ }
+
+ /**
+ * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int)
+ */
+ public Socket createSocket(String host, int port)
+ throws IOException, UnknownHostException {
+ return getSSLContext().getSocketFactory().createSocket(
+ host,
+ port
+ );
+ }
+
+ /**
+ * @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean)
+ */
+ public Socket createSocket(
+ Socket socket,
+ String host,
+ int port,
+ boolean autoClose)
+ throws IOException, UnknownHostException {
+ return getSSLContext().getSocketFactory().createSocket(
+ socket,
+ host,
+ port,
+ autoClose
+ );
+ }
+
+ public boolean equals(Object obj) {
+ return ((obj != null) && obj.getClass().equals(EasySSLProtocolSocketFactory.class));
+ }
+
+ public int hashCode() {
+ return EasySSLProtocolSocketFactory.class.hashCode();
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/httpclient/contrib/ssl/EasyX509TrustManager.java b/src/main/java/org/apache/commons/httpclient/contrib/ssl/EasyX509TrustManager.java
new file mode 100644
index 0000000..f566f5a
--- /dev/null
+++ b/src/main/java/org/apache/commons/httpclient/contrib/ssl/EasyX509TrustManager.java
@@ -0,0 +1,103 @@
+/*
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+package org.apache.commons.httpclient.contrib.ssl;
+
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ *
+ * EasyX509TrustManager unlike default {@link X509TrustManager} accepts
+ * self-signed certificates.
+ *
+ *
+ * This trust manager SHOULD NOT be used for productive systems
+ * due to security reasons, unless it is a concious decision and
+ * you are perfectly aware of security implications of accepting
+ * self-signed certificates
+ *
+ *
+ * @author Adrian Sutton
+ * @author Oleg Kalnichevski
+ *
+ *
+ * DISCLAIMER: HttpClient developers DO NOT actively support this component.
+ * The component is provided as a reference material, which may be inappropriate
+ * for use without additional customization.
+ *
+ */
+
+public class EasyX509TrustManager implements X509TrustManager
+{
+ private X509TrustManager standardTrustManager = null;
+
+ /**
+ * Constructor for EasyX509TrustManager.
+ */
+ public EasyX509TrustManager(KeyStore keystore) throws NoSuchAlgorithmException, KeyStoreException {
+ super();
+ TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ factory.init(keystore);
+ TrustManager[] trustmanagers = factory.getTrustManagers();
+ if (trustmanagers.length == 0) {
+ throw new NoSuchAlgorithmException("no trust manager found");
+ }
+ this.standardTrustManager = (X509TrustManager)trustmanagers[0];
+ }
+
+ /**
+ * @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],String authType)
+ */
+ public void checkClientTrusted(X509Certificate[] certificates,String authType) throws CertificateException {
+ standardTrustManager.checkClientTrusted(certificates,authType);
+ }
+
+ /**
+ * @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],String authType)
+ */
+ public void checkServerTrusted(X509Certificate[] certificates,String authType) throws CertificateException {
+ if ((certificates != null) && (certificates.length == 1)) {
+ certificates[0].checkValidity();
+ } else {
+ standardTrustManager.checkServerTrusted(certificates,authType);
+ }
+ }
+
+ /**
+ * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
+ */
+ public X509Certificate[] getAcceptedIssuers() {
+ return this.standardTrustManager.getAcceptedIssuers();
+ }
+}