summaryrefslogblamecommitdiffstats
path: root/src/main/java/org/openslx/satellitedaemon/filetransfer/ThriftConnection.java
blob: 040b61b7c750b70a260c8a6c30f93b69d0835701 (plain) (tree)
1
2
3
4
5
6
7
8
9
                                                 


                                     

                                     
                           

                                              
                      
 




                                         
                               


                                                  

                                                    
                                              
                                                       
                                                    
                                                  
                                                                    

                                                                   
                                                         
                                                      

                                                               

                                                              
                                                       

                                                            
                                                     
                                           
                                            
                                              
                                                     
 

                                                                                                 

                                                                           
   

                             

                                                                
                                                                                                      
                                                    
                                                                               
                                          
 

                                                                                                         
                                          
           


                                                                                  

                                                        
                                     
           
                                                                                                         
         
                                                    




                                                        


                                             


                                                                                          
                                                   



                                                                          

                     

                                                                                      


                                                                                     

                                                                               
                                
                                                                              
                         
                                                  
                                
                                               
                                                                     

                                                                                   
                                                                           
                                                               

                                                                    


                                                    

                                                     


                            
 

                                                                                                         
                                                                                    
                                                                      


                                                        

                                                                    
                                                    




                                                        
                 
 
                     




                                                                                                  

                                                               
                                                                                            
                                                                    

                                                                                               
                                                                                     
                                                                                               

                                                                                                           



                                                                                           

                                                      
                                                                

                                                                                                  

                                                          

                                                                                                
                                                                     


                                                    

                                                     
                 


                            















                                                                       

                                                                                                         





                                                                                   
                                                         
         











                                                                                      
                                                            

















                                                                     




                                                                                                  
                                                
                                                
                                                  
                                                                                     

                                            
                        











                                                                                                                               
                         
                 
 
                                         
                             
                                                                
                                                                                    


                                                                                         
                                                                                      
                                                                           

                                                                                   
                                                                   
                                                                               
                                                                               
                                                               
                                                                                                                                     
                                            
                                                  
                                                                                                                        
                                            
                         
                                                        
 



                                 

                                                                                                         
                                                                     
           
                              
           

                                                     
                                                   
                     












                                                                                                                                      

                                                                              


                                                                                                                
                                                   
                                                                                                     





                                                                                       
                 
                            
         
 

                                                                        
           


                                       

                                                              






                                                        
                                                   







                                                                                
 


                                                                                  
           



                                
                                       
           

                                                                                                                           
                                                                      









                                                                                                  







                                                                                                                    
 

                                                                
           


                                       

                                                                        

                                                    
                                          









                                                                                            
 
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;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;
import org.openslx.encryption.AsymEncryptionHandler;
import org.openslx.imagemaster.crcchecker.CrcFile;
import org.openslx.imagemaster.thrift.iface.AuthenticationException;
import org.openslx.imagemaster.thrift.iface.AuthorizationError;
import org.openslx.imagemaster.thrift.iface.AuthorizationException;
import org.openslx.imagemaster.thrift.iface.DownloadData;
import org.openslx.imagemaster.thrift.iface.ImageData;
import org.openslx.imagemaster.thrift.iface.ImageDataError;
import org.openslx.imagemaster.thrift.iface.ImageDataException;
import org.openslx.imagemaster.thrift.iface.ImageServer;
import org.openslx.imagemaster.thrift.iface.ServerSessionData;
import org.openslx.imagemaster.thrift.iface.UploadData;
import org.openslx.imagemaster.thrift.iface.UploadError;
import org.openslx.imagemaster.thrift.iface.UploadException;
import org.openslx.imagemaster.thrift.iface.UserInfo;
import org.openslx.satellitedaemon.Globals;
import org.openslx.satellitedaemon.Identity;
import org.openslx.satellitedaemon.db.DbImage;
import org.openslx.satellitedaemon.db.DbImage.Status;

/***********************************************************************************************/
/**
 * Handles the authentication with the Satellite Server and sends the
 * FILTRANSFERCredentials, which are necessary for the upload of the image.
 */
public class ThriftConnection
{
	private static final int MAX_MSG_LEN = 30 * 1000 * 1000;

	private static ThreadLocal<ImageServer.Client> client = new ThreadLocal<ImageServer.Client>();
	private static ServerSessionData sSD = null;
	private static Logger log = Logger.getLogger( ThriftConnection.class );
	private static CrcFile crc = null;

	/***********************************************************************************************/
	/**
	 * Method for getting UploadeInfos
	 * 
	 * when the CRCsum need to be transfered. The method calls getConnection()
	 * to check if the connection is ok and to get the ServerSessionData. If
	 * connection is ok, it calls submitImage with CRCsum in List<Integer>.
	 * 
	 * @return returns 'null' if there is a problem.
	 * @throws ImageDataException
	 */
	public static UploadData getUploadInfos( ImageData imDat, String path ) throws ImageDataException
	{
		ImageServer.Client theClient = null;
		String crcPath = path.concat( ".crc" );
		theClient = getConnection();
		if ( theClient == null ) {
			log.error( "Client was null!" );
			return null;
		}
		List<Integer> crcSums = null;
		try {
			crc = new CrcFile( crcPath );
			log.info( "Made CRCFile from " + crcPath );
			log.info( "crc.getCrcSums( ).size = " + crc.getCrcSums().size() );
			crcSums = crc.getCrcSums();
		} catch ( FileNotFoundException e ) {
			log.debug( "crcFile " + crcPath + " not found." );
		} catch ( IOException e ) {
			log.error( "IOException", e );
		}
		try {
			return theClient.submitImage( sSD.sessionId, imDat, crcSums );
		} catch ( AuthorizationException e ) {
			if ( e.number == AuthorizationError.NOT_AUTHENTICATED ) {
				log.warn( "Suddenly nut authenticated anymore.", e );
			} else if ( e.number == AuthorizationError.NO_PERMISSION ) {
				log.error( "No permission for uploading.", e );
				// TODO: add error message into database.
			} else {
				log.warn( "Unknown authorization error.", e );
			}
		} catch ( ImageDataException e ) {
			throw e;
		} catch ( UploadException e ) {
			if ( e.number == UploadError.BROKEN_BLOCK ) {
				// A Block was transmitted 20 times unsuccessfully.
				// TODO: Mark the Image as corrupted.
			} else if ( e.number == UploadError.INVALID_CRC ) {
				// The CRC sum contained errors
				if ( crc != null && !crc.isValid() )
					crc.delete();
			} else {
				e.printStackTrace();
			}
		} catch ( TException e ) {
			log.error( "TException", e );
		}
		return null;
	}

	/***********************************************************************************************/
	/**
	 * Method for getting DonwloadInfos. Calls getConnection if client was null.
	 * You need to specify all Blocks you want to have in an List.
	 * 
	 * @return returns 'null' if there is a problem.
	 */
	public static DownloadData getDownloadInfos( DbImage imDat )
	{
		ImageServer.Client theClient = null;

		theClient = getConnection();
		if ( theClient == null ) {
			log.error( "Client was null!" );
			return null;
		}

		try {
			return theClient.getImage( sSD.sessionId, imDat.guid );
		} catch ( ImageDataException e ) {
			log.debug( "In catch - blog of thrift connection" );
			if ( e.isSetNumber()
					&& e.getNumber().equals( ImageDataError.INVALID_DATA ) ) {
				// Data in the db is not valid
				// TODO: add e.message into DB;
			} else if ( e.getNumber().equals( ImageDataError.UNKNOWN_IMAGE ) ) {
				// The image requested is not known.
				// TODO: change field image_syncMode, so the image is not asked
				// for again.
				// For now just changed status of image. Currently no
				// possibility for creating new useful state in DB. (Offenburg)
				log.info( "Image not known. For skipping next time, mark as only_local." );
				imDat.updateStatus( Status.only_local );
				// Plus add a note in some way to mark as unknown by Server
			} else {
				e.printStackTrace();
			}
		} catch ( AuthorizationException e ) {
			if ( e.isSetNumber()
					&& e.getNumber().equals(
							AuthorizationError.NOT_AUTHENTICATED ) ) {
				log.error( "Not authenticated. SessionID is not valid.", e );
				// SessionID is not valid
				// TODO: Code for new SSID
			} else if ( e.getNumber().equals( AuthorizationError.NO_PERMISSION ) ) {
				log.error( "No permission error.", e );
				// TODO: add e.message into database.
			} else {
				e.printStackTrace();
			}
		} catch ( TException e ) {
			log.error( "TException", e );
		}
		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,
	 * newClient() establishes one. Also it does the Authentication if not done
	 * yet.
	 * 
	 * @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 ) {
			// There is no client instance for this thread, create a new one
			log.info( "No existing client for this thread. Making a new client ..." );
			theClient = newClient();
			isAuthenticated = false;
			if ( theClient == null ) {
				log.debug( "The client was null after newClient()" );
				return null;
			}
		} else {
			// There is a client instance for this thread, see if it's still usable and authenticated
			try {
				isAuthenticated = theClient.isServerAuthenticated( sSD.sessionId );
				log.debug( "Existing client is " + ( isAuthenticated ? "still" : "not" ) + " authenticated." );
			} catch ( TException x ) {
				theClient = newClient();
				if ( theClient == null ) {
					log.warn( "Masterserver connection fail" );
					return null;
				}
				log.debug( "Existing client was not connected anymore." );
				isAuthenticated = false;
			}
		}

		if ( !isAuthenticated ) {
			try {
				ByteBuffer tmpBuffer = theClient
						.startServerAuthentication( Identity
								.getOrganizationName() );
				byte[] toEncrypt = new byte[ tmpBuffer.remaining() ];
				tmpBuffer.get( toEncrypt );
				AsymEncryptionHandler aeh = new AsymEncryptionHandler(
						Identity.getPrivateKey() );

				byte[] byteArray = aeh.encryptMessage( toEncrypt );
				sSD = theClient.serverAuthenticate(
						Identity.getOrganizationName(),
						ByteBuffer.wrap( byteArray ) );
			} catch ( AuthenticationException e ) {
				log.error( "ThriftConnection: AuthenticationException: Server Authetication was not sucessful.", e );
				return null;
			} catch ( TException e ) {
				log.error( "ThriftConnection: TException: Server Authetication was not sucessful.", e );
				return null;
			}
			log.info( "is Authenticated." );

		}
		return theClient;
	}

	/***********************************************************************************************/
	/**
	 * Method for creating a new Client for Thrift communication.
	 * 
	 * @throws IOException
	 */
	private static ImageServer.Client newClient()
	{
		final ImageServer.Client newClient;
		try {
			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 (TLS=" + Globals.getThriftTls() + ")" );
			client.set( newClient );
			return newClient;
		} catch ( TTransportException e ) {
			log.error( "Transport could not be opened. Couldn't create new client.", e );
		} 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 );
		}
		return null;
	}

	/**
	 * Publish new user to master-server, which insert it to his db.
	 * 
	 * @param userInfo
	 * @return true, if successful.
	 */
	public static boolean publishUser( UserInfo userInfo )
	{
		ImageServer.Client theClient = null;
		theClient = getConnection();
		if ( theClient == null ) {
			log.error( "Client was null!" );
			return false;
		}
		try {
			log.info( sSD.toString() );
			return theClient.publishUser( sSD.sessionId, userInfo );
		} catch ( AuthorizationException e ) {
			log.error( "AutorizationException", e );
		} catch ( TException e ) {
			log.error( "TException", e );
		}
		return false;
	}

	/**
	 * 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.
	 */
	public static boolean registerSatellite( String organizationId, String ipAddress, String modulus, String exponent )
	{
		ImageServer.Client theClient = getConnection( false );

		if ( theClient == null ) {
			// There is no client instance for this thread, create a new one
			log.info( "No existing client for this thread. Making a new client ..." );
			theClient = newClient();
			if ( theClient == null ) {
				log.debug( "The client was null after newClient()" );
				return false;
			}
		}
		// No check for valid connection. --> not needed, because this satellite is not known yet by master.
		try {
			return theClient.registerSatellite( organizationId, ipAddress, modulus, exponent );
		} catch ( TException e ) {
			log.error( "TException", e );
			return false;
		}
	}

	/**
	 * Update in master - DB existing satellite - ipAddress.
	 * 
	 * @param ipAddress
	 * @return true, if successful.
	 */
	public static boolean updateSatelliteAddress( String ipAddress )
	{
		ImageServer.Client theClient = null;
		theClient = getConnection();
		if ( theClient == null ) {
			log.error( "Client was null!" );
			return false;
		}
		try {
			return theClient.updateSatelliteAddress( sSD.sessionId, ipAddress );
		} catch ( TException e ) {
			log.error( "TException", e );
			return false;
		}
	}
}