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 --- 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 ++++++++++++++++++--- 4 files changed, 126 insertions(+), 69 deletions(-) (limited to 'src') 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