Skip to content

Commit

Permalink
RW-754: Added self-signed SSL cert support.
Browse files Browse the repository at this point in the history
The DeployR server supports and can be configured to require HTTPS connections from clients. Sometimes (primarily for testing or prototyping) self-signed SSL certificates are used on the server. The client library has been updated to work with servers using self-signed certs:

- RClientFactory.createClient(endpoint, allowSelfSignedSSLCert )

To facilitate these changes instances of URL are no longer returned on download calls on the API. In place of URLs, instances of InputStream are returned on the following interfaces:

- InputStream RProject.export()
- InputStream RProjectFile.download()
- InputStream RProjectResult.download()
- InputStream RRepositoryFile.download()

The underlying URL is still avaiable on the *Details instance associated with the File or Result.

All unit tests and tutorial examples have been updated to reflect these changes.
  • Loading branch information
david-russell committed Mar 31, 2015
1 parent b2b0ac4 commit a683b0e
Show file tree
Hide file tree
Showing 43 changed files with 519 additions and 351 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import com.revo.deployr.client.params.DirectoryUploadOptions;
import org.apache.log4j.Logger;

import java.net.URL;
import java.io.InputStream;
import java.util.List;

public class AuthProjectDirectory {
Expand Down Expand Up @@ -95,9 +95,15 @@ public static void main(String args[]) throws Exception {

/*
* Download working directory file content using
* standard Java URL.
* standard Java InputStream.
*/
URL fileURL = rProjectFile.download();
InputStream fileStream = null;
try {
fileStream = rProjectFile.download();
} finally {
if(fileStream != null)
fileStream.close();
}

/*
* Retrieve a list of files in the R session's
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import com.revo.deployr.client.params.RepoUploadOptions;
import org.apache.log4j.Logger;

import java.net.URL;
import java.io.InputStream;
import java.util.List;

public class AuthRepositoryManagement {
Expand Down Expand Up @@ -82,7 +82,8 @@ public static void main(String args[]) throws Exception {
* Download working directory file content using
* standard Java URL.
*/
URL fileURL = rRepositoryFile.download();
InputStream downStream = rRepositoryFile.download();
downStream.close();

/*
* Retrieve a list of files in the authenticated user's
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/revo/deployr/client/RProject.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import com.revo.deployr.client.params.ProjectCloseOptions;
import com.revo.deployr.client.params.ProjectDropOptions;

import java.net.URL;
import java.io.InputStream;

/**
* Represents a DeployR managed project.
Expand Down Expand Up @@ -183,6 +183,6 @@ public RProjectDetails recycle(boolean preserveWorkspace,
* @throws RClientException if RClient fails to complete call.
* @throws RSecurityException if DeployR server security conditions not met on call.
*/
public URL export() throws RClientException, RSecurityException;
public InputStream export() throws RClientException, RSecurityException;

}
3 changes: 2 additions & 1 deletion src/main/java/com/revo/deployr/client/RProjectFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.revo.deployr.client.params.RepoUploadOptions;

import java.net.URL;
import java.io.InputStream;

/**
* Represents a DeployR project directory file.
Expand Down Expand Up @@ -65,6 +66,6 @@ public interface RProjectFile {
* @throws RSecurityException if DeployR server security conditions not met on call.
* @see RProjectFileDetails
*/
public URL download() throws RClientException, RSecurityException;
public InputStream download() throws RClientException, RSecurityException;

}
8 changes: 8 additions & 0 deletions src/main/java/com/revo/deployr/client/RProjectResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package com.revo.deployr.client;

import com.revo.deployr.client.about.RProjectResultDetails;
import java.io.InputStream;

/**
* Represents a DeployR project execution result.
Expand All @@ -34,5 +35,12 @@ public interface RProjectResult {
*/
public void delete() throws RClientException, RSecurityException;

