From b3dff2789104e11f0b7ba9e47385ead9a6166d53 Mon Sep 17 00:00:00 2001
From: Simon Rettberg
Date: Fri, 21 Nov 2014 12:21:25 +0100
Subject: Add TLS support for thrift connection to master, switch to TLSv1.2
everywhere
---
config/global.properties.example | 7 +-
pom.xml | 7 +-
src/main/java/org/openslx/satellitedaemon/App.java | 45 ++-------
.../java/org/openslx/satellitedaemon/Globals.java | 14 ++-
.../java/org/openslx/satellitedaemon/Identity.java | 33 ++++---
.../filetransfer/ThriftConnection.java | 103 ++++++++++++++++++---
6 files changed, 132 insertions(+), 77 deletions(-)
diff --git a/config/global.properties.example b/config/global.properties.example
index 4c009a6..192a76b 100644
--- a/config/global.properties.example
+++ b/config/global.properties.example
@@ -23,8 +23,11 @@ THRIFT_KEYSTORE_PASSWORD=password
# and it's path
THRIFT_KEYSTORE_PATH=./config/satellite.jks
-# port where the thrift connection is opened (usually this is 9191)
-THRIFT_PORT=9090
+# use TLS? defaults to yes if missing
+THRIFT_TLS=yes
+
+# port where the thrift connection is opened (usually this is 9090/plain 9091/tls)
+THRIFT_PORT=9091
# proxy configuration:
# 3 options for proxy configuration: AUTO = autmatically, YES, NO. If nothing is
diff --git a/pom.xml b/pom.xml
index cf842c7..480a55c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -91,7 +91,7 @@
4.11
test
-
+
log4j
log4j
1.2.17
@@ -114,10 +114,5 @@
1.0.6
test
-
- com.googlecode.vestige
- proxy_vole
- 0.0.3-SNAPSHOT
-
diff --git a/src/main/java/org/openslx/satellitedaemon/App.java b/src/main/java/org/openslx/satellitedaemon/App.java
index 55e3149..e65f01b 100644
--- a/src/main/java/org/openslx/satellitedaemon/App.java
+++ b/src/main/java/org/openslx/satellitedaemon/App.java
@@ -1,25 +1,14 @@
package org.openslx.satellitedaemon;
import java.math.BigInteger;
-import java.net.Authenticator;
-import java.net.InetSocketAddress;
-import java.net.Proxy;
-import java.net.ProxySelector;
import java.security.NoSuchAlgorithmException;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.interfaces.RSAPublicKey;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.openslx.network.ProxyConfiguration;
-import org.openslx.network.ProxyProperties;
-import org.openslx.network.StaticProxyAuthenticator;
-import org.openslx.network.StaticProxySelector;
import org.openslx.satellitedaemon.filetransfer.FileDownloadWorker;
import org.openslx.satellitedaemon.filetransfer.FileUploadWorker;
-
-import com.btr.proxy.search.wpad.WpadProxySearchStrategy;
-import com.btr.proxy.util.ProxyException;
+import org.openslx.satellitedaemon.filetransfer.ThriftConnection;
/***********************************************************************************************/
/**
@@ -34,6 +23,10 @@ public class App
{
BasicConfigurator.configure();
+ log.info( "Ping: " + ThriftConnection.ping() );
+
+ System.exit( 0 );
+
int i = 0;
String arg;
String organizationName;
@@ -45,10 +38,10 @@ public class App
// Arguments available, take the first one.
arg = args[i++];
if ( arg.equals( "--checkconfig" ) ) {
- if ( checkConfig() ) {
+ if ( Identity.load() ) {
System.exit( 0 );
}
- log.error( "Config not valid: existing modulus, private and public exponent no valid key pair." );
+ log.error( "Config not valid: Missing organization, or keypair missing/corrupted." );
System.exit( 2 );
} else if ( arg.equals( "--genid" ) ) {
if ( i < args.length ) {
@@ -113,7 +106,8 @@ public class App
} else if ( args.length == 0 ) {
// No Option choosed, try to load existing identity.
- if ( !tryLoadIdentity() ) {
+ if ( !Identity.load() ) {
+ log.error( "Bailing out!" );
System.exit( 2 );
}
}
@@ -134,22 +128,6 @@ public class App
downloadWorker.start();
}
- private static boolean checkConfig()
- {
- if ( Identity.getOrganizationName() == null ) {
- log.error( "Checking config failed: no existing organization name." );
- return false;
- }
- RSAPublicKey pub = (RSAPublicKey)Identity.getPublicKey();
- RSAPrivateKey priv = (RSAPrivateKey)Identity.getPrivateKey();
- assert ( pub.getModulus() == priv.getModulus() );
- BigInteger modulus = pub.getModulus();
- return Identity.isValidKeyPair(
- modulus,
- priv.getPrivateExponent(),
- pub.getPublicExponent() );
- }
-
private static boolean genId( String organizationName )
{
return Identity.generateIdentity( organizationName );
@@ -173,9 +151,4 @@ public class App
{
return Identity.updateAddress( ipAddress );
}
-
- private static boolean tryLoadIdentity()
- {
- return checkConfig();
- }
}
diff --git a/src/main/java/org/openslx/satellitedaemon/Globals.java b/src/main/java/org/openslx/satellitedaemon/Globals.java
index fa39d2d..bb6e6da 100644
--- a/src/main/java/org/openslx/satellitedaemon/Globals.java
+++ b/src/main/java/org/openslx/satellitedaemon/Globals.java
@@ -5,6 +5,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
+import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.util.Properties;
@@ -48,6 +49,12 @@ public class Globals
// Integers //
+ public static boolean getThriftTls()
+ {
+ String s = properties.getProperty( "THRIFT_TLS", "yes" );
+ return s.equalsIgnoreCase( "yes" ) || s.equalsIgnoreCase( "true" ) || s.equalsIgnoreCase( "1" ) || s.equalsIgnoreCase( "on" );
+ }
+
public static int getThriftPort()
{
return Util.tryToParseInt( properties.getProperty( "THRIFT_PORT" ) );
@@ -87,8 +94,9 @@ public class Globals
return true;
if ( getTruststorePath() == null || getTruststorePath().isEmpty() ) {
try {
- context = SSLContext.getDefault();
- } catch ( NoSuchAlgorithmException e ) {
+ context = SSLContext.getInstance( "TLSv1.2" );
+ context.init( null, null, null );
+ } catch ( NoSuchAlgorithmException | KeyManagementException e ) {
log.error( "could not load system default ssl context.", e );
return false;
}
@@ -101,7 +109,7 @@ public class Globals
TrustManagerFactory tmf = TrustManagerFactory
.getInstance( TrustManagerFactory.getDefaultAlgorithm() );
tmf.init( keystore );
- context = SSLContext.getInstance( "SSLv3" );
+ context = SSLContext.getInstance( "TLSv1.2" );
TrustManager[] trustManagers = tmf.getTrustManagers();
context.init( null, trustManagers, null );
} catch ( FileNotFoundException e ) {
diff --git a/src/main/java/org/openslx/satellitedaemon/Identity.java b/src/main/java/org/openslx/satellitedaemon/Identity.java
index 6ddbfb3..bb5ba29 100644
--- a/src/main/java/org/openslx/satellitedaemon/Identity.java
+++ b/src/main/java/org/openslx/satellitedaemon/Identity.java
@@ -31,7 +31,7 @@ public class Identity
public static String getOrganizationName()
{
- return properties.getProperty( "ORGANIZATION_NAME" );
+ return properties.getProperty( "ORGANIZATION_NAME", "" );
}
private static BigInteger getModulus()
@@ -52,7 +52,8 @@ public class Identity
/**
* Load properties
*/
- static {
+ public static boolean load()
+ {
InputStreamReader stream = null;
try {
// Load all entries of the config file into properties
@@ -61,20 +62,27 @@ public class Identity
properties.load( stream );
stream.close();
} catch ( IOException e ) {
- log.error( "Could not load identity.properties. Exiting." );
- System.exit( 2 );
+ log.error( "Could not load identity.properties." );
+ return false;
} finally {
Util.streamClose( stream );
}
- Util.notNullOrEmptyFatal( getOrganizationName(), "Organiziation Name must not be empty!" );
+ if ( getOrganizationName().isEmpty() ) {
+ log.error( "Organiziation Name must not be empty!" );
+ return false;
+ }
try {
akh = new AsymKeyHolder( getPrivateExponent(), getPublicExponent(), getModulus() );
+ if ( akh.getPrivateKey() != null && akh.getPublicExponent() != null )
+ return true;
+ log.error( "Organization name is empty!" );
} catch ( InvalidKeySpecException e ) {
log.error( "InvalidKeySpecException", e );
} catch ( NoSuchAlgorithmException e ) {
log.error( "NoSuchAlgorithmException", e );
}
+ return false;
}
/**
@@ -177,6 +185,7 @@ public class Identity
/**
* Submit new satellite - ipAddress to master with organizationId, ipAddress
* and key - information.
+ *
* @param ipAddress
* @return true, if successful.
*/
@@ -197,9 +206,10 @@ public class Identity
pubKey.getModulus().toString(),
pubKey.getPublicExponent().toString() );
}
-
+
/**
* Update already existing satellite - ipAddress in master - Db.
+ *
* @param ipAddress
* @return true, if successful.
*/
@@ -252,17 +262,6 @@ public class Identity
}
}
- /**
- * Check modulus, privExp and pubExp for not being null.
- *
- * @return
- */
- private static boolean checkMembers()
- {
- return ( ( getModulus() != null ) &&
- ( getPrivateExponent() != null ) && ( getPublicExponent() != null ) );
- }
-
/**
* Get BigInteger of read String number.
*
diff --git a/src/main/java/org/openslx/satellitedaemon/filetransfer/ThriftConnection.java b/src/main/java/org/openslx/satellitedaemon/filetransfer/ThriftConnection.java
index 2196c5e..040b61b 100644
--- a/src/main/java/org/openslx/satellitedaemon/filetransfer/ThriftConnection.java
+++ b/src/main/java/org/openslx/satellitedaemon/filetransfer/ThriftConnection.java
@@ -2,9 +2,18 @@ package org.openslx.satellitedaemon.filetransfer;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.net.Socket;
+import java.net.UnknownHostException;
import java.nio.ByteBuffer;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
import java.util.List;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+
import org.apache.log4j.Logger;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
@@ -40,6 +49,8 @@ import org.openslx.satellitedaemon.db.DbImage.Status;
*/
public class ThriftConnection
{
+ private static final int MAX_MSG_LEN = 30 * 1000 * 1000;
+
private static ThreadLocal client = new ThreadLocal();
private static ServerSessionData sSD = null;
private static Logger log = Logger.getLogger( ThriftConnection.class );
@@ -54,7 +65,7 @@ public class ThriftConnection
* connection is ok, it calls submitImage with CRCsum in List.
*
* @return returns 'null' if there is a problem.
- * @throws ImageDataException
+ * @throws ImageDataException
*/
public static UploadData getUploadInfos( ImageData imDat, String path ) throws ImageDataException
{
@@ -162,6 +173,22 @@ public class ThriftConnection
return null;
}
+ /**
+ * Returns true iff the server is reachable and its ping method
+ * returns true.
+ *
+ * @return sausages
+ */
+ public static boolean ping()
+ {
+ ImageServer.Client theClient = getConnection( false );
+ try {
+ return theClient != null && theClient.ping();
+ } catch ( TException e ) {
+ return false;
+ }
+ }
+
/***********************************************************************************************/
/**
* This method checks if there is already a working connection. If not,
@@ -171,8 +198,38 @@ public class ThriftConnection
* @return returns the client if successful.
*/
private static ImageServer.Client getConnection()
+ {
+ return getConnection( true );
+ }
+
+ /**
+ * Get established connection, only authenticate if needAuth is set, otherwise
+ * we just make sure we're connected.
+ *
+ * @param needAuth authenticate to server?
+ * @return
+ */
+ private static ImageServer.Client getConnection( boolean needAuth )
{
ImageServer.Client theClient = client.get();
+
+ if ( !needAuth ) {
+ try {
+ theClient.ping();
+ } catch ( Exception e ) {
+ // Need new client, connection is bad
+ theClient = newClient();
+ try {
+ theClient.ping();
+ } catch ( Exception e1 ) {
+ // No luck today :(
+ theClient = null;
+ }
+ }
+ return theClient;
+ }
+
+ // Want a connected authenticated client
boolean isAuthenticated;
if ( theClient == null ) {
@@ -237,22 +294,39 @@ public class ThriftConnection
{
final ImageServer.Client newClient;
try {
- TTransport transport = new TFramedTransport( new TSocket(
- Globals.getMasterserverHost(), Globals.getThriftPort(), 8000 ) );
- transport.open();
+ TTransport transport;
+ if ( Globals.getThriftTls() ) {
+ SSLContext sslContext = SSLContext.getInstance( "TLSv1.2" );
+ sslContext.init( null, null, null );
+ SSLSocketFactory sslsocketfactory = sslContext.getSocketFactory();
+ Socket sock = sslsocketfactory.createSocket( Globals.getMasterserverHost(), Globals.getThriftPort() );
+ sock.setSoTimeout( 8000 );
+ transport = new TFramedTransport( new TSocket( sock ), MAX_MSG_LEN );
+ } else {
+ transport = new TFramedTransport( new TSocket(
+ Globals.getMasterserverHost(), Globals.getThriftPort(), 8000 ), MAX_MSG_LEN );
+ transport.open();
+ }
TProtocol protocol = new TBinaryProtocol( transport );
newClient = new ImageServer.Client( protocol );
- log.debug( "ThriftConnection: Made a new Client" );
+ log.debug( "ThriftConnection: Made a new Client (TLS=" + Globals.getThriftTls() + ")" );
+ client.set( newClient );
+ return newClient;
} catch ( TTransportException e ) {
log.error( "Transport could not be opened. Couldn't create new client.", e );
- return null;
+ } catch ( UnknownHostException e ) {
+ log.error( "Could not resolve host name of master server", e );
+ } catch ( IOException e ) {
+ log.error( "Unknown error connecting to master", e );
+ } catch ( NoSuchAlgorithmException | KeyManagementException e ) {
+ log.error( "No valid TLS algorithm found", e );
}
- client.set( newClient );
- return newClient;
+ return null;
}
/**
* Publish new user to master-server, which insert it to his db.
+ *
* @param userInfo
* @return true, if successful.
*/
@@ -278,15 +352,16 @@ public class ThriftConnection
/**
* Register new, by master unknown satellite - server with organizationId,
* ipAddress and key - information.
+ *
* @param organizationId
* @param ipAddress
* @param modulus
* @param exponent
- * @return true, if successful.
+ * @return true, if successful.
*/
public static boolean registerSatellite( String organizationId, String ipAddress, String modulus, String exponent )
{
- ImageServer.Client theClient = client.get();
+ ImageServer.Client theClient = getConnection( false );
if ( theClient == null ) {
// There is no client instance for this thread, create a new one
@@ -305,16 +380,18 @@ public class ThriftConnection
return false;
}
}
-
+
/**
* Update in master - DB existing satellite - ipAddress.
+ *
* @param ipAddress
* @return true, if successful.
*/
- public static boolean updateSatelliteAddress(String ipAddress) {
+ public static boolean updateSatelliteAddress( String ipAddress )
+ {
ImageServer.Client theClient = null;
theClient = getConnection();
- if ( theClient == null) {
+ if ( theClient == null ) {
log.error( "Client was null!" );
return false;
}
--
cgit v1.2.3-55-g7522