In the following cases SSL error is returned:
Exception in thread "main" javax.net.ssl. SSLPeerUnverifiedException: peer not authenticated at com.sun.net.ssl.internal.ssl.SSLSessionImpl.getPeerCertificates(Unknown Source) at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:126) at org.apache.http.conn.ssl.SSLSocketFactory.createLayeredSocket(SSLSocketFactory.java:493) at org.apache.http.impl.conn.DefaultClientConnectionOperator.updateSecureConnection(DefaultClientConnectionOperator.java:232) at org.apache.http.impl.conn.ManagedClientConnectionImpl.layerProtocol(ManagedClientConnectionImpl.java:401) at org.apache.http.impl.client.DefaultRequestDirector.establishRoute(DefaultRequestDirector.java:840) at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:647) at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479) at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906) at org.apache.http.impl.client.DecompressingHttpClient.execute(DecompressingHttpClient.java:137) at org.apache.http.impl.client.DecompressingHttpClient.execute(DecompressingHttpClient.java:108) at com.rallydev.rest.client.HttpClient.executeRequest(HttpClient.java:157) at com.rallydev.rest.client.HttpClient.doRequest(HttpClient.java:145) at com.rallydev.rest.client.BasicAuthClient.doRequest(BasicAuthClient.java:56) at com.rallydev.rest.client.HttpClient.doGet(HttpClient.java:221) at com.rallydev.rest.RallyRestApi.query(RallyRestApi.java:168) at rest.authenticate(rest.java:64) at rest.main(rest.java:905)
Generally, invalid or expired certificates cause "javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated".
SSL certificates use a chain of trust, where each certificate is signed by a higher, more credible certificate. At the top of the chain of trust are the root certificates, owned by Verisign or others certifcate authorities.
When using a self-signed certificate, there is no chain of trust. A web browser will issue a warning when a web site certificate cannot be verified, but the user can dismiss the warning and it will not appear again. But a java app is more stringent than a browser and it needs to be explicitly told to tolerate invalid certificate chains.
CA Agile Central REST Toolkit for Java does not support that scenario out of box, and custom code is needed for that use case.
As mentioned here, Rally does not actively maintain or support the toolkit.
The reason for this caveat is that it is a community effort, and not an enterprise effort. The source is available on github, and customization is possible.
As of rally-rest-api-2.1.1.jar the toolkit is current, and works with latest features of WS API v2.0.
Starting with 2.1 version of the jar the toolkit allows access to the HTTPClient under it.
It means that when we instantiate RallyRestApi:
String host = "https://rally1.rallydev.com"; String apiKey = "<Password>"; RallyRestApi restApi = new RallyRestApi(new URI(host),apiKey); restApi.setProxy(new URI("http://<YOUR_HOST_NAME_OR_IP>"), "MyProxyUsername", "MyProxyPassword");
we may access HttpClient object with getClient() method:
HttpClient client = restApi.getClient();
From there we may customize client to ignore invalid certificate chains and workaround SSLPeerUnverifiedException: peer not authenticated
exception. Here is a full code example:
import com.rallydev.rest.RallyRestApi; import com.rallydev.rest.client.HttpClient; import com.rallydev.rest.request.GetRequest; import com.rallydev.rest.response.GetResponse; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.conn.scheme.Scheme; public class ConnnectionTestWithHTTPClient { public static void main(String[] args) throws URISyntaxException, IOException { String host = "https://rally1.rallydev.com"; String apiKey = "<Your_Password>"; String applicationName = "Connnection Test With HTTPClient"; RallyRestApi restApi = new RallyRestApi(new URI(host),apiKey); restApi.setApplicationName(applicationName); //restApi.setProxy(new URI("http://<YOUR_HOST_NAME_OR_IP>"), "MyProxyUsername", "MyProxyPassword"); //YOUR PROXY SETTINGS HERE HttpClient client = restApi.getClient(); try { SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy() { public boolean isTrusted(X509Certificate[] certificate, String authType) throws CertificateException { //trust all certs return true; } }, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); client.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 443, sf)); String workspaceRef = "/workspace/<Workspace OID>"; //YOUR VALID WORKSPACE OID HERE GetRequest getRequest = new GetRequest(workspaceRef); GetResponse getResponse = restApi.get(getRequest); System.out.println(getResponse.getObject()); } catch (Exception e) { System.out.println(e); } finally { restApi.close(); } } }
The same java code can be used to ignore self-signed certificate when connecting to On-premises instance. The only difference is that the host will not point to rall1.rallydev.com but to a specific on-premise instance,e.g.
String host = "https://<YOUR_HOST_NAME_OR_IP>";
Here is a C# code example for On-premises case:
using System; using System.Collections.Generic; using System.Collections; using System.Linq; using System.Text; using Rally.RestApi; using Rally.RestApi.Response; // The following are SSL Cert related libraries using System.Security.Cryptography.X509Certificates; using System.Net.Security; using System.Net; namespace ConnectToOnPremises { class Program { static void Main(string[] args) { // Trust the un-trusted connection ValidateCertificate(); RallyRestApi restApi; restApi = new RallyRestApi("<User>@<Company.com>", "<Your_Password>", "<YOUR_HOST_NAME_OR_IP>", "v2.0"); //USER YOUR OWN URL DynamicJsonObject sub = restApi.GetSubscription("Workspaces"); Request wRequest = new Request(sub["Workspaces"]); wRequest.Limit = 1000; QueryResult queryResult = restApi.Query(wRequest); int allProjects = 0; foreach (var result in queryResult.Results) { var workspaceReference = result["_ref"]; var workspaceName = result["Name"]; Console.WriteLine("Workspace: " + workspaceName); Request projectsRequest = new Request(result["Projects"]); projectsRequest.Fetch = new List<string>() {"Name"}; projectsRequest.Limit = 1000; //project requests are made per workspace QueryResult queryProjectResult = restApi.Query(projectsRequest); int projectsPerWorkspace = 0; foreach (var p in queryProjectResult.Results) { allProjects++; projectsPerWorkspace++; Console.WriteLine(projectsPerWorkspace + " Project: " + p["Name"] + " State: " + p["State"]); } Console.WriteLine("----------------------------"); } } private static void ValidateCertificate() { // The following code is required to connect to an on-premise Rally server without a trusted cert uploaded // If we remove this code it throws the following error // Could not establish trust relationship for the SSL/TLS secure channel". // This code has to placed before starting any calls to the webservise. TrustAllCertificatePolicy trustAll = new TrustAllCertificatePolicy(); System.Net.ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(TrustAllCertificatePolicy.AcceptAllCerts); } } public class TrustAllCertificatePolicy : ICertificatePolicy { //Default policy for certificate validation. public static bool DefaultValidate = false; public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate cert, WebRequest request, int problem) { return true; } public static bool AcceptAllCerts(object sender, X509Certificate cert, X509Chain chain, System.Net.Security.SslPolicyErrors SslPolicyErrors) { return true; } } }