/**
* Download execution result.
*
* @throws RClientException if RClient fails to complete call.
* @throws RSecurityException if DeployR server security conditions not met on call.
*/
public InputStream download() throws RClientException, RSecurityException;

}
3 changes: 2 additions & 1 deletion src/main/java/com/revo/deployr/client/RRepositoryFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.revo.deployr.client.about.RRepositoryFileDetails;

import java.net.URL;
import java.io.InputStream;
import java.util.List;

/**
Expand Down Expand Up @@ -95,7 +96,7 @@ public interface RRepositoryFile {
* @throws RSecurityException if DeployR server security conditions not met on call.
* @see RRepositoryFileDetails
*/
public URL download() throws RClientException, RSecurityException;
public InputStream download() throws RClientException, RSecurityException;

/**
* Delete managed repository file.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@
*/
public class RProjectFileDetails {

public RProjectFileDetails(String filename, String descr, String type, long size, URL url) {
public RProjectFileDetails(String filename,
String descr,
String type,
long size,
URL url) {
this.filename = filename;
this.descr = descr;
this.type = type;
this.size = size;
this.url = url;
}

/**
Expand All @@ -46,4 +51,9 @@ public RProjectFileDetails(String filename, String descr, String type, long size
*/
public final long size;

/**
* Project directory file URL.
*/
public final URL url;

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@
*/
public class RProjectResultDetails {

public RProjectResultDetails(String execution, String filename, String type, long size, URL url) {
public RProjectResultDetails(String execution,
String filename,
String type,
long size,
URL url) {
this.execution = execution;
this.filename = filename;
this.type = type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public RRepositoryFileDetails(String filename, String directory,
this.category = category;
this.md5 = md5;
this.lastModified = lastModified;
this.url = url;
}

/**
Expand Down Expand Up @@ -151,4 +152,10 @@ public RRepositoryFileDetails(String filename, String directory,
*/
public final Date lastModified;

/**
* Repository file url.
*/
public final URL url;


}
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,14 @@ public interface RProjectDirectoryCalls {
* @throws RClientException if RClient fails to complete call.
* @throws RSecurityException if DeployR server security conditions not met on call.
*/
public URL downloadFiles() throws RClientException, RSecurityException;
public InputStream downloadFiles() throws RClientException, RSecurityException;

/**
* Download files from project directory.
*
* @throws RClientException if RClient fails to complete call.
* @throws RSecurityException if DeployR server security conditions not met on call.
*/
public URL downloadFiles(List<String> files) throws RClientException, RSecurityException;
public InputStream downloadFiles(List<String> files) throws RClientException, RSecurityException;

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import com.revo.deployr.client.*;
import com.revo.deployr.client.params.ProjectExecutionOptions;

import java.net.URL;
import java.io.InputStream;
import java.util.List;

/**
Expand Down Expand Up @@ -215,6 +215,6 @@ public RProjectExecution executeExternal(String externalSource,
* @throws RClientException if RClient fails to complete call.
* @throws RSecurityException if DeployR server security conditions not met on call.
*/
public URL downloadResults() throws RClientException, RSecurityException;
public InputStream downloadResults() throws RClientException, RSecurityException;

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
import com.revo.deployr.client.RSecurityException;
import com.revo.deployr.client.call.RCall;

import org.apache.http.client.utils.URIBuilder;

import java.io.InputStream;

public interface RClientExecutor {

public RCoreResult processCall(RCall call)
Expand All @@ -28,4 +32,7 @@ public RCoreResult processCallOnGrid(RCall call)
RSecurityException,
RGridException;

public InputStream download(URIBuilder builder)
throws RClientException;

}
85 changes: 79 additions & 6 deletions src/main/java/com/revo/deployr/client/core/impl/RClientImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,20 @@
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.utils.URIBuilder;
import javax.net.ssl.SSLContext;
import org.apache.http.conn.ssl.*;
import org.apache.http.config.*;
import org.apache.http.conn.socket.*;
import org.apache.http.impl.client.HttpClients;
import java.security.cert.X509Certificate;
import java.security.*;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;

import java.util.*;
import java.net.*;
import java.io.*;

import java.util.concurrent.Executors;
import java.util.concurrent.Callable;
Expand All @@ -91,6 +102,7 @@ public class RClientImpl implements RClient, RClientExecutor {
private ExecutorService eService;
private String serverurl;
private String httpcookie;
private SSLSocketFactory sslSocketFactory;
private RLiveContext liveContext;

private ArrayList<Integer> GRID_EXCEPTION_CODES = new ArrayList<Integer>(
Expand All @@ -99,13 +111,24 @@ public class RClientImpl implements RClient, RClientExecutor {
public RClientImpl(String serverurl)
throws RClientException, RSecurityException {

this(serverurl, 200);
this(serverurl, 200, false);
}

public RClientImpl(String serverurl, int concurrentCallLimit)
throws RClientException, RSecurityException {

log.debug("Creating client connection: serverurl=" + serverurl + " concurrentCallLimit=" + concurrentCallLimit);
this(serverurl, concurrentCallLimit, false);
}

public RClientImpl(String serverurl,
int concurrentCallLimit,
boolean allowSelfSignedSSLCert)
throws RClientException, RSecurityException {


log.debug("Creating client connection: serverurl=" + serverurl +
", concurrentCallLimit=" + concurrentCallLimit +
", allowSelfSignedSSLCert=" + allowSelfSignedSSLCert);

this.serverurl = serverurl;

Expand All @@ -114,20 +137,52 @@ public RClientImpl(String serverurl, int concurrentCallLimit)
// Set Infinite Connection and Socket Timeouts.
HttpConnectionParams.setConnectionTimeout(httpParams, 0);
HttpConnectionParams.setSoTimeout(httpParams, 0);
ConnManagerParams.setMaxTotalConnections(httpParams, concurrentCallLimit);
ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(concurrentCallLimit));
ConnManagerParams.setMaxTotalConnections(httpParams,
concurrentCallLimit);
ConnManagerParams.setMaxConnectionsPerRoute(httpParams,
new ConnPerRouteBean(concurrentCallLimit));
HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);

// Create and initialize scheme registry
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(
new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));

if(allowSelfSignedSSLCert) {
/*
* Register scheme for "https" that bypasses
* SSL cert trusted-origin verification check
* which makes it possible to connect to a
* DeployR server using a self-signed certificate.
*
* Recommended for prototyping and testing only,
* not recommended for production environments.
*/
TrustStrategy blindTrust = new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] certificate,
String authType) {
return true;
}
};
try {
sslSocketFactory = new SSLSocketFactory(blindTrust,
SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
schemeRegistry.register(new Scheme("https",
8443, sslSocketFactory));
} catch(GeneralSecurityException gsex) {
String exMsg = "Self-signed SSL cert config failed, " +
gsex.getMessage();
log.debug(exMsg);
throw new RSecurityException(exMsg, 0);
}
}

// Create a HttpClient with the ThreadSafeClientConnManager.
// This connection manager must be used if more than one thread will
// be using the HttpClient.
ClientConnectionManager cm =
new ThreadSafeClientConnManager(httpParams, schemeRegistry);
new ThreadSafeClientConnManager(httpParams, schemeRegistry);

httpClient = new DefaultHttpClient(cm, httpParams);

Expand Down Expand Up @@ -556,6 +611,24 @@ public RCoreResult processCallOnGrid(RCall rCall)
return rResult;
}

public InputStream download(URIBuilder builder)
throws RClientException {

try {
log.debug("download: uri builder=" + builder);
String uriPath = builder.build().toString();
HttpGet request = new HttpGet(uriPath);
HttpResponse response = httpClient.execute(request);
return response.getEntity().getContent();

} catch(Exception ex){
String exMsg = builder +
" download failed, " + ex.getMessage();
throw new RClientException(exMsg, ex);
}

}

// Private method implementations.

public RCoreResponse execute(RCall call) {
Expand Down
Loading

0 comments on commit a683b0e

Please sign in to comment.