def __init__(self, config=None): ApplicationSession.__init__(self, config) # FIXME self._default_gas = 100000 self._chain_id = 4 profile = config.extra['profile'] if 'ethkey' in config.extra and config.extra['ethkey']: self._ethkey_raw = config.extra['ethkey'] else: self._ethkey_raw = profile.ethkey self._ethkey = eth_keys.keys.PrivateKey(self._ethkey_raw) self._ethadr = web3.Web3.toChecksumAddress(self._ethkey.public_key.to_canonical_address()) self._ethadr_raw = binascii.a2b_hex(self._ethadr[2:]) self.log.info('Client Ethereum key loaded, public address is {adr}', func=hltype(self.__init__), adr=hlid(self._ethadr)) if 'cskey' in config.extra and config.extra['cskey']: cskey = config.extra['cskey'] else: cskey = profile.cskey self._key = cryptosign.SigningKey.from_key_bytes(cskey) self.log.info('Client WAMP authentication key loaded, public key is {pubkey}', func=hltype(self.__init__), pubkey=hlid('0x' + self._key.public_key())) self._running = True
async def authenticate(realm, authid, details): """ this is our dynamic authenticator procedure that will be called by Crossbar.io when a session is authenticating """ log.info( 'authenticate(realm="{realm}", authid="{authid}", details={details}) {func}', realm=hl(realm), authid=hl(authid), details=details, func=hltype(create_rlink_authenticator), ) assert ('authmethod' in details) assert (details['authmethod'] == 'cryptosign') assert ('authextra' in details) assert ('pubkey' in details['authextra']) pubkey = details['authextra']['pubkey'] log.info( 'authenticating session using realm="{realm}", pubkey={pubkey} .. {func}', realm=hl(realm), pubkey=hl(pubkey), func=hltype(create_rlink_authenticator), ) if pubkey in pubkey_to_principals: principal = pubkey_to_principals[pubkey] auth = { 'pubkey': pubkey, 'realm': principal['realm'], 'authid': principal['authid'], 'role': principal['role'], 'extra': principal['extra'], 'cache': True } # Note: with WAMP-cryptosign, even though a client may or may not request a `realm`, but in any case, the # effective realm the client is authenticated will be returned in the principal `auth['role']` (!) effective_realm = auth['realm'] log.info( 'found valid principal authid="{authid}", authrole="{authrole}", realm="{realm}" matching given client public key {func}', func=hltype(create_rlink_authenticator), authid=hl(auth['authid']), authrole=hl(auth['role']), realm=hl(effective_realm), ) # only now that we know the effective realm a client is to be joined to (see above), maybe active (start) # the desired application realm to let the client join to subsequently # await _maybe_activate_realm(controller, effective_realm) return auth else: msg = 'no principal with matching public key 0x{}'.format(pubkey) log.warn(msg) raise ApplicationError('com.example.no_such_user', msg)
def _send_Allowance(self, from_adr, to_adr, amount): # FIXME: estimate gas required for call gas = self._default_gas gasPrice = self._w3.toWei('10', 'gwei') from_adr = self._ethadr # each submitted transaction must contain a nonce, which is obtained by the on-chain transaction number # for this account, including pending transactions (I think ..;) .. nonce = self._w3.eth.getTransactionCount(from_adr, block_identifier='pending') self.log.info('{func}::[1/4] - Ethereum transaction nonce: nonce={nonce}', func=hltype(self._send_Allowance), nonce=nonce) # serialize transaction raw data from contract call and transaction settings raw_transaction = xbr.xbrtoken.functions.approve(to_adr, amount).buildTransaction({ 'from': from_adr, 'gas': gas, 'gasPrice': gasPrice, 'chainId': self._chain_id, # https://stackoverflow.com/a/57901206/884770 'nonce': nonce, }) self.log.info( '{func}::[2/4] - Ethereum transaction created: raw_transaction=\n{raw_transaction}\n', func=hltype(self._send_Allowance), raw_transaction=raw_transaction) # compute signed transaction from above serialized raw transaction signed_txn = self._w3.eth.account.sign_transaction(raw_transaction, private_key=self._ethkey_raw) self.log.info( '{func}::[3/4] - Ethereum transaction signed: signed_txn=\n{signed_txn}\n', func=hltype(self._send_Allowance), signed_txn=hlval(binascii.b2a_hex(signed_txn.rawTransaction).decode())) # now send the pre-signed transaction to the blockchain via the gateway .. # https://web3py.readthedocs.io/en/stable/web3.eth.html # web3.eth.Eth.sendRawTransaction txn_hash = self._w3.eth.sendRawTransaction(signed_txn.rawTransaction) txn_hash = bytes(txn_hash) self.log.info( '{func}::[4/4] - Ethereum transaction submitted: txn_hash=0x{txn_hash}', func=hltype(self._send_Allowance), txn_hash=hlval(binascii.b2a_hex(txn_hash).decode())) return txn_hash
def onJoin(self, details): def authenticate(realm, authid, details): self.log.info( '{func}(realm="{realm}", authid="{authid}", details=details)', func=authenticate, realm=hlid(realm), authid=hlid(authid), details=details) return 'anonymous' yield self.register(authenticate, 'crossbarfabriccenter.mrealm.arealm.authenticate') self.log.info('{func}() Application realm authenticator ready!', func=hltype(self.onJoin))
async def create_authenticator(config, controller): """ Creates and returns a function to do authentication. The actual authentication method will be called like: authenticate(realm, authid, session_details) Note that this function can itself do async work (as can the "authenticate" method). For example, we could connect to a database here (and then use that connection in the authenticate() method) 'controller' will be None unless `"expose_controller": true` is in the config. """ log.info( 'create_authenticator(config={config}) {func}', config=pformat(config), func=hltype(create_authenticator), ) def authenticate(realm, authid, details): ticket = details['ticket'] print( "WAMP-Ticket dynamic authenticator invoked: realm='{}', authid='{}', ticket='{}'" .format(realm, authid, ticket)) pprint(details) if authid in PRINCIPALS_DB: if ticket == PRINCIPALS_DB[authid]['ticket']: return PRINCIPALS_DB[authid]['role'] else: raise ApplicationError( "com.example.invalid_ticket", "could not authenticate session - invalid ticket '{}' for principal {}" .format(ticket, authid)) else: raise ApplicationError( "com.example.no_such_user", "could not authenticate session - no such principal {}".format( authid)) return authenticate
def __init__(self, config_path): self._config_path = os.path.abspath(config_path) config = configparser.ConfigParser() config.read(config_path) self.config = config profiles = {} for profile_name in config.sections(): profile = Profile.parse(config_path, profile_name, config.items(profile_name)) profiles[profile_name] = profile self.profiles = profiles self.log.debug('profiles loaded: {profiles}', func=hltype(self.__init__), profiles=', '.join( hlval(x) for x in sorted(self.profiles.keys())))
async def create_authenticator(config, controller): """ Creates and returns a function to do authentication. The actual authentication method will be called like: authenticate(realm, authid, session_details) Note that this function can itself do async work (as can the "authenticate" method). For example, we could connect to a database here (and then use that connection in the authenticate() method) 'controller' will be None unless `"expose_controller": true` is in the config. """ log.info( 'create_authenticator(config={config}) {func}', config=pformat(config), func=hltype(create_authenticator), ) def authenticate(realm, authid, details): print( "WAMP-CRA dynamic authenticator invoked: realm='{}', authid='{}'". format(realm, authid)) pprint(details) if authid in USERDB: # return a dictionary with authentication information ... return USERDB[authid] else: raise ApplicationError( 'com.example.no_such_user', 'could not authenticate session - no such user {}'.format( authid)) return authenticate
def run_on_button1(widget): self.log.info('{func}({widget})', func=hltype(run_on_button1), widget=widget) reactor.callLater(0, on_button1, widget)
async def create_rlink_authenticator(config, controller): """ Create an authenticator function for the listening transport of router workers in a worker group of a router cluster to authenticate rlink connections incoming from other workers in this worker group. The actual authentication method will be called like: authenticate(realm, authid, session_details) Note that this function can itself do async work (as can the "authenticate" method). For example, we could connect to a database here (and then use that connection in the authenticate() method) 'controller' will be None unless `"expose_controller": true` is in the config. """ log.info( '{func}(config={config}, controller={controller})', config=pformat(config), func=hltype(create_rlink_authenticator), controller=hltype(controller), ) pubkey_to_principals = {} for p in PRINCIPALS: for k in p['authorized_keys']: if k in pubkey_to_principals: raise Exception("ambiguous key {}".format(k)) else: pubkey_to_principals[k] = p async def authenticate(realm, authid, details): """ this is our dynamic authenticator procedure that will be called by Crossbar.io when a session is authenticating """ log.info( 'authenticate(realm="{realm}", authid="{authid}", details={details}) {func}', realm=hl(realm), authid=hl(authid), details=details, func=hltype(create_rlink_authenticator), ) assert ('authmethod' in details) assert (details['authmethod'] == 'cryptosign') assert ('authextra' in details) assert ('pubkey' in details['authextra']) pubkey = details['authextra']['pubkey'] log.info( 'authenticating session using realm="{realm}", pubkey={pubkey} .. {func}', realm=hl(realm), pubkey=hl(pubkey), func=hltype(create_rlink_authenticator), ) if pubkey in pubkey_to_principals: principal = pubkey_to_principals[pubkey] auth = { 'pubkey': pubkey, 'realm': principal['realm'], 'authid': principal['authid'], 'role': principal['role'], 'extra': principal['extra'], 'cache': True } # Note: with WAMP-cryptosign, even though a client may or may not request a `realm`, but in any case, the # effective realm the client is authenticated will be returned in the principal `auth['role']` (!) effective_realm = auth['realm'] log.info( 'found valid principal authid="{authid}", authrole="{authrole}", realm="{realm}" matching given client public key {func}', func=hltype(create_rlink_authenticator), authid=hl(auth['authid']), authrole=hl(auth['role']), realm=hl(effective_realm), ) # only now that we know the effective realm a client is to be joined to (see above), maybe active (start) # the desired application realm to let the client join to subsequently # await _maybe_activate_realm(controller, effective_realm) return auth else: msg = 'no principal with matching public key 0x{}'.format(pubkey) log.warn(msg) raise ApplicationError('com.example.no_such_user', msg) return authenticate