def requestAvatarId(self, credentials): """ Extract an avatar ID from an ISSLTransport object. NOTE: Authentication has technically already happened during the SSL handshake. """ if not ISSLTransport.providedBy(credentials): return defer.fail(UnauthorizedLogin("The credentials provided did not provide the ISSLTransport interface.")) peer_cert = credentials.getPeerCertificate() if peer_cert is None: return defer.fail(UnauthorizedLogin("A client certificate was not provided!")) subject= peer_cert.get_subject() #issuer = peer_cert.get_issuer() transform = self.transform subject_components = subject.get_components() match_part = self.subject_part avatar_part = None for part, value in subject_components: if part == match_part: avatar_part = value break if avatar_part is None: return defer.fail(UnauthorizedLogin("Client certificate did not contain subject part '%s'." % match_part)) if transform is not None: return defer.maybeDeferred(transform, avatar_part) else: return defer.succeed(avatar_part)
def _get_target(self): scheme = ('https' if ISSLTransport.providedBy(self.transport) else 'http') h = self.transport.getHost() host = h.host port = h.port return scheme, host, port
def connectionMade(self): self.connection_expire.cancel() self.type = IRCUser(self) tryagain = [] for function in self.factory.actions["connect"]: result = function(self.type) if result == "again": tryagain.append(function) elif not result: self.transport.loseConnection() self.type = None break if self.type: for function in tryagain: if not function(self.type): self.transport.loseConnection() self.type = None break if self.type: self.secure = ISSLTransport(self.transport, None) is not None self.data_checker.start(5) self.pinger.start(self.factory.servconfig["client_ping_interval"], now=False) for server in self.factory.servers.itervalues(): if server.nearHop == self.factory.name: server.callRemote(ConnectUser, uuid=self.type.uuid, ip=self.type.ip, server=self.factory.name, secure=self.secure, signon=epoch(self.type.signon))
def connectionMade(self) -> None: # Connection finalizing. if ISSLTransport.providedBy(self.transport): self.secureConnection = True self.supportHelper.network = self.server self.logger.info('Connection established.') # Try to enable IRCv3 support. self.logger.info('Requesting supported capabilities...') self.output.cmdCAP_LS() # Initialize login data from the config. self.nick = self.config.getWithDefault('nickname', 'DesertBot') self.gecos = self.config.getWithDefault('realname', self.nick) self.ident = self.config.getWithDefault('username', self.nick) # Send a server password if defined. password = self.config.getWithDefault('password', None) if password: self.bot.log.info('Sending network password...') self.output.cmdPASS(password) # Start logging in. self.logger.info('Logging in as {}!{} :{}...'.format(self.nick, self.ident, self.gecos)) self.output.cmdNICK(self.nick) self.output.cmdUSER(self.ident, self.gecos)
def isSecure(self): """ Borrowed technique for determining whether this connection is over SSL/TLS. """ return ISSLTransport(self.transport, None) is not None
def connectionMade(self) -> None: # Connection finalizing. if ISSLTransport.providedBy(self.transport): self.secureConnection = True self.supportHelper.network = self.server self.logger.info('Connection established.') # Try to enable IRCv3 support. self.logger.info('Requesting supported capabilities...') self.output.cmdCAP_LS() # Initialize login data from the config. self.nick = self.config.getWithDefault('nickname', 'DesertBot') self.gecos = self.config.getWithDefault('realname', self.nick) self.ident = self.config.getWithDefault('username', self.nick) # Send a server password if defined. password = self.config.getWithDefault('password', None) if password: self.bot.log.info('Sending network password...') self.output.cmdPASS(password) # Start logging in. self.logger.info('Logging in as {}!{} :{}...'.format( self.nick, self.ident, self.gecos)) self.output.cmdNICK(self.nick) self.output.cmdUSER(self.ident, self.gecos)
def requestAvatarId(self, credentials): """ Extract an avatar ID from an ISSLTransport object. NOTE: Authentication has technically already happened during the SSL handshake. """ if not ISSLTransport.providedBy(credentials): return defer.fail( UnauthorizedLogin( "The credentials provided did not provide the ISSLTransport interface." )) peer_cert = credentials.getPeerCertificate() if peer_cert is None: return defer.fail( UnauthorizedLogin("A client certificate was not provided!")) subject = peer_cert.get_subject() #issuer = peer_cert.get_issuer() transform = self.transform subject_components = subject.get_components() match_part = self.subject_part avatar_part = None for part, value in subject_components: if part == match_part: avatar_part = value break if avatar_part is None: return defer.fail( UnauthorizedLogin( "Client certificate did not contain subject part '%s'." % match_part)) if transform is not None: return defer.maybeDeferred(transform, avatar_part) else: return defer.succeed(avatar_part)
def test_interfaces(self): """ L{TLSMemoryBIOProtocol} instances provide L{ISSLTransport} and L{ISystemHandle}. """ proto = TLSMemoryBIOProtocol(None, None) self.assertTrue(ISSLTransport.providedBy(proto)) self.assertTrue(ISystemHandle.providedBy(proto))
def _isSecure(self): """ Returns L{True} if this channel is using a secure transport. @returns: L{True} if this channel is secure. @rtype: L{bool} """ # A channel is secure if its transport is ISSLTransport. return ISSLTransport(self.transport, None) is not None
def connectionMade(self): # We need to callLater the connect action call because the connection isn't fully set up yet, # nor is it fully set up even with a delay of zero, which causes the message buffer not to be sent # when the connection is closed. # The "connection" register hold is used basically solely for the purposes of this to prevent potential # race conditions with registration. reactor.callLater(0.1, self._callConnectAction) if ISSLTransport.providedBy(self.transport): self.secureConnection = True
def extract_peer_certificate(transport): """ Extract TLS x509 client certificate information from a Twisted stream transport. """ if not _HAS_TLS: raise Exception( "cannot extract certificate - TLS support packages not installed") # check if the Twisted transport is a TLSMemoryBIOProtocol if not (hasattr(transport, 'getPeerCertificate') and ISSLTransport.providedBy(transport)): return None cert = transport.getPeerCertificate() if cert: # Extract x509 name components from an OpenSSL X509Name object. # pkey = cert.get_pubkey() def maybe_bytes(value): if isinstance(value, bytes): return value.decode('utf8') else: return value result = { u'md5': u'{}'.format(maybe_bytes(cert.digest('md5'))).upper(), u'sha1': u'{}'.format(maybe_bytes(cert.digest('sha1'))).upper(), u'sha256': u'{}'.format(maybe_bytes(cert.digest('sha256'))).upper(), u'expired': bool(cert.has_expired()), u'hash': maybe_bytes(cert.subject_name_hash()), u'serial': int(cert.get_serial_number()), u'signature_algorithm': maybe_bytes(cert.get_signature_algorithm()), u'version': int(cert.get_version()), u'not_before': maybe_bytes(cert.get_notBefore()), u'not_after': maybe_bytes(cert.get_notAfter()), u'extensions': [] } for i in range(cert.get_extension_count()): ext = cert.get_extension(i) ext_info = { u'name': u'{}'.format(maybe_bytes(ext.get_short_name())), u'value': u'{}'.format(maybe_bytes(ext)), u'criticial': ext.get_critical() != 0 } result[u'extensions'].append(ext_info) for entity, name in [(u'subject', cert.get_subject()), (u'issuer', cert.get_issuer())]: result[entity] = {} for key, value in name.get_components(): key = maybe_bytes(key) value = maybe_bytes(value) result[entity][u'{}'.format(key).lower()] = u'{}'.format(value) return result
def connectionMade(self): # We need to callLater the connect action call because the connection isn't fully set up yet, # nor is it fully set up even with a delay of zero, which causes the message buffer not to be sent # when the connection is closed. # The "connection" register hold is used basically solely for the purposes of this to prevent potential # race conditions with registration. self._connectHandlerTimer = reactor.callLater(0.1, self._callConnectAction) if ISSLTransport.providedBy(self.transport): self.secureConnection = True
def startNegotiation(self, server, prefix, params): self.bot.log.info("[{server}] Server replied: \"{reply}\"", server=server, reply=params[1]) self.bot.log.info("[{server}] Proceeding with TLS handshake...", server=server) self.bot.servers[server].transport.startTLS(ssl.CertificateOptions()) if ISSLTransport.providedBy(self.bot.servers[server].transport): self.bot.servers[server].secureConnection = True self.bot.log.info("[{server}] TLS handshake successful. Connection is now secure.", server=server) else: self.bot.log.warn("[{server}] TLS handshake failed. Connection is still not secure!", server=server) self.bot.moduleHandler.runGenericAction("cap-handler-finished", server, self.capName) return True
def onUse(self, user, data): try: user.socket.transport = ITLSTransport(user.socket.transport) except: user.sendMessage(irc.ERR_STARTTLS, ":STARTTLS failed") else: user.sendMessage( irc.RPL_STARTTLS, ":STARTTLS successful, proceed with TLS handshake") user.socket.transport.startTLS(self.ircd.ssl_cert) user.socket.secure = ISSLTransport(user.socket.transport, None) is not None
def extract_peer_certificate(transport): """ Extract TLS x509 client certificate information from a Twisted stream transport. """ if not _HAS_TLS: raise Exception("cannot extract certificate - TLS support packages not installed") # check if the Twisted transport is a TLSMemoryBIOProtocol if not (hasattr(transport, 'getPeerCertificate') and ISSLTransport.providedBy(transport)): return None cert = transport.getPeerCertificate() if cert: # Extract x509 name components from an OpenSSL X509Name object. # pkey = cert.get_pubkey() def maybe_bytes(value): if type(value) == six.binary_type: return value.decode('utf8') else: return value result = { u'md5': u'{}'.format(maybe_bytes(cert.digest('md5'))).upper(), u'sha1': u'{}'.format(maybe_bytes(cert.digest('sha1'))).upper(), u'sha256': u'{}'.format(maybe_bytes(cert.digest('sha256'))).upper(), u'expired': bool(cert.has_expired()), u'hash': maybe_bytes(cert.subject_name_hash()), u'serial': int(cert.get_serial_number()), u'signature_algorithm': maybe_bytes(cert.get_signature_algorithm()), u'version': int(cert.get_version()), u'not_before': maybe_bytes(cert.get_notBefore()), u'not_after': maybe_bytes(cert.get_notAfter()), u'extensions': [] } for i in range(cert.get_extension_count()): ext = cert.get_extension(i) ext_info = { u'name': u'{}'.format(maybe_bytes(ext.get_short_name())), u'value': u'{}'.format(maybe_bytes(ext)), u'criticial': ext.get_critical() != 0 } result[u'extensions'].append(ext_info) for entity, name in [(u'subject', cert.get_subject()), (u'issuer', cert.get_issuer())]: result[entity] = {} for key, value in name.get_components(): key = maybe_bytes(key) value = maybe_bytes(value) result[entity][u'{}'.format(key).lower()] = u'{}'.format(value) return result
def extract_peer_certificate(transport): """ Extract TLS x509 client certificate information from a Twisted stream transport. """ if not _HAS_TLS: raise Exception("cannot extract certificate - TLS support packages not installed") # check if the Twisted transport is a TLSMemoryBIOProtocol if not (hasattr(transport, "getPeerCertificate") and ISSLTransport.providedBy(transport)): return None cert = transport.getPeerCertificate() if cert: # Extract x509 name components from an OpenSSL X509Name object. # pkey = cert.get_pubkey() def maybe_bytes(value): if type(value) == six.binary_type: return value.decode("utf8") else: return value result = { u"md5": u"{}".format(maybe_bytes(cert.digest("md5"))).upper(), u"sha1": u"{}".format(maybe_bytes(cert.digest("sha1"))).upper(), u"sha256": u"{}".format(maybe_bytes(cert.digest("sha256"))).upper(), u"expired": bool(cert.has_expired()), u"hash": maybe_bytes(cert.subject_name_hash()), u"serial": int(cert.get_serial_number()), u"signature_algorithm": maybe_bytes(cert.get_signature_algorithm()), u"version": int(cert.get_version()), u"not_before": maybe_bytes(cert.get_notBefore()), u"not_after": maybe_bytes(cert.get_notAfter()), u"extensions": [], } for i in range(cert.get_extension_count()): ext = cert.get_extension(i) ext_info = { u"name": u"{}".format(maybe_bytes(ext.get_short_name())), u"value": u"{}".format(maybe_bytes(ext)), u"criticial": ext.get_critical() != 0, } result[u"extensions"].append(ext_info) for entity, name in [(u"subject", cert.get_subject()), (u"issuer", cert.get_issuer())]: result[entity] = {} for key, value in name.get_components(): key = maybe_bytes(key) value = maybe_bytes(value) result[entity][u"{}".format(key).lower()] = u"{}".format(value) return result
def signedOn(self): if ISSLTransport.providedBy(self.transport): cert = self.transport.getPeerCertificate() fp = cert.digest("sha1") verified = "verified" if self.factory.parent.server_fingerprint else "unverified" self.console("irc: connected securely. server fingerprint: {0} ({1})".format(fp, verified)) else: self.console("irc: connected") if self.ns_username and self.ns_password and not self.sasl_login: self.msg('NickServ', 'IDENTIFY {0} {1}'.format(self.ns_username, self.ns_password)) self.join(self.channel)
def signedOn(self): if ISSLTransport.providedBy(self.transport): cert = self.transport.getPeerCertificate() fp = cert.digest("sha1") verified = "verified" if self.factory.parent.server_fingerprint else "unverified" print("irc: connected securely. server fingerprint: {0} ({1})".format(fp, verified)) else: print("irc: connected") if self.ns_username and self.ns_password and not self.sasl_login: self.msg('NickServ', 'IDENTIFY {0} {1}'.format(self.ns_username, self.ns_password)) for channel in self.join_channels: self.join(channel)
def _create_transport_details(self): """ Internal helper. Base class calls this to create a TransportDetails """ # note that ITLSTransport exists too, which is "a TCP # transport that *can be upgraded* to TLS" .. if it *is* # upgraded to TLS, then the transport will implement # ISSLTransport at that point according to Twisted # documentation # the peer we are connected to is_secure = ISSLTransport.providedBy(self.transport) if is_secure: secure_channel_id = { 'tls-unique': transport_channel_id(self.transport, False, 'tls-unique'), } else: secure_channel_id = {} return TransportDetails(peer=self.peer, is_secure=is_secure, secure_channel_id=secure_channel_id)
def _create_transport_details(self): """ Internal helper. Base class calls this to create a TransportDetails """ # note that ITLSTransport exists too, which is "a TCP # transport that *can be upgraded* to TLS" .. if it *is* # upgraded to TLS, then the transport will implement # ISSLTransport at that point according to Twisted # documentation # the peer we are connected to is_secure = ISSLTransport.providedBy(self.transport) if is_secure: secure_channel_id = { u'tls-unique': transport_channel_id(self.transport, False, u'tls-unique'), } else: secure_channel_id = {} return TransportDetails(peer=self.peer, is_secure=is_secure, secure_channel_id=secure_channel_id)
def startNegotiation(self, server, prefix, params): self.bot.log.info("[{server}] Server replied: \"{reply}\"", server=server, reply=params[1]) self.bot.log.info("[{server}] Proceeding with TLS handshake...", server=server) self.bot.servers[server].transport.startTLS(ssl.CertificateOptions()) if ISSLTransport.providedBy(self.bot.servers[server].transport): self.bot.servers[server].secureConnection = True self.bot.log.info( "[{server}] TLS handshake successful. Connection is now secure.", server=server) else: self.bot.log.warn( "[{server}] TLS handshake failed. Connection is still not secure!", server=server) self.bot.moduleHandler.runGenericAction("cap-handler-finished", server, self.capName) return True
def connectionMade(self): self.bot.moduleHandler.runGenericAction("connect", self.name) # Connection finalizing. if ISSLTransport.providedBy(self.transport): self.secureConnection = True self.name = self.transport.addr[0] self.bot.log.info("[{connection}] Connection established.", connection=self.name) self.supportHelper.network = self.name self.bot.servers[self.name] = self # Enable modules. self.bot.moduleHandler.enableModulesForServer(self.name) # Initialize login data from the config. self.nick = self.bot.config.serverItemWithDefault( self.name, "nickname", "HeufyBot") self.ident = self.bot.config.serverItemWithDefault( self.name, "username", self.nick) self.gecos = self.bot.config.serverItemWithDefault( self.name, "realname", self.nick) # Send a server password if defined. password = self.bot.config.serverItemWithDefault( self.name, "password", None) if password: self.bot.log.info("[{connection}] Sending network password...", connection=self.name) self.outputHandler.cmdPASS(password) # Start logging in. self.bot.moduleHandler.runGenericAction("prelogin", self.name) self.bot.log.info( "[{connection}] Logging in as {nick}!{ident} :{gecos}...", connection=self.name, nick=self.nick, ident=self.ident, gecos=self.gecos) self.outputHandler.cmdNICK(self.nick) self.outputHandler.cmdUSER(self.ident, self.gecos)
def execute(self, user, data): if user.secureConnection: user.sendMessage(irc.ERR_STARTTLS, "The connection is already secure") return True try: secureTransport = ITLSTransport(user.transport) except TypeError: user.sendMessage(irc.ERR_STARTTLS, "Failed to initialize transport for STARTTLS") return True if secureTransport is None: user.sendMessage(irc.ERR_STARTTLS, "Failed to initialize transport for STARTTLS") return True user.transport = secureTransport user.sendMessage(irc.RPL_STARTTLS, "STARTTLS successful; proceed with TLS handshake") secureTransport.startTLS(self.certContext) user.secureConnection = ISSLTransport(secureTransport, None) is not None return True
def isTLS(xmlstream): return ISSLTransport.providedBy(xmlstream.transport) or \ isinstance(xmlstream.transport, twisted.TLSMixin)
def process_connect(self, packet): """ Process the initial Connect message from the MQTT client. This should return a pair `(accept_conn, session_present)`, where `accept_conn` is a return code: 0: connection accepted 1-5: connection refused (see MQTT spec 3.2.2.3) """ # Connect(client_id='paho/4E23D8C09DD9C6CF2C', # flags=ConnectFlags(username=False, # password=False, # will=False, # will_retain=False, # will_qos=0, # clean_session=True, # reserved=False), # keep_alive=60, # will_topic=None, # will_message=None, # username=None, # password=None) self.log.info( 'WampMQTTServerProtocol.process_connect(packet={packet})', packet=packet) # we don't support session resumption: https://github.com/crossbario/crossbar/issues/892 if not packet.flags.clean_session: self.log.warn( 'denying MQTT connect from {peer}, as the clients wants to resume a session (which we do not support)', peer=peer2str(self.transport.getPeer())) return succeed((1, False)) # we won't support QoS 2: https://github.com/crossbario/crossbar/issues/1046 if packet.flags.will and packet.flags.will_qos not in [0, 1]: self.log.warn( 'denying MQTT connect from {peer}, as the clients wants to provide a "last will" event with QoS {will_qos} (and we only support QoS 0/1 here)', peer=peer2str(self.transport.getPeer()), will_qos=packet.flags.will_qos) return succeed((1, False)) # this will be resolved when the MQTT connect handshake is completed self._waiting_for_connect = Deferred() roles = { "subscriber": role.RoleSubscriberFeatures(payload_transparency=True, pattern_based_subscription=True), "publisher": role.RolePublisherFeatures(payload_transparency=True, x_acknowledged_event_delivery=True) } realm = self.factory._options.get('realm', None) authmethods = [] authextra = { 'mqtt': { 'client_id': packet.client_id, 'will': bool(packet.flags.will), 'will_topic': packet.will_topic } } if ISSLTransport.providedBy(self.transport): authmethods.append("tls") if packet.username and packet.password: authmethods.append("ticket") msg = message.Hello(realm=realm, roles=roles, authmethods=authmethods, authid=packet.username, authextra=authextra) self._pw_challenge = packet.password else: authmethods.append("anonymous") msg = message.Hello(realm=realm, roles=roles, authmethods=authmethods, authid=packet.client_id, authextra=authextra) self._wamp_session.onMessage(msg) if packet.flags.will: # it's unclear from the MQTT spec whether a) the publication of the last will # is to happen in-band during "connect", and if it fails, deny the connection, # or b) the last will publication happens _after_ "connect", and the connection # succeeds regardless whether the last will publication succeeds or not. # # we opt for b) here! # @inlineCallbacks @self._waiting_for_connect.addCallback def process_will(res): self.log.info() payload_format, mapped_topic, options = yield self.factory.transform_mqtt( packet.will_topic, packet.will_message) request = util.id() msg = message.Call( request=request, procedure="wamp.session.add_testament", args=[ mapped_topic, options.get('args', None), options.get('kwargs', None), { # specifiy "retain" for when the testament (last will) # will be auto-published by the broker later 'retain': bool(packet.flags.will_retain) } ]) self._wamp_session.onMessage(msg) returnValue(res) return self._waiting_for_connect
def connectionMade(self, ignore_handshake=False): if ignore_handshake or not ISSLTransport.providedBy(self.transport): self._when_ready()
def onOpen(self, transport): """ Implements :func:`autobahn.wamp.interfaces.ITransportHandler.onOpen` """ # this is a WAMP transport instance self._transport = transport # this is a Twisted stream transport instance stream_transport = self._transport.transport # a dict with x509 TLS client certificate information (if the client provided a cert) self._client_cert = None # check if stream_transport is a TLSMemoryBIOProtocol if hasattr(stream_transport, 'getPeerCertificate') and ISSLTransport.providedBy(stream_transport): cert = self._transport.transport.getPeerCertificate() if cert: def extract_x509(cert): """ Extract x509 name components from an OpenSSL X509Name object. """ # pkey = cert.get_pubkey() result = { u'md5': u'{}'.format(cert.digest('md5')).upper(), u'sha1': u'{}'.format(cert.digest('sha1')).upper(), u'sha256': u'{}'.format(cert.digest('sha256')).upper(), u'expired': cert.has_expired(), u'hash': cert.subject_name_hash(), u'serial': cert.get_serial_number(), u'signature_algorithm': cert.get_signature_algorithm(), u'version': cert.get_version(), u'not_before': cert.get_notBefore(), u'not_after': cert.get_notAfter(), u'extensions': [] } for i in range(cert.get_extension_count()): ext = cert.get_extension(i) ext_info = { u'name': u'{}'.format(ext.get_short_name()), u'value': u'{}'.format(ext), u'criticial': ext.get_critical() != 0 } result[u'extensions'].append(ext_info) for entity, name in [(u'subject', cert.get_subject()), (u'issuer', cert.get_issuer())]: result[entity] = {} for key, value in name.get_components(): result[entity][u'{}'.format(key).lower()] = u'{}'.format(value) return result self._client_cert = extract_x509(self._transport.transport.getPeerCertificate()) self.log.debug("Client connecting with TLS certificate cn='{cert_cn}', sha1={cert_sha1}.., expired={cert_expired}", cert_cn=self._client_cert['subject']['cn'], cert_sha1=self._client_cert['sha1'][:12], cert_expired=self._client_cert['expired']) if self._transport._transport_info: self._transport._transport_info[u'client_cert'] = self._client_cert self._realm = None self._session_id = None self._pending_session_id = None self._session_roles = None # session authentication information # self._authid = None self._authrole = None self._authmethod = None self._authprovider = None self._authextra = None if hasattr(self._transport, 'factory') and hasattr(self._transport.factory, '_config'): self._transport_config = self._transport.factory._config else: self._transport_config = {} self._pending_auth = None self._session_details = None self._service_session = None
def process_connect(self, packet): """ Process the initial Connect message from the MQTT client. This should return a pair `(accept_conn, session_present)`, where `accept_conn` is a return code: 0: connection accepted 1-5: connection refused (see MQTT spec 3.2.2.3) """ # Connect(client_id='paho/4E23D8C09DD9C6CF2C', # flags=ConnectFlags(username=False, # password=False, # will=False, # will_retain=False, # will_qos=0, # clean_session=True, # reserved=False), # keep_alive=60, # will_topic=None, # will_message=None, # username=None, # password=None) self.log.info('WampMQTTServerProtocol.process_connect(packet={packet})', packet=packet) # we don't support session resumption: https://github.com/crossbario/crossbar/issues/892 if not packet.flags.clean_session: self.log.warn('denying MQTT connect from {peer}, as the clients wants to resume a session (which we do not support)', peer=peer2str(self.transport.getPeer())) return succeed((1, False)) # we won't support QoS 2: https://github.com/crossbario/crossbar/issues/1046 if packet.flags.will and packet.flags.will_qos not in [0, 1]: self.log.warn('denying MQTT connect from {peer}, as the clients wants to provide a "last will" event with QoS {will_qos} (and we only support QoS 0/1 here)', peer=peer2str(self.transport.getPeer()), will_qos=packet.flags.will_qos) return succeed((1, False)) # this will be resolved when the MQTT connect handshake is completed self._waiting_for_connect = Deferred() roles = { u"subscriber": role.RoleSubscriberFeatures( payload_transparency=True, pattern_based_subscription=True), u"publisher": role.RolePublisherFeatures( payload_transparency=True, x_acknowledged_event_delivery=True) } realm = self.factory._options.get(u'realm', None) authmethods = [] authextra = { u'mqtt': { u'client_id': packet.client_id, u'will': bool(packet.flags.will), u'will_topic': packet.will_topic } } if ISSLTransport.providedBy(self.transport): authmethods.append(u"tls") if packet.username and packet.password: authmethods.append(u"ticket") msg = message.Hello( realm=realm, roles=roles, authmethods=authmethods, authid=packet.username, authextra=authextra) self._pw_challenge = packet.password else: authmethods.append(u"anonymous") msg = message.Hello( realm=realm, roles=roles, authmethods=authmethods, authid=packet.client_id, authextra=authextra) self._wamp_session.onMessage(msg) if packet.flags.will: # it's unclear from the MQTT spec whether a) the publication of the last will # is to happen in-band during "connect", and if it fails, deny the connection, # or b) the last will publication happens _after_ "connect", and the connection # succeeds regardless whether the last will publication succeeds or not. # # we opt for b) here! # @inlineCallbacks @self._waiting_for_connect.addCallback def process_will(res): self.log.info() payload_format, mapped_topic, options = yield self.factory.transform_mqtt(packet.will_topic, packet.will_message) request = util.id() msg = message.Call( request=request, procedure=u"wamp.session.add_testament", args=[ mapped_topic, options.get('args', None), options.get('kwargs', None), { # specifiy "retain" for when the testament (last will) # will be auto-published by the broker later u'retain': bool(packet.flags.will_retain) } ]) self._wamp_session.onMessage(msg) returnValue(res) return self._waiting_for_connect
def emitpong(self): from twisted.internet.interfaces import ISSLTransport if not ISSLTransport.providedBy(self.transport): raise DeathThreat("only send secure pings over secure channels") return {'pinged': True}
def isSecure(self): return ISSLTransport(self.transport, None) is not None
def process_connect(self, packet): try: self.log.debug( 'WampMQTTServerProtocol.process_connect(packet={packet})', packet=packet) self._waiting_for_connect = Deferred() roles = { u"subscriber": role.RoleSubscriberFeatures(payload_transparency=True), u"publisher": role.RolePublisherFeatures(payload_transparency=True, x_acknowledged_event_delivery=True) } realm = self.factory._options.get('realm', None) methods = [] if ISSLTransport.providedBy(self.transport): methods.append(u"tls") if packet.username and packet.password: methods.append(u"ticket") msg = message.Hello(realm=realm, roles=roles, authmethods=methods, authid=packet.username) self._pw_challenge = packet.password else: methods.append(u"anonymous") msg = message.Hello(realm=realm, roles=roles, authmethods=methods, authid=packet.client_id) self._wamp_session.onMessage(msg) if packet.flags.will: @inlineCallbacks @self._waiting_for_connect.addCallback def process_will(res): payload_format, mapped_topic, options = yield self.factory.transform_mqtt( packet.will_topic, packet.will_message) request = util.id() msg = message.Call(request=request, procedure=u"wamp.session.add_testament", args=[ mapped_topic, options.get('args', None), options.get('kwargs', None), { 'retain': bool(packet.flags.will_retain) } ]) self._wamp_session.onMessage(msg) returnValue(res) return self._waiting_for_connect except: self.log.failure()
def onOpen(self, transport): """ Implements :func:`autobahn.wamp.interfaces.ITransportHandler.onOpen` """ # this is a WAMP transport instance self._transport = transport # this is a Twisted stream transport instance stream_transport = self._transport.transport # a dict with x509 TLS client certificate information (if the client provided a cert) self._client_cert = None # check if stream_transport is a TLSMemoryBIOProtocol if hasattr(stream_transport, 'getPeerCertificate' ) and ISSLTransport.providedBy(stream_transport): cert = self._transport.transport.getPeerCertificate() if cert: def extract_x509(cert): """ Extract x509 name components from an OpenSSL X509Name object. """ # pkey = cert.get_pubkey() result = { u'md5': u'{}'.format(cert.digest('md5')).upper(), u'sha1': u'{}'.format(cert.digest('sha1')).upper(), u'sha256': u'{}'.format(cert.digest('sha256')).upper(), u'expired': cert.has_expired(), u'hash': cert.subject_name_hash(), u'serial': cert.get_serial_number(), u'signature_algorithm': cert.get_signature_algorithm(), u'version': cert.get_version(), u'not_before': cert.get_notBefore(), u'not_after': cert.get_notAfter(), u'extensions': [] } for i in range(cert.get_extension_count()): ext = cert.get_extension(i) ext_info = { u'name': u'{}'.format(ext.get_short_name()), u'value': u'{}'.format(ext), u'criticial': ext.get_critical() != 0 } result[u'extensions'].append(ext_info) for entity, name in [(u'subject', cert.get_subject()), (u'issuer', cert.get_issuer())]: result[entity] = {} for key, value in name.get_components(): result[entity][u'{}'.format( key).lower()] = u'{}'.format(value) return result self._client_cert = extract_x509( self._transport.transport.getPeerCertificate()) self.log.debug( "Client connecting with TLS certificate cn='{cert_cn}', sha1={cert_sha1}.., expired={cert_expired}", cert_cn=self._client_cert['subject']['cn'], cert_sha1=self._client_cert['sha1'][:12], cert_expired=self._client_cert['expired']) if self._transport._transport_info: self._transport._transport_info[u'client_cert'] = self._client_cert self._realm = None self._session_id = None self._pending_session_id = None self._session_roles = None # session authentication information # self._authid = None self._authrole = None self._authmethod = None self._authprovider = None self._authextra = None if hasattr(self._transport, 'factory') and hasattr( self._transport.factory, '_config'): self._transport_config = self._transport.factory._config else: self._transport_config = {} self._pending_auth = None self._session_details = None self._service_session = None
def ext_AUTH(self, rest): # if we aren't encrypted, do not accept any authentication if ISSLTransport.providedBy(self.transport): return smtp.ESMTP.ext_AUTH(self, rest) self.sendCode(530, 'Encrypt the connection by using SSL or STARTTLS before authenticating.')
def process_connect(self, packet): self._waiting_for_connect = Deferred() roles = { u"subscriber": role.RoleSubscriberFeatures(payload_transparency=True), u"publisher": role.RolePublisherFeatures(payload_transparency=True, x_acknowledged_event_delivery=True) } # Will be autoassigned realm = None methods = [] if ISSLTransport.providedBy(self.transport): methods.append(u"tls") if packet.username and packet.password: methods.append(u"ticket") msg = message.Hello(realm=realm, roles=roles, authmethods=methods, authid=packet.username) self._pw_challenge = packet.password else: methods.append(u"anonymous") msg = message.Hello(realm=realm, roles=roles, authmethods=methods, authid=packet.client_id) self._wamp_session.onMessage(msg) if packet.flags.will: @self._waiting_for_connect.addCallback def process_will(res): akw = mqtt_payload_transform( self._wamp_session._router._mqtt_payload_format, packet.will_message) if not akw: # Drop it I guess :( return res args, kwargs = akw msg = message.Call( request=util.id(), procedure=u"wamp.session.add_testament", args=[ u".".join(tokenise_mqtt_topic(packet.will_topic)), args, kwargs, { "retain": bool(packet.flags.will_retain) } ]) self._wamp_session.onMessage(msg) return res return self._waiting_for_connect