Skip to content

Commit

Permalink
feat(iot-dev): Add basic authentication support for proxying over https
Browse files Browse the repository at this point in the history
  • Loading branch information
timtay-microsoft committed Sep 30, 2019
1 parent f044788 commit 549a7af
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@

package com.microsoft.azure.sdk.iot.device.transport.https;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.microsoft.azure.sdk.iot.deps.transport.http.HttpMethod;
import com.microsoft.azure.sdk.iot.device.ProxySettings;
import com.microsoft.azure.sdk.iot.device.exceptions.TransportException;
import com.microsoft.azure.sdk.iot.device.transport.HttpProxySocketFactory;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
Expand Down Expand Up @@ -38,6 +36,8 @@ public class HttpsConnection
/** The underlying HTTP/HTTPS connection. */
private final HttpURLConnection connection;

private ProxySettings proxySettings;

/**
* The body. {@link HttpURLConnection} silently calls connect() when the output
* stream is written to. We buffer the body and defer writing to the output
Expand Down Expand Up @@ -84,26 +84,7 @@ public HttpsConnection(URL url, HttpsMethod method, final ProxySettings proxySet
try
{
// Codes_SRS_HTTPSCONNECTION_11_001: [The constructor shall open a connection to the given URL.]
if (proxySettings != null)
{
if (proxySettings.getUsername() != null && proxySettings.getPassword() != null)
{
Authenticator authenticator = new Authenticator()
{
public PasswordAuthentication getPasswordAuthentication()
{
return (new PasswordAuthentication(proxySettings.getUsername(), proxySettings.getPassword()));
}
};
Authenticator.setDefault(authenticator);
}

this.connection = (HttpURLConnection) url.openConnection(proxySettings.getProxy());
}
else
{
this.connection = (HttpURLConnection) url.openConnection();
}
this.connection = (HttpURLConnection) url.openConnection();

// Codes_SRS_HTTPSCONNECTION_11_021: [The constructor shall set the HTTPS method to the given method.]
this.connection.setRequestMethod(method.name());
Expand All @@ -113,6 +94,8 @@ public PasswordAuthentication getPasswordAuthentication()
// Codes_SRS_HTTPSCONNECTION_11_002: [The constructor shall throw a TransportException if the connection was unable to be opened.]
throw HttpsConnection.buildTransportException(e);
}

this.proxySettings = proxySettings;
}

/**
Expand Down Expand Up @@ -384,8 +367,15 @@ void setSSLContext(SSLContext sslContext) throws IllegalArgumentException
}
if (this.connection instanceof HttpsURLConnection)
{
//Codes_SRS_HTTPSCONNECTION_25_024: [The function shall set the the SSL context with the given value.]
((HttpsURLConnection)this.connection).setSSLSocketFactory(sslContext.getSocketFactory());
if (this.proxySettings != null)
{
((HttpsURLConnection)this.connection).setSSLSocketFactory(new HttpProxySocketFactory(sslContext.getSocketFactory(), proxySettings));
}
else
{
//Codes_SRS_HTTPSCONNECTION_25_024: [The function shall set the the SSL context with the given value.]
((HttpsURLConnection)this.connection).setSSLSocketFactory(sslContext.getSocketFactory());
}
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@
package tests.unit.com.microsoft.azure.sdk.iot.device.transport.https;

import com.microsoft.azure.sdk.iot.device.ProxySettings;
import com.microsoft.azure.sdk.iot.device.exceptions.ProtocolException;
import com.microsoft.azure.sdk.iot.device.exceptions.TransportException;
import com.microsoft.azure.sdk.iot.device.transport.https.HttpsConnection;
import com.microsoft.azure.sdk.iot.device.transport.https.HttpsMethod;
import com.microsoft.azure.sdk.iot.device.transport.HttpProxySocketFactory;
import mockit.*;
import org.junit.Assert;
import org.junit.Test;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
Expand Down Expand Up @@ -65,31 +66,6 @@ public void constructorOpensConnection() throws IOException, TransportException
};
}

@Test
public void constructorOpensConnectionWithProxy(@Mocked final Proxy mockProxy) throws IOException, TransportException
{
final HttpsMethod httpsMethod = HttpsMethod.PUT;
final String expectedProxyHostname = "127.0.0.1";
final int expectedProxyPort = 8888;
final InetSocketAddress inetSocketAddress = new InetSocketAddress(expectedProxyHostname, expectedProxyPort);
new Expectations()
{
{
mockUrl.getProtocol();
result = "https";

mockProxySettings.getProxy();
result = mockProxy;

mockUrl.openConnection(mockProxy);
result = mockUrlConn;
}
};

// act
new HttpsConnection(mockUrl, httpsMethod, mockProxySettings);
}

// Tests_SRS_HTTPSCONNECTION_11_002: [The constructor shall throw a TransportException if the connection was unable to be opened.]
@Test(expected = TransportException.class)
public void constructorThrowsIoExceptionIfCannotOpenConnection() throws IOException, TransportException
Expand Down Expand Up @@ -385,6 +361,38 @@ public void setSSLContextSetsContext(@Mocked final SSLContext mockedContext) thr
};
}

@Test
public void setSSLContextSetsContextWithProxy(@Mocked final SSLContext mockedContext, @Mocked final SSLSocketFactory mockedSocketFactory, @Mocked final HttpProxySocketFactory mockedHttpProxySocketFactory) throws IOException, TransportException
{
final HttpsMethod httpsMethod = HttpsMethod.POST;
new NonStrictExpectations()
{
{
mockUrl.getProtocol();
result = "https";
mockUrl.openConnection();
result = mockUrlConn;
mockUrlConn.getRequestMethod();
result = httpsMethod.name();
mockedContext.getSocketFactory();
result = mockedSocketFactory;
new HttpProxySocketFactory(mockedSocketFactory, mockProxySettings);
result = mockedHttpProxySocketFactory;
}
};
final HttpsConnection conn = new HttpsConnection(mockUrl, httpsMethod, mockProxySettings);

Deencapsulation.invoke(conn, "setSSLContext", mockedContext);

new Verifications()
{
{
mockUrlConn.setSSLSocketFactory(mockedHttpProxySocketFactory);
times = 1;
}
};
}

//Tests_SRS_HTTPSCONNECTION_34_026: [If this object uses HTTP, this function shall throw an UnsupportedOperationException.]
@Test (expected = UnsupportedOperationException.class)
public void setSSLContextThrowsIfHttp(@Mocked final SSLContext mockedContext) throws IOException, TransportException
Expand Down

0 comments on commit 549a7af

Please sign in to comment.