I am trying to connect to a sync gateway using basic authentication over https with a custom keystore. I keep getting 401 Unauthorized error. The user is already set up on the gateway and can be accessed via httpie. I am not quite sure what is wrong with my code:
private void tryBasicAuthWithUpdatedTrustStore() throws KeyStoreException {
this.trustStore = KeyStore.getInstance("BKS");
InputStream in = getResources().openRawResource(R.raw.<KEYSTORE_NAME>);
try {
trustStore.load(in, "<PASSWORD>".toCharArray());
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
}
// Get persistent cookies
cookieStore = database.getPersistentCookieStore();
// Make HttpClientFactory
HttpClientFactory httpClientFactory = new HttpClientFactory() {
private CookieStore cs = cookieStore;
@Override
public HttpClient getHttpClient() {
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
try {
schemeRegistry.register(new Scheme("https", new SSLSocketFactory(trustStore), 443));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
}
HttpParams params = new BasicHttpParams();
ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
DefaultHttpClient client = new DefaultHttpClient(cm, params);
synchronized (this) {
client.setCookieStore(cookieStore);
}
return client;
}
@Override
public void addCookies(List<Cookie> cookies) {
if (cookieStore == null) {
return;
}
synchronized (this) {
for (Cookie cookie : cookies) {
cookieStore.addCookie(cookie);
}
}
}
@Override
public void deleteCookie(String name) {
if (cookieStore == null) {
return;
}
List<Cookie> cookies = cookieStore.getCookies();
List<Cookie> retainedCookies = new ArrayList<Cookie>();
for (Cookie cookie : cookies) {
if (!cookie.getName().equals(name)) {
retainedCookies.add(cookie);
}
}
cookieStore.clear();
for (Cookie retainedCookie : retainedCookies) {
cookieStore.addCookie(retainedCookie);
}
}
@Override
public CookieStore getCookieStore() {
return cookieStore;
}
};
URL url = null;
try {
url = new URL(ReplicationTest.SYNC_URL);
} catch (MalformedURLException e) {
e.printStackTrace();
}
Replication pull = new Replication(this.database, url, Replication.Direction.PULL, httpClientFactory, this.manager.getWorkExecutor());
pull.setContinuous(true);
Authenticator auth = new BasicAuthenticator(username, password);
pull.setAuthenticator(auth);
pull.start();
Stack trace:
06-08 08:38:57.092 15886-15928/com.icfi.couchbasereplicationtest E/RemoteRequestďą• Got error status: 401 for SYNC_URL. Reason: Unauthorized
06-08 08:38:57.092 15886-15928/com.icfi.couchbasereplicationtest E/Syncďą• com.couchbase.lite.replicator.ReplicationInternal$4@40ee2038: Session check failed
org.apache.http.client.HttpResponseException: Unauthorized
at com.couchbase.lite.support.RemoteRequest.executeRequest(RemoteRequest.java:222)
at com.couchbase.lite.support.RemoteRequest.run(RemoteRequest.java:104)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:390)
at java.util.concurrent.FutureTask.run(FutureTask.java:234)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:153)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:267)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:856)
06-08 08:38:57.092 15886-15928/com.icfi.couchbasereplicationtest E/Syncďą• com.couchbase.lite.replicator.PullerInternal@40ed58a0: Progress: set error = org.apache.http.client.HttpResponseException: Unauthorized
The code produced the following errors (I tried something similar during my debugging, it’s why I figured I needed the custom key store.):
06-08 15:06:32.023 29789-29874/com.icfi.couchbasereplicationtest E/RemoteRequestďą• io exception. url: https:/SYNC_URL/_session
javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
at org.apache.harmony.xnet.provider.jsse.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:137)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:93)
at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:381)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:165)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
at com.couchbase.lite.support.RemoteRequest.executeRequest(RemoteRequest.java:201)
at com.couchbase.lite.support.RemoteRequest.run(RemoteRequest.java:104)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:390)
at java.util.concurrent.FutureTask.run(FutureTask.java:234)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:153)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:267)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:856)
06-08 15:06:32.023 29789-29874/com.icfi.couchbasereplicationtest E/Syncďą• com.couchbase.lite.replicator.ReplicationInternal$4@40ee03d8: Session check failed
javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
at org.apache.harmony.xnet.provider.jsse.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:137)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:93)
at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:381)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:165)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
at com.couchbase.lite.support.RemoteRequest.executeRequest(RemoteRequest.java:201)
at com.couchbase.lite.support.RemoteRequest.run(RemoteRequest.java:104)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:390)
at java.util.concurrent.FutureTask.run(FutureTask.java:234)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:153)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:267)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:856)
06-08 15:06:32.023 29789-29874/com.icfi.couchbasereplicationtest E/Syncďą• com.couchbase.lite.replicator.PullerInternal@40ed1078: Progress: set error = javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
There is a chain issue with the certificate, which is why I added it to a custom keystore. There is no http server set up, only https. It doesn’t throw a security error in the browser, but httpie warns of:
http: error: SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590) while doing GET request to URL: SYNC_URL
However if I run httpie with the “–verify no” flag set, it is good to go and returns documents. I just have no idea what is wrong with my credentials in the mobile api…
Note: Storing your certificate in the KeyStore could be good. But I am not sure if ignoring/skipping certificate check is good idea from security point of view.