def test_on_message(self): ''' This is quite a complicated method, so it would take a long time to write a comprehensive test. Instead, I will start with where there might be problems. ''' test_ssm = Ssm2(self._brokers, self._msgdir, TEST_CERT_FILE, self._key_path, dest=self._dest, listen=self._listen) # SSM crashed when headers were missing. It should just ignore the # message. test_ssm.on_message({}, '') test_ssm.on_message({'nothing': 'dummy'}, '') test_ssm.on_message({'nothing': 'dummy'}, 'Not signed or encrypted.') # Try changing permissions on the directory we're writing to. # The on_message function shouldn't throw an exception. os.chmod(self._msgdir, 0400) test_ssm.on_message({'nothing': 'dummy'}, 'Not signed or encrypted.') os.chmod(self._msgdir, 0777) # Check that message with ID of 'ping' doesn't raise an exception. # Messages with this ID are handled differently to normal messages. test_ssm.on_message({'empa-id': 'ping'}, 'body') # Check that msg with ID and no real content doesn't raise exception. test_ssm.on_message({'empa-id': '012345'}, 'body')
def test_ssm_init_non_dirq(self): """Test a SSM can be initialised with support for non-dirq sending.""" try: ssm = Ssm2(self._brokers, self._msgdir, TEST_CERT_FILE, self._key_path, dest=self._dest, listen=None, path_type='directory') except Ssm2Exception as error: self.fail('An error occured trying to create an SSM using ' 'the non-dirq functionality: %s.' % error) # Assert the outbound queue is of the expected type. self.assertTrue(isinstance(ssm._outq, MessageDirectory))
def test_init_expired_cert(self): """Test right exception is thrown creating an SSM with expired cert.""" expected_error = ('Certificate %s has expired or will expire ' 'within a day.' % self._expired_cert_path) try: # Indirectly test crypto.verify_cert_date Ssm2(self._brokers, self._msgdir, self._expired_cert_path, self._key_path, listen=self._listen) except Ssm2Exception as error: if str(error) != expected_error: self.fail('Raised: "%s" Expected: "%s"' % (error, expected_error)) else: return # If the test gets here, then it has failed as no exception was thrown. self.fail('An SSM instance was created with an expired certificate!')
log.info(LOG_BREAK) sys.exit(1) log.info('The SSM will run as a daemon.') # We need to preserve the file descriptor for any log files. rootlog = logging.getLogger() log_files = [x.stream for x in rootlog.handlers] dc = DaemonContext(files_preserve=log_files) try: ssm = Ssm2(brokers, cp.get('messaging', 'path'), cert=cp.get('certificates', 'certificate'), key=cp.get('certificates', 'key'), listen=cp.get('messaging', 'destination'), use_ssl=cp.getboolean('broker', 'use_ssl'), capath=cp.get('certificates', 'capath'), check_crls=cp.getboolean('certificates', 'check_crls'), pidfile=pidfile) log.info('Fetching valid DNs.') dns = get_dns(options.dn_file) ssm.set_dns(dns) except Exception, e: log.fatal('Failed to initialise SSM: %s', e) log.info(LOG_BREAK) sys.exit(1) try:
except ConfigParser.NoOptionError: log.info( 'No server certificate supplied. Will not encrypt messages.') server_cert = None try: destination = scp.get('messaging', 'destination') if destination == '': raise Ssm2Exception('No destination queue is configured.') except ConfigParser.NoOptionError, e: raise Ssm2Exception(e) ssm = Ssm2(brokers, scp.get('messaging', 'path'), dest=scp.get('messaging', 'destination'), cert=scp.get('certificates', 'certificate'), capath=scp.get('certificates', 'capath'), key=scp.get('certificates', 'key'), use_ssl=scp.getboolean('broker', 'use_ssl'), enc_cert=server_cert) except Ssm2Exception, e: log.error('Failed to initialise SSM: %s', e) log.error('Messages have not been sent.') return try: ssm.handle_connect() ssm.send_all() ssm.close_connection() except Ssm2Exception, e: log.error('SSM failed to complete successfully: %s', e) return
# Determine what type of message store we are interacting with, # i.e. a dirq QueueSimple object or a plain MessageDirectory directory. try: path_type = cp.get('messaging', 'path_type') except ConfigParser.NoOptionError: log.info('No path type defined, assuming dirq.') path_type = 'dirq' sender = Ssm2(brokers, cp.get('messaging', 'path'), path_type=path_type, cert=cp.get('certificates', 'certificate'), key=cp.get('certificates', 'key'), dest=cp.get('messaging', 'destination'), use_ssl=use_ssl, capath=cp.get('certificates', 'capath'), enc_cert=server_cert, verify_enc_cert=verify_server_cert, protocol=protocol, project=project, token=token) if sender.has_msgs(): sender.handle_connect() sender.send_all() log.info('SSM run has finished.') else: log.info('No messages found to send.') except (Ssm2Exception, CryptoException), e:
def main(): """Set up connection, send all messages and quit.""" ver = "SSM %s.%s.%s" % __version__ op = OptionParser(description=__doc__, version=ver) op.add_option('-c', '--config', help='location of config file', default='/etc/apel/sender.cfg') op.add_option('-l', '--log_config', help='location of logging config file (optional)', default='/etc/apel/logging.cfg') (options, unused_args) = op.parse_args() cp = ConfigParser.ConfigParser({'use_ssl': 'true'}) cp.read(options.config) # set up logging try: if os.path.exists(options.log_config): logging.config.fileConfig(options.log_config) else: set_up_logging(cp.get('logging', 'logfile'), cp.get('logging', 'level'), cp.getboolean('logging', 'console')) except (ConfigParser.Error, ValueError, IOError) as err: print('Error configuring logging: %s' % err) print('The system will exit.') sys.exit(1) log = logging.getLogger('ssmsend') log.info(LOG_BREAK) log.info('Starting sending SSM version %s.%s.%s.', *__version__) # Determine the protocol and destination type of the SSM to configure. try: protocol = cp.get('sender', 'protocol') except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): # If the newer configuration setting 'protocol' is not set, use 'STOMP' # for backwards compatability. protocol = Ssm2.STOMP_MESSAGING log.debug("No option set for 'protocol'. Defaulting to %s.", protocol) log.info('Setting up SSM with protocol: %s', protocol) if protocol == Ssm2.STOMP_MESSAGING: # Set defaults for AMS variables that Ssm2 constructor requires below. project = None token = '' use_ssl = cp.getboolean('broker', 'use_ssl') if use_ssl: service = STOMP_SSL_SERVICE else: service = STOMP_SERVICE # If we can't get a broker to connect to, we have to give up. try: bdii_url = cp.get('broker', 'bdii') log.info('Retrieving broker details from %s ...', bdii_url) bg = StompBrokerGetter(bdii_url) brokers = bg.get_broker_hosts_and_ports( service, cp.get('broker', 'network')) log.info('Found %s brokers.', len(brokers)) except ConfigParser.NoOptionError as e: try: host = cp.get('broker', 'host') port = cp.get('broker', 'port') brokers = [(host, int(port))] except ConfigParser.NoOptionError: log.error('Options incorrectly supplied for either single ' 'broker or broker network. ' 'Please check configuration') log.error('System will exit.') log.info(LOG_BREAK) print('SSM failed to start. See log file for details.') sys.exit(1) except ldap.LDAPError as e: log.error('Could not connect to LDAP server: %s', e) log.error('System will exit.') log.info(LOG_BREAK) print('SSM failed to start. See log file for details.') sys.exit(1) elif protocol == Ssm2.AMS_MESSAGING: # Then we are setting up an SSM to connect to a AMS. # 'use_ssl' isn't checked when using AMS (SSL is always used), but it # is needed for the call to the Ssm2 constructor below. use_ssl = None try: # We only need a hostname, not a port host = cp.get('broker', 'host') # Use brokers variable so subsequent code is not dependant on # the exact destination type. brokers = [host] except ConfigParser.NoOptionError: log.error('The host must be specified when connecting to AMS, ' 'please check your configuration') log.error('System will exit.') log.info(LOG_BREAK) print('SSM failed to start. See log file for details.') sys.exit(1) # Attempt to configure AMS project variable. try: project = cp.get('messaging', 'ams_project') except (ConfigParser.Error, ValueError, IOError) as err: # A project is needed to successfully send to an # AMS instance, so log and then exit on an error. log.error('Error configuring AMS values: %s', err) log.error('SSM will exit.') print('SSM failed to start. See log file for details.') sys.exit(1) try: token = cp.get('messaging', 'token') except (ConfigParser.Error, ValueError, IOError) as err: # A token is not necessarily needed, if the cert and key can be # used by the underlying auth system to get a suitable token. log.info('No AMS token provided, using cert/key pair instead.') # Empty string used by AMS to define absence of token. token = '' if len(brokers) == 0: log.error('No brokers available.') log.error('System will exit.') log.info(LOG_BREAK) sys.exit(1) try: server_cert = None verify_server_cert = True try: server_cert = cp.get('certificates', 'server_cert') try: verify_server_cert = cp.getboolean('certificates', 'verify_server_cert') except ConfigParser.NoOptionError: pass except ConfigParser.NoOptionError: log.info( 'No server certificate supplied. Will not encrypt messages.') try: destination = cp.get('messaging', 'destination') if destination == '': raise Ssm2Exception('No destination queue is configured.') except ConfigParser.NoOptionError as e: raise Ssm2Exception(e) # Determine what type of message store we are interacting with, # i.e. a dirq QueueSimple object or a plain MessageDirectory directory. try: path_type = cp.get('messaging', 'path_type') except ConfigParser.NoOptionError: log.info('No path type defined, assuming dirq.') path_type = 'dirq' sender = Ssm2(brokers, cp.get('messaging', 'path'), path_type=path_type, cert=cp.get('certificates', 'certificate'), key=cp.get('certificates', 'key'), dest=cp.get('messaging', 'destination'), use_ssl=use_ssl, capath=cp.get('certificates', 'capath'), enc_cert=server_cert, verify_enc_cert=verify_server_cert, protocol=protocol, project=project, token=token) if sender.has_msgs(): sender.handle_connect() sender.send_all() log.info('SSM run has finished.') else: log.info('No messages found to send.') except (Ssm2Exception, CryptoException) as e: print( 'SSM failed to complete successfully. See log file for details.') log.error('SSM failed to complete successfully: %s', e) except Exception as e: print( 'SSM failed to complete successfully. See log file for details.') log.error('Unexpected exception in SSM: %s', e) log.error('Exception type: %s', e.__class__) try: sender.close_connection() except UnboundLocalError: # SSM not set up. pass log.info('SSM has shut down.') log.info(LOG_BREAK)
def main(): """Set up connection, and listen for messages.""" ver = "SSM %s.%s.%s" % __version__ op = OptionParser(description=__doc__, version=ver) op.add_option('-c', '--config', help='location of config file', default='/etc/apel/receiver.cfg') op.add_option('-l', '--log_config', help='location of logging config file (optional)', default='/etc/apel/logging.cfg') op.add_option('-d', '--dn_file', help='location of the file containing valid DNs', default='/etc/apel/dns') (options, unused_args) = op.parse_args() cp = ConfigParser.ConfigParser({'use_ssl': 'true'}) cp.read(options.config) # Check for pidfile pidfile = cp.get('daemon', 'pidfile') if os.path.exists(pidfile): print('Cannot start SSM. Pidfile %s already exists.' % pidfile) sys.exit(1) # set up logging try: if os.path.exists(options.log_config): logging.config.fileConfig(options.log_config) else: set_up_logging(cp.get('logging', 'logfile'), cp.get('logging', 'level'), cp.getboolean('logging', 'console')) except (ConfigParser.Error, ValueError, IOError) as err: print('Error configuring logging: %s' % err) print('SSM will exit.') sys.exit(1) global log log = logging.getLogger('ssmreceive') log.info(LOG_BREAK) log.info('Starting receiving SSM version %s.%s.%s.', *__version__) # Determine the protocol for the SSM to use. try: protocol = cp.get('receiver', 'protocol') except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): # If the newer configuration setting 'protocol' is not set, use 'STOMP' # for backwards compatability. protocol = Ssm2.STOMP_MESSAGING log.debug("No option set for 'protocol'. Defaulting to %s.", protocol) log.info('Setting up SSM with protocol: %s', protocol) if protocol == Ssm2.STOMP_MESSAGING: # Set defaults for AMS variables that Ssm2 constructor requires below. project = None token = '' use_ssl = cp.getboolean('broker', 'use_ssl') if use_ssl: service = STOMP_SSL_SERVICE else: service = STOMP_SERVICE # If we can't get a broker to connect to, we have to give up. try: bg = StompBrokerGetter(cp.get('broker', 'bdii')) brokers = bg.get_broker_hosts_and_ports(service, cp.get('broker', 'network')) except ConfigParser.NoOptionError as e: try: host = cp.get('broker', 'host') port = cp.get('broker', 'port') brokers = [(host, int(port))] except ConfigParser.NoOptionError: log.error('Options incorrectly supplied for either single ' 'broker or broker network. ' 'Please check configuration') log.error('System will exit.') log.info(LOG_BREAK) sys.exit(1) except ldap.SERVER_DOWN as e: log.error('Could not connect to LDAP server: %s', e) log.error('System will exit.') log.info(LOG_BREAK) sys.exit(1) elif protocol == Ssm2.AMS_MESSAGING: # Then we are setting up an SSM to connect to a AMS. # 'use_ssl' isn't checked when using AMS (SSL is always used), but it # is needed for the call to the Ssm2 constructor below. use_ssl = None try: # We only need a hostname, not a port host = cp.get('broker', 'host') # Use brokers variable so subsequent code is not dependant on # the exact destination type. brokers = [host] except ConfigParser.NoOptionError: log.error('The host must be specified when connecting to AMS, ' 'please check your configuration') log.error('System will exit.') log.info(LOG_BREAK) print('SSM failed to start. See log file for details.') sys.exit(1) # Attempt to configure AMS specific variables. try: token = cp.get('messaging', 'token') project = cp.get('messaging', 'ams_project') except (ConfigParser.Error, ValueError, IOError) as err: # A token and project are needed to successfully receive from an # AMS instance, so log and then exit on an error. log.error('Error configuring AMS values: %s', err) log.error('SSM will exit.') print('SSM failed to start. See log file for details.') sys.exit(1) if len(brokers) == 0: log.error('No brokers available.') log.error('System will exit.') log.info(LOG_BREAK) sys.exit(1) log.info('The SSM will run as a daemon.') # We need to preserve the file descriptor for any log files. rootlog = logging.getLogger() log_files = [x.stream for x in rootlog.handlers] dc = DaemonContext(files_preserve=log_files) try: ssm = Ssm2(brokers, cp.get('messaging', 'path'), cert=cp.get('certificates', 'certificate'), key=cp.get('certificates', 'key'), listen=cp.get('messaging', 'destination'), use_ssl=use_ssl, capath=cp.get('certificates', 'capath'), check_crls=cp.getboolean('certificates', 'check_crls'), pidfile=pidfile, protocol=protocol, project=project, token=token) log.info('Fetching valid DNs.') dns = get_dns(options.dn_file) ssm.set_dns(dns) except Exception as e: log.fatal('Failed to initialise SSM: %s', e) log.info(LOG_BREAK) sys.exit(1) try: # Note: because we need to be compatible with python 2.4, we can't use # with dc: # here - we need to call the open() and close() methods # manually. dc.open() ssm.startup() i = 0 # The message listening loop. while True: try: time.sleep(0.1) if protocol == Ssm2.AMS_MESSAGING: # We need to pull down messages as part of # this loop when using AMS. ssm.pull_msg_ams() if i % (REFRESH_DNS * 10) == 0: log.info('Refreshing valid DNs and then sending ping.') dns = get_dns(options.dn_file) ssm.set_dns(dns) if protocol == Ssm2.STOMP_MESSAGING: ssm.send_ping() except (NotConnectedException, AmsConnectionException) as error: log.warn('Connection lost.') log.debug(error) ssm.shutdown() dc.close() log.info("Waiting for 10 minutes before restarting...") time.sleep(10 * 60) log.info('Restarting SSM.') dc.open() ssm.startup() i += 1 except SystemExit as e: log.info('Received the shutdown signal: %s', e) ssm.shutdown() dc.close() except Exception as e: log.error('Unexpected exception: %s', e) log.error('Exception type: %s', e.__class__) log.error('The SSM will exit.') ssm.shutdown() dc.close() log.info('Receiving SSM has shut down.') log.info(LOG_BREAK)
except ConfigParser.NoOptionError: log.info( 'No server certificate supplied. Will not encrypt messages.') try: destination = cp.get('messaging', 'destination') if destination == '': raise Ssm2Exception('No destination queue is configured.') except ConfigParser.NoOptionError, e: raise Ssm2Exception(e) sender = Ssm2(brokers, cp.get('messaging', 'path'), cert=cp.get('certificates', 'certificate'), key=cp.get('certificates', 'key'), dest=cp.get('messaging', 'destination'), use_ssl=cp.getboolean('broker', 'use_ssl'), capath=cp.get('certificates', 'capath'), enc_cert=server_cert, verify_enc_cert=verify_server_cert) if sender.has_msgs(): sender.handle_connect() sender.send_all() log.info('SSM run has finished.') else: log.info('No messages found to send.') except (Ssm2Exception, CryptoException), e: print 'SSM failed to complete successfully. See log file for details.' log.error('SSM failed to complete successfully: %s' % e)
def run_receiver(protocol, brokers, project, token, cp, log, dn_file): """Run Ssm2 as a receiver daemon.""" log.info('The SSM will run as a daemon.') # We need to preserve the file descriptor for any log files. rootlog = logging.getLogger() log_files = [x.stream for x in rootlog.handlers] dc = DaemonContext(files_preserve=log_files) try: ssm = Ssm2(brokers, cp.get('messaging', 'path'), cert=cp.get('certificates', 'certificate'), key=cp.get('certificates', 'key'), listen=cp.get('messaging', 'destination'), use_ssl=cp.getboolean('broker', 'use_ssl'), capath=cp.get('certificates', 'capath'), check_crls=cp.getboolean('certificates', 'check_crls'), pidfile=cp.get('daemon', 'pidfile'), protocol=protocol, project=project, token=token) log.info('Fetching valid DNs.') dns = get_dns(dn_file, log) ssm.set_dns(dns) except Exception as e: log.fatal('Failed to initialise SSM: %s', e) log.info(LOG_BREAK) sys.exit(1) try: # Note: because we need to be compatible with python 2.4, we can't use # with dc: # here - we need to call the open() and close() methods # manually. dc.open() ssm.startup() i = 0 # The message listening loop. while True: try: time.sleep(0.1) if protocol == Ssm2.AMS_MESSAGING: # We need to pull down messages as part of # this loop when using AMS. ssm.pull_msg_ams() if i % (REFRESH_DNS * 10) == 0: log.info('Refreshing valid DNs and then sending ping.') dns = get_dns(dn_file, log) ssm.set_dns(dns) if protocol == Ssm2.STOMP_MESSAGING: ssm.send_ping() except (NotConnectedException, AmsConnectionException) as error: log.warn('Connection lost.') log.debug(error) ssm.shutdown() dc.close() log.info("Waiting for 10 minutes before restarting...") time.sleep(10 * 60) log.info('Restarting SSM.') dc.open() ssm.startup() i += 1 except SystemExit as e: log.info('Received the shutdown signal: %s', e) ssm.shutdown() dc.close() except Exception as e: log.error('Unexpected exception: %s', e) log.error('Exception type: %s', e.__class__) log.error('The SSM will exit.') ssm.shutdown() dc.close() log.info('Receiving SSM has shut down.') log.info(LOG_BREAK)
def run_sender(protocol, brokers, project, token, cp, log): """Run Ssm2 as a sender.""" try: server_cert = None verify_server_cert = True try: server_cert = cp.get('certificates', 'server_cert') server_dn = get_certificate_subject(_from_file(server_cert)) log.info('Messages will be encrypted using %s', server_dn) try: verify_server_cert = cp.getboolean('certificates', 'verify_server_cert') except ConfigParser.NoOptionError: pass except ConfigParser.NoOptionError: log.info( 'No server certificate supplied. Will not encrypt messages.') try: destination = cp.get('messaging', 'destination') if destination == '': raise Ssm2Exception('No destination queue is configured.') except ConfigParser.NoOptionError as e: raise Ssm2Exception(e) # Determine what type of message store we are interacting with, # i.e. a dirq QueueSimple object or a plain MessageDirectory directory. try: path_type = cp.get('messaging', 'path_type') except ConfigParser.NoOptionError: log.info('No path type defined, assuming dirq.') path_type = 'dirq' host_cert = cp.get('certificates', 'certificate') host_dn = get_certificate_subject(_from_file(host_cert)) log.info('Messages will be signed using %s', host_dn) sender = Ssm2(brokers, cp.get('messaging', 'path'), path_type=path_type, cert=host_cert, key=cp.get('certificates', 'key'), dest=cp.get('messaging', 'destination'), use_ssl=cp.getboolean('broker', 'use_ssl'), capath=cp.get('certificates', 'capath'), enc_cert=server_cert, verify_enc_cert=verify_server_cert, protocol=protocol, project=project, token=token) if sender.has_msgs(): sender.handle_connect() sender.send_all() log.info('SSM run has finished.') else: log.info('No messages found to send.') except (Ssm2Exception, CryptoException) as e: print( 'SSM failed to complete successfully. See log file for details.') log.error('SSM failed to complete successfully: %s', e) except Exception as e: print( 'SSM failed to complete successfully. See log file for details.') log.error('Unexpected exception in SSM: %s', e) log.error('Exception type: %s', e.__class__) try: sender.close_connection() except UnboundLocalError: # SSM not set up. pass log.info('SSM has shut down.') log.info(LOG_BREAK)
sys.exit(1) log.info('The SSM will run as a daemon.') # We need to preserve the file descriptor for any log files. rootlog = logging.getLogger() log_files = [x.stream for x in rootlog.handlers] dc = DaemonContext(files_preserve=log_files) try: ssm = Ssm2(brokers, cp.get('messaging','path'), cert=cp.get('certificates','certificate'), key=cp.get('certificates','key'), listen=cp.get('messaging','destination'), use_ssl=use_ssl, capath=cp.get('certificates', 'capath'), check_crls=cp.getboolean('certificates', 'check_crls'), pidfile=pidfile, protocol=protocol, project=project, token=token) log.info('Fetching valid DNs.') dns = get_dns(options.dn_file) ssm.set_dns(dns) except Exception, e: log.fatal('Failed to initialise SSM: %s', e) log.info(LOG_BREAK) sys.exit(1)