Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Default HostnameVerifier for ignoreAllCerts #35

Merged
merged 2 commits into from

2 participants

@dominicfarr

Added AllowAllHostnameVerifier; cleaned up Resty.ignoreAllCerts(); added test ssl server and tests.

@dominicfarr

resolve #35

@beders beders merged commit faa72e6 into from
@beders
Owner

Thank you for your contribution!

@dominicfarr

Some of the integration tests were a little rough, but something to leverage.
If you need other improvements, let me know, happy to help where I can.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 11, 2014
  1. @dominicfarr
  2. @dominicfarr

    Update .gitignore

    dominicfarr authored
This page is out of date. Refresh to see the latest.
View
23 .gitignore
@@ -1,8 +1,17 @@
-target/*
-.settings/*
-*.ipr
+# Ignore all hidden files, except this .gitignore file.
+.*
+!.sorting
+!.gitignore
+!.mavenrc
+# Ignore all files with the following extension.
+*.log
*.iws
-.classpath
-.project
-bin/*
-*~
+*.orig
+*.iml
+*.ipr
+.idea
+*.ids
+*.pyc
+# Ignore the build directory
+target
+
View
41 pom.xml
@@ -70,6 +70,35 @@
<charset>utf-8</charset>
</configuration>
</plugin>
+ <!--<plugin>--> <!-- quick way for maven to make keystore -->
+ <!--<groupId>org.codehaus.mojo</groupId>-->
+ <!--<artifactId>keytool-maven-plugin</artifactId>-->
+ <!--<version>1.3</version>-->
+ <!--<executions>-->
+ <!--<execution>-->
+ <!--<phase>generate-resources</phase>-->
+ <!--<id>clean</id>-->
+ <!--<goals>-->
+ <!--<goal>clean</goal>-->
+ <!--</goals>-->
+ <!--</execution>-->
+ <!--<execution>-->
+ <!--<phase>generate-resources</phase>-->
+ <!--<id>genkey</id>-->
+ <!--<goals>-->
+ <!--<goal>generateKeyPair</goal>-->
+ <!--</goals>-->
+ <!--</execution>-->
+ <!--</executions>-->
+ <!--<configuration>-->
+ <!--<keystore>${project.build.directory}/test-ssl-hostname-eq-localhost.keystore</keystore>-->
+ <!--<dname>cn=localhost</dname>-->
+ <!--<keypass>testpass</keypass>-->
+ <!--<storepass>testpass</storepass>-->
+ <!--<alias>test</alias>-->
+ <!--<keyalg>RSA</keyalg>-->
+ <!--</configuration>-->
+ <!--</plugin>-->
</plugins>
</build>
<repositories>
@@ -113,6 +142,18 @@
<version>1.1</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>16.0</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-multipart</artifactId>
View
189 src/main/java/us/monoid/web/Resty.java
@@ -11,53 +11,48 @@
import java.net.URI;
import java.net.URLConnection;
import java.net.URLEncoder;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
-import java.util.logging.Logger;
import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
import javax.xml.xpath.XPathException;
import us.monoid.json.JSONObject;
import us.monoid.web.auth.RestyAuthenticator;
import us.monoid.web.mime.MultipartContent;
+import us.monoid.web.ssl.AllowAllHostnameVerifier;
+import us.monoid.web.ssl.TrustAllX509SocketFactory;
/**
* Main class. Use me! Use me! Resty is a small, convenient interface to talk to RESTful services.
- *
+ *
* Basic usage is very simple: Create a Resty instance, use authenticate methode to add credentials (optional), then call one of the content type specific methods,
- * like json(...), xml(...), text(...) or bytes(...).
- *
+ * like json(...), xml(...), text(...) or bytes(...).
+ *
* The idea is that the method name
* will convey the expected content type you can then operate on. Most static methods help you build content objects or queries with a compact syntax. Static methods like put(...) and delete() are
* used to implement the respective HTTP methods.
- *
+ *
* A neat trick to save you typing is to use <pre><code>import static us.monoid.web.Resty.*;</code></pre>
* <p>
- *
+ *
* GETting an URL (as JSON):
* <pre><code>new Resty().json(url);</code></pre>
- *
+ *
* POSTing to an URL (using multipart/form-data) and expecting JSON back:
* <pre><code>new Resty().json(url, form(data("name", "Don Draper"), data("occupation", "Ad Man")));</code></pre>
- *
+ *
* PUTting content and expecting JSON back:
* <pre><code>
* new Resty().json(url, put(content(someJSON)));
* </code></pre>
- *
+ *
* DELETE a resource via URL expecting JSON back:
* <pre><code>new Resty().json(url, delete());</code></pre>
*
- *
+ *
* Here is an example on how to use the geonames web service. It retrieves the json object (see json.org for details) and gets the name of a place from the zip code:
- *
+ *
* <pre>
* <code>
* Resty r = new Resty();
@@ -65,19 +60,19 @@
* assertEquals(name, "Rehlingen-Siersburg");
* </code>
* </pre>
- *
+ *
* The return value is a resource with the data you requested AND a new Resty instance with the same set of options you initialized Resty with.
- *
- *
+ *
+ *
* Resty supports complex path queries to navigate into a json object. This is mainly used for extracting URIs to surf along a series of REST resources for web services following the HATEOS paradigm.
- *
+ *
* Resty objects are not re-entrant.
- *
+ *
* You can also specify options when creating a Resty instance. Well, currently there is one option to set the timeout for connections.
* But you can also create your own options! See Resty.Option for more info.
- *
+ *
* @author beders
- *
+ *
*/
public class Resty {
@@ -105,14 +100,14 @@
* Create an instance of Resty with the following list of options.
* <b>Also, options are carried over to resources created by calls to json/text/binary etc.</b>
* Use {@link #setOptions(Option...)} to change options afterwards.
- *
+ *
*/
public Resty(Option... someOptions) {
setOptions(someOptions);
}
-
+
/** Set options if you missed your opportunity in the c'tor or if you want to change the options.
- *
+ *
* @param someOptions new set of options
* @return
*/
@@ -128,7 +123,7 @@ public Resty setOptions(Option... someOptions) {
* Register this root URI for authentication. Whenever a URL is requested that starts with this root, the credentials given are used for HTTP AUTH. Note that currently authentication information is
* shared across all Resty instances. This is due to the shortcomings of the java.net authentication mechanism. This might change should Resty adopt HttpClient and is the reason why this method is
* not a static one.
- *
+ *
* @param aSite
* the root URI of the site
* @param aLogin
@@ -141,9 +136,9 @@ public void authenticate(URI aSite, String aLogin, char[] aPwd) {
}
/**
- *
+ *
* @see Resty#authenticate(URI, String, char[])
- *
+ *
* @param string
* @param aLogin
* @param charArray
@@ -151,12 +146,12 @@ public void authenticate(URI aSite, String aLogin, char[] aPwd) {
public void authenticate(String string, String aLogin, char[] charArray) {
authenticate(URI.create(string), aLogin, charArray);
}
-
+
/**
* Register a login password for the realm returned by the authorization challenge.
* Use this method instead of authenticate in case the URL is not made available to the java.net.Authenticator class
- *
- * @param realm the realm (see rfc2617, section 1.2)
+ *
+ * @param realm the realm (see rfc2617, section 1.2)
* @param aLogin
* @param charArray
*/
@@ -174,7 +169,7 @@ public Resty identifyAsMozilla() {
/**
* Sets the User-Agent to Resty. WHICH IS THE DEFAULT. Sorry for yelling.
- *
+ *
*/
public Resty identifyAsResty() {
userAgent = DEFAULT_USER_AGENT;
@@ -183,7 +178,7 @@ public Resty identifyAsResty() {
/**
* GET a URI given by string and parse the result as JSON.
- *
+ *
* @param string
* - the string to use as URI
* @see Resty#json(URI) for more docs
@@ -194,7 +189,7 @@ public JSONResource json(String string) throws IOException {
/**
* GET a URI and parse the result as JSON.
- *
+ *
* @param anUri
* the URI to request
* @return the JSONObject, wrapped in a neat JSONResource
@@ -210,7 +205,7 @@ protected JSONResource createJSONResource() {
/**
* POST to a URI and parse the result as JSON
- *
+ *
* @param anUri
* the URI to visit
* @param requestContent
@@ -230,7 +225,7 @@ public JSONResource json(String anUri, AbstractContent content) throws IOExcepti
/**
* Get a plain text resource for the specified URI.
- *
+ *
* @param anUri
* the URI to follow
* @return a plain text resource, if available
@@ -247,7 +242,7 @@ protected TextResource createTextResource() {
/**
* Get a plain text resource for the specified URI by POSTing to it.
- *
+ *
* @param anUri
* the URI to follow
* @return a plain text resource, if available
@@ -260,7 +255,7 @@ public TextResource text(URI anUri, AbstractContent content) throws IOException
/**
* Get a plain text resource for the specified URI.
- *
+ *
* @param anUri
* the URI to follow
* @return a plain text resource, if available
@@ -273,7 +268,7 @@ public TextResource text(String anUri) throws IOException {
/**
* Get a plain text resource for the specified URI by POSTing to it.
- *
+ *
* @param anUri
* the URI to follow
* @return a plain text resource, if available
@@ -286,7 +281,7 @@ public TextResource text(String anUri, AbstractContent content) throws IOExcepti
/**
* GET a URI given by string and parse the result as XML.
- *
+ *
* @param string
* - the string to use as URI
* @see Resty#xml(URI) for more docs
@@ -297,7 +292,7 @@ public XMLResource xml(String string) throws IOException {
/**
* GET a URI and parse the result as XML.
- *
+ *
* @param anUri
* the URI to request
* @return the XML, wrapped in a neat XMLResource
@@ -313,7 +308,7 @@ protected XMLResource createXMLResource() {
/**
* POST to a URI and parse the result as XML
- *
+ *
* @param anUri
* the URI to visit
* @param requestContent
@@ -333,7 +328,7 @@ public XMLResource xml(String anUri, AbstractContent content) throws IOException
/**
* Get the resource specified by the uri and return a binary resource for it.
- *
+ *
* @param anUri
* the uri to follow
* @return
@@ -345,7 +340,7 @@ public BinaryResource bytes(String anUri) throws IOException {
/**
* Get the resource specified by the uri and return a binary resource for it.
- *
+ *
* @param uri
* the uri to follow
* @return
@@ -361,7 +356,7 @@ protected BinaryResource createBinaryResource() {
/**
* POST to the URI and get the resource as binary resource.
- *
+ *
* @param anUri
* the uri to follow
* @return
@@ -373,7 +368,7 @@ public BinaryResource bytes(String anUri, AbstractContent someContent) throws IO
/**
* POST to the URI and get the resource as binary resource.
- *
+ *
* @param uri
* the uri to follow
* @return
@@ -419,7 +414,7 @@ protected void addAdditionalHeaders(URLConnection con) {
/**
* Get the content from the URLConnection, create a Resource representing the content and carry over some metadata like HTTP Result and location header.
- *
+ *
* @param <T extends AbstractResource> the resource that will be created and filled
* @param con
* the URLConnection used to get the data
@@ -439,9 +434,9 @@ protected void addAdditionalHeaders(URLConnection con) {
* <code>
* Resty r = new Resty();
* r.json(someUrl).json(path("path.to.url.in.json"));
- *
+ *
* </code>
- *
+ *
* @param string
* @return
*/
@@ -452,7 +447,7 @@ public static JSONPathQuery path(String string) {
/**
* Create an XPathQuery to extract data from an XML document. This is usually used to extract a URI and use it in json|text|xml(XPathQuery...) methods. In this case, your XPath must result in a
* String value, i.e. it can't just extract an Element.
- *
+ *
* @param anXPathExpression
* an XPath expression with result type String
* @return the query
@@ -464,7 +459,7 @@ public static XPathQuery xpath(String anXPathExpression) throws XPathException {
/**
* Create a content object from JSON. Use this to POST the content to a URL.
- *
+ *
* @param someJson
* the JSON to use
* @return the content to send
@@ -480,7 +475,7 @@ public static Content content(JSONObject someJson) {
/**
* Create a content object from plain text. Use this to POST the content to a URL.
- *
+ *
* @param somePlainText
* the plain text to send
* @return the content to send
@@ -496,7 +491,7 @@ public static Content content(String somePlainText) {
/**
* Create a content object from a byte array. Use this to POST the content to a URL with mime type application/octet-stream.
- *
+ *
* @param bytes
* the bytes to send
* @return the content to send
@@ -504,10 +499,10 @@ public static Content content(String somePlainText) {
public static Content content(byte[] bytes) {
return new Content("application/octet-stream", bytes);
}
-
+
/**
* Create form content as application/x-www-form-urlencoded (i.e. a=b&c=d&...)
- *
+ *
* @param query
* the preformatted, properly encoded form data
* @return a content object to be useable for upload
@@ -519,8 +514,8 @@ public static FormContent form(String query) {
/**
* Create form content to be sent as multipart/form-data. Useful if you want to upload files or have tons of form data that looks really ugly in a URL.
- *
- *
+ *
+ *
*/
public static MultipartContent form(FormData... formData) {
MultipartContent mc = new MultipartContent("form-data", formData);
@@ -529,7 +524,7 @@ public static MultipartContent form(FormData... formData) {
/**
* Create a plain/text form data entry for a multipart form.
- *
+ *
* @param name
* the name of the control of the form
* @param plainTextValue
@@ -542,7 +537,7 @@ public static FormData data(String name, String plainTextValue) {
/**
* Create a form data entry for a multipart form with any kind of content type.
- *
+ *
* @param name
* the name of the control or variable in a form
* @param content
@@ -557,7 +552,7 @@ public static FormData data(String name, AbstractContent content) {
/**
* Shortcut to URLEncoder.encode with UTF-8.
- *
+ *
* @param unencodedString
* the string to encode
* @return the URL encoded string, safe to be used in URLs
@@ -587,7 +582,7 @@ public static AbstractContent delete() {
/**
* Tell Resty to send the specified header with each request done on this instance. These headers will also be sent from any resource object returned by this instance. I.e. chained calls will carry
* over the headers r.json(url).json(get("some.path.to.a.url")); Multiple headers of the same type are not supported (yet).
- *
+ *
* @deprecated
* @param aHeader
* the header to send
@@ -601,7 +596,7 @@ public void alwaysSend(String aHeader, String aValue) {
/**
* Tell Resty to send the specified header with each request done on this instance. These headers will also be sent from any resource object returned by this instance. I.e. chained calls will carry
* over the headers r.json(url).json(get("some.path.to.a.url")); Multiple headers of the same type are not supported (yet).
- *
+ *
* @param aHeader
* the header to send
* @param aValue
@@ -610,10 +605,10 @@ public void alwaysSend(String aHeader, String aValue) {
public void withHeader(String aHeader, String aValue) {
getAdditionalHeaders().put(aHeader, aValue);
}
-
+
/**
* Don't send a header that was formely added in the alwaysSend method.
- *
+ *
* @param aHeader
* the header to remove
*/
@@ -628,35 +623,26 @@ public void dontSend(String aHeader) {
return additionalHeaders;
}
- /** Install a SSL socket factory which will trust all certificates.
- * This is generally considered dangerous as you won't know if you are really talking to the server you think you are talking to.
- * This is like your best friend using his Facebook account in an Apple store and forgetting to log out.
- *
- * This method should be called once and replaces the SSL factory for ALL HttpsURLConnections.
- */
- public static void ignoreAllCerts() {
- TrustManager trm = new X509TrustManager() {
- public void checkClientTrusted(X509Certificate[] certs, String authType) {}
- public void checkServerTrusted(X509Certificate[] certs, String authType) {}
- public X509Certificate[] getAcceptedIssuers() { return null; }
- };
-
- SSLContext sc;
- try {
- sc = SSLContext.getInstance("SSL");
- sc.init(null, new TrustManager[] { trm }, null);
- HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
- } catch (KeyManagementException e) {
- e.printStackTrace();
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- }
- }
-
- /** Set the proxy for this instance of Resty.
+ /**
+ * Defines the HttpsURLConnection's default SSLSocketFactory and HostnameVerifier so that all subsequence HttpsURLConnection instances
+ * will trusts all certificates and accept all certificate hostnames.
+ * <p/>
+ * WARNING: Using this is dangerous as it bypasses most of what ssl certificates are made for. However, self-signed certificate, testing, and
+ * domains with multiple sub-domains will not fail handshake verification when this setting is applied.
+ */
+ public static void ignoreAllCerts() {
+ try {
+ HttpsURLConnection.setDefaultSSLSocketFactory(TrustAllX509SocketFactory.getSSLSocketFactory());
+ HttpsURLConnection.setDefaultHostnameVerifier(AllowAllHostnameVerifier.ALLOW_ALL_HOSTNAMES);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to set 'Trust all' default SSL SocketFactory and Hostname Verifier", e);
+ }
+ }
+
+ /** Set the proxy for this instance of Resty.
* Note, that the proxy settings will be carried over to Resty instances created by this instance only if you used
* new Resty(Option.proxy(...))!
- *
+ *
* @param proxyhost name of the host
* @param proxyport port to be used
*/
@@ -665,14 +651,14 @@ public void setProxy(String proxyhost, int proxyport) {
}
/**
- * Base class for Resty options. You can also create your own options.
+ * Base class for Resty options. You can also create your own options.
* Override one of the apply methods to change an object like URLConnection before it is being used.
- *
+ *
* @author beders
- *
+ *
*/
abstract public static class Option {
-
+
/** Override this to get access to the URLConnection before the actual connection is made.
* @param aConnection
*/
@@ -686,7 +672,7 @@ public void init(Resty resty) {
/**
* Specify the connection timeout in milliseconds.
- * Example: <code><pre> new Resty(Option.timeout(3000)); </pre></code>
+ * Example: <code><pre> new Resty(Option.timeout(3000)); </pre></code>
* @see java.net.URLConnection#setConnectTimeout(int)
* @param t
* the timeout
@@ -695,8 +681,8 @@ public void init(Resty resty) {
public static Timeout timeout(int t) {
return new Timeout(t);
}
-
- /**
+
+ /**
* Set a proxy (overrides standard proxy settings)
* @param aHostName the hostname to use
* @param aPortNumber the port number
@@ -720,7 +706,7 @@ public void apply(URLConnection urlConnection) {
}
}
-
+
/** Option to set the proxy for a Resty instance.
*/
public static class Proxy extends Option {
@@ -735,4 +721,5 @@ public void init(Resty resty) {
resty.setProxy(host,port);
}
}
+
}
View
19 src/main/java/us/monoid/web/ssl/AllowAllHostnameVerifier.java
@@ -0,0 +1,19 @@
+package us.monoid.web.ssl;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLSession;
+
+/**
+ * This HostnameVerifier turns off hostname verification.
+ *
+ * WARNING: Using this is dangerous as it bypasses an importance part of SSL handshaking. However, good for testing...
+ */
+public final class AllowAllHostnameVerifier implements HostnameVerifier {
+
+ public static final HostnameVerifier ALLOW_ALL_HOSTNAMES = new AllowAllHostnameVerifier();
+
+ @Override
+ public boolean verify(String s, SSLSession sslSession) {
+ return true;
+ }
+}
View
15 src/main/java/us/monoid/web/ssl/TrustAllX509Certificates.java
@@ -0,0 +1,15 @@
+package us.monoid.web.ssl;
+
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.security.cert.X509Certificate;
+
+final class TrustAllX509Certificates implements X509TrustManager {
+ static final TrustManager[] TRUST_MANAGER = new TrustManager[] { new TrustAllX509Certificates() };
+
+ public void checkClientTrusted(X509Certificate[] certs, String authType) {}
+
+ public void checkServerTrusted(X509Certificate[] certs, String authType) {}
+
+ public X509Certificate[] getAcceptedIssuers() { return null; }
+}
View
14 src/main/java/us/monoid/web/ssl/TrustAllX509SocketFactory.java
@@ -0,0 +1,14 @@
+package us.monoid.web.ssl;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+public class TrustAllX509SocketFactory {
+ public static SSLSocketFactory getSSLSocketFactory() throws Exception {
+ SSLContext sc = SSLContext.getInstance("SSL");
+ sc.init(null, TrustAllX509Certificates.TRUST_MANAGER, null);
+ return sc.getSocketFactory();
+ }
+
+}
View
18 src/test/java/us/monoid/web/RestyTest.java
@@ -1,11 +1,20 @@
package us.monoid.web;
+import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.*;
import static us.monoid.web.Resty.*;
import org.junit.Test;
+import sun.net.www.protocol.https.HttpsURLConnectionImpl;
import us.monoid.web.Resty;
+import us.monoid.web.ssl.AllowAllHostnameVerifier;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSocketFactory;
+import java.io.IOException;
+import java.net.Socket;
public class RestyTest {
@@ -62,5 +71,14 @@ public void formDataPost() throws Exception {
//
// }
+
+ @Test
+ public void shouldSetDefaultHostnameVerifierToAllowAllHostnamesWhenIgnoreAllCertsIsSet() {
+ Resty.ignoreAllCerts();
+
+ HostnameVerifier defaultHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
+
+ assertThat("Should be static AllowAllHostnameVerifier", defaultHostnameVerifier, equalTo(AllowAllHostnameVerifier.ALLOW_ALL_HOSTNAMES));
+ }
}
View
53 src/test/java/us/monoid/web/ssl/AbstractSSLServerTest.java
@@ -0,0 +1,53 @@
+package us.monoid.web.ssl;
+
+import com.google.common.io.Resources;
+import com.sun.grizzly.SSLConfig;
+import com.sun.grizzly.http.embed.GrizzlyWebServer;
+import com.sun.grizzly.http.servlet.ServletAdapter;
+import com.sun.jersey.spi.container.servlet.ServletContainer;
+
+import java.io.File;
+import java.net.URL;
+
+public abstract class AbstractSSLServerTest {
+ GrizzlyWebServer webServer;
+
+ protected void startServer(String keystorePath) throws Exception {
+
+ webServer = new GrizzlyWebServer(getPort(), ".", true);
+
+ SSLConfig sslConfig = new SSLConfig();
+
+ URL resource = Resources.getResource(keystorePath);
+
+ if (resource != null) {
+ String path = new File(resource.toURI()).getAbsolutePath();
+ sslConfig.setKeyStoreFile(path);
+ sslConfig.setKeyStorePass("testpass");
+ } else {
+ throw new RuntimeException("Failed to find test keystore");
+ }
+ webServer.setSSLConfig(sslConfig);
+
+ // Jersey web resources
+ ServletAdapter jerseyAdapter = new ServletAdapter();
+ jerseyAdapter.addInitParameter("com.sun.jersey.config.property.packages", "us.monoid.web.ssl");
+ jerseyAdapter.setContextPath("/");
+
+ jerseyAdapter.setServletInstance(new ServletContainer());
+
+ // register all above defined adapters
+ webServer.addGrizzlyAdapter(jerseyAdapter, new String[] {"/"});
+
+ // let Grizzly run
+ webServer.start();
+ }
+
+ protected int getPort() {
+ return 8443;
+ }
+
+ public void stopServer() {
+ webServer.stop();
+ }
+}
View
19 src/test/java/us/monoid/web/ssl/AllowAllHostnameVerifierTest.java
@@ -0,0 +1,19 @@
+package us.monoid.web.ssl;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import javax.net.ssl.SSLSession;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+public class AllowAllHostnameVerifierTest {
+
+ private static AllowAllHostnameVerifier ALL_ALL_HOSTNAMES = new AllowAllHostnameVerifier();
+
+ @Test
+ public void shouldAllowAllHostnames() {
+ assertThat("Should always verify true, but was false", ALL_ALL_HOSTNAMES.verify("AnyString", Mockito.mock(SSLSession.class)), equalTo(true));
+ }
+}
View
18 src/test/java/us/monoid/web/ssl/HelloWorldTestResource.java
@@ -0,0 +1,18 @@
+package us.monoid.web.ssl;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+
+@Path(HelloWorldTestResource.HELLO_WORLD_PATH)
+@Consumes(MediaType.APPLICATION_JSON)
+public class HelloWorldTestResource {
+ public final static String HELLO_WORLD = "Hello World";
+ public static final String HELLO_WORLD_PATH = "/hello-world";
+
+ @GET
+ public String get() {
+ return HELLO_WORLD;
+ }
+}
View
62 src/test/java/us/monoid/web/ssl/IgnoreAllCertsTest.java
@@ -0,0 +1,62 @@
+package us.monoid.web.ssl;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import sun.net.www.protocol.https.DefaultHostnameVerifier;
+import sun.security.provider.certpath.SunCertPathBuilderException;
+import sun.security.ssl.SSLSocketFactoryImpl;
+import sun.security.validator.ValidatorException;
+import us.monoid.web.Resty;
+import us.monoid.web.TextResource;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLHandshakeException;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+public class IgnoreAllCertsTest extends AbstractSSLServerTest {
+
+ @After
+ public void tearDown() {
+ super.stopServer();
+ }
+
+ @Test
+ public void shouldAllowConnectionToResourceWhereCertAndHostnameAreInvalidButWhenIgnoreAllCertsIsSet() throws Exception {
+ startServer("us/monoid/web/ssl/test-ssl-hostname-eq-site.com.keystore");
+
+ Resty.ignoreAllCerts();
+
+ Resty resty = new Resty();
+
+ TextResource response = resty.text(String.format("https://localhost:%d%s", getPort(), HelloWorldTestResource.HELLO_WORLD_PATH));
+
+ assertThat(response.toString(), equalTo(HelloWorldTestResource.HELLO_WORLD));
+ }
+
+ @Test(expected = SSLHandshakeException.class)
+ public void shouldFailSSLHandshakeWhenHostnameMatchesButCertificateIsInvalid() throws Exception {
+ HttpsURLConnection.setDefaultSSLSocketFactory(new SSLSocketFactoryImpl());
+ HttpsURLConnection.setDefaultHostnameVerifier(new DefaultHostnameVerifier());
+
+ startServer("us/monoid/web/ssl/test-ssl-hostname-eq-localhost.keystore");
+
+ Resty resty = new Resty();
+
+ resty.text(String.format("https://localhost:%d%s", getPort(), HelloWorldTestResource.HELLO_WORLD_PATH));
+ }
+
+ @Test(expected = SSLHandshakeException.class)
+ public void shouldFailWhenCertificateHostnameDoesNotMatchAndHostnameIsNotIgnored() throws Exception {
+ HttpsURLConnection.setDefaultSSLSocketFactory(new SSLSocketFactoryImpl());
+ HttpsURLConnection.setDefaultHostnameVerifier(AllowAllHostnameVerifier.ALLOW_ALL_HOSTNAMES);
+
+ startServer("us/monoid/web/ssl/test-ssl-hostname-eq-site.com.keystore");
+
+ Resty resty = new Resty();
+
+ resty.text(String.format("https://localhost:%d%s", getPort(), HelloWorldTestResource.HELLO_WORLD_PATH));
+ }
+}
View
BIN  src/test/resources/us/monoid/web/ssl/test-ssl-hostname-eq-localhost.keystore
Binary file not shown
View
BIN  src/test/resources/us/monoid/web/ssl/test-ssl-hostname-eq-site.com.keystore
Binary file not shown
Something went wrong with that request. Please try again.