def test_authorization_challenge_submit_bad_last_message(self): """ Test the AuthorizationChallengeSubmitHandler returns an AuthorizationViolation and closes the connection if the last message was not AuthorizaitonChallengeRequest. """ context = create_context('secp256k1') private_key = context.new_random_private_key() crypto_factory = CryptoFactory(context) signer = crypto_factory.new_signer(private_key) payload = os.urandom(10) signature = signer.sign(payload) auth_challenge_submit = AuthorizationChallengeSubmit( public_key=signer.get_public_key().as_hex(), signature=signature, roles=[RoleType.Value("NETWORK")]) roles = {"network": AuthorizationType.TRUST} network = MockNetwork(roles, connection_status={"connection_id": "other"}) permission_verifer = MockPermissionVerifier() gossip = MockGossip() handler = AuthorizationChallengeSubmitHandler( network, permission_verifer, gossip, {"connection_id": payload}) handler_status = handler.handle( "connection_id", auth_challenge_submit.SerializeToString()) self.assertEqual(handler_status.status, HandlerStatus.RETURN_AND_CLOSE) self.assertEqual(handler_status.message_type, validator_pb2.Message.AUTHORIZATION_VIOLATION)
def test_authorization_challenge_submit(self): """ Test the AuthorizationChallengeSubmitHandler returns an AuthorizationViolation and closes the connection if the permission verifier does not permit the public_key. """ private_key = signing.generate_privkey() public_key = signing.generate_pubkey(private_key) payload = os.urandom(10) signature = signing.sign(payload, private_key) auth_challenge_submit = AuthorizationChallengeSubmit( public_key=public_key, payload=payload, signature=signature, roles=[RoleType.Value("NETWORK")]) roles = {"network": AuthorizationType.TRUST} network = MockNetwork(roles, connection_status={ "connection_id": ConnectionStatus.AUTH_CHALLENGE_REQUEST }) permission_verifer = MockPermissionVerifier(allow=False) gossip = MockGossip() handler = AuthorizationChallengeSubmitHandler(network, permission_verifer, gossip) handler_status = handler.handle( "connection_id", auth_challenge_submit.SerializeToString()) self.assertEqual(handler_status.status, HandlerStatus.RETURN_AND_CLOSE) self.assertEqual(handler_status.message_type, validator_pb2.Message.AUTHORIZATION_VIOLATION)
def _inbound_challenge_authorization_callback(self, request, result, connection=None): if result.message_type != \ validator_pb2.Message.AUTHORIZATION_CHALLENGE_RESPONSE: LOGGER.debug("Unable to complete Challenge Authorization.") return auth_challenge_response = AuthorizationChallengeResponse() auth_challenge_response.ParseFromString(result.content) payload = auth_challenge_response.payload signature = signing.sign(payload, self._priv_key) auth_challenge_submit = AuthorizationChallengeSubmit( public_key=self._public_key, payload=payload, signature=signature, roles=[RoleType.Value("NETWORK")]) self.send(validator_pb2.Message.AUTHORIZATION_CHALLENGE_SUBMIT, auth_challenge_submit.SerializeToString(), connection)
def test_authorization_challenge_submit(self): """ Test the AuthorizationChallengeSubmitHandler returns an AuthorizationChallengeResult. """ context = create_context('secp256k1') private_key = context.new_random_private_key() crypto_factory = CryptoFactory(context) signer = crypto_factory.new_signer(private_key) payload = os.urandom(10) signature = signer.sign(payload) auth_challenge_submit = AuthorizationChallengeSubmit( public_key=signer.get_public_key().as_hex(), signature=signature, roles=[RoleType.Value("NETWORK")]) roles = {"network": AuthorizationType.TRUST} network = MockNetwork(roles, connection_status={ "connection_id": ConnectionStatus.AUTH_CHALLENGE_REQUEST }) permission_verifer = MockPermissionVerifier() gossip = MockGossip() handler = AuthorizationChallengeSubmitHandler(network, permission_verifer, gossip) handler_status = handler.handle( "connection_id", auth_challenge_submit.SerializeToString()) self.assertEqual(handler_status.status, HandlerStatus.RETURN) self.assertEqual(handler_status.message_type, validator_pb2.Message.AUTHORIZATION_CHALLENGE_RESULT)
def handle(self, connection_id, message_content): """ When the validator receives an AuthorizationChallengeSubmit message, it will verify the public key against the signature. If the public key is verified, the requested roles will be checked against the stored roles to see if the public key is included in the policy. If the node’s response is accepted, the node’s public key will be stored and the requester may start sending messages for the approved roles. If the requester wanted a role that is either not available on the endpoint, the requester does not have access to one of the roles requested, or the previous message was not an AuthorizationChallengeRequest, the challenge will be rejected and the connection will be closed. """ if self._network.get_connection_status(connection_id) != \ ConnectionStatus.AUTH_CHALLENGE_REQUEST: LOGGER.debug( "Connection's previous message was not a" " AuthorizationChallengeRequest, Remove connection to" "%s", connection_id) return AuthorizationChallengeSubmitHandler \ ._network_violation_result() auth_challenge_submit = AuthorizationChallengeSubmit() auth_challenge_submit.ParseFromString(message_content) try: payload = self._challenge_payload_cache[connection_id] except KeyError: LOGGER.debug( "Connection's challenge payload expired before a" "response was received. %s", connection_id) return AuthorizationChallengeSubmitHandler \ ._network_violation_result() context = create_context('secp256k1') try: public_key = Secp256k1PublicKey.from_hex( auth_challenge_submit.public_key) except ParseError: LOGGER.warning( 'Authorization Challenge Request cannot be ' 'verified. Invalid public key %s', auth_challenge_submit.public_key) return AuthorizationChallengeSubmitHandler \ ._network_violation_result() if not context.verify(auth_challenge_submit.signature, payload, public_key): LOGGER.warning( "Signature was not able to be verifed. Remove " "connection to %s", connection_id) return AuthorizationChallengeSubmitHandler \ ._network_violation_result() roles = self._network.roles for role in auth_challenge_submit.roles: if role == RoleType.Value("NETWORK") or role == \ RoleType.Value("ALL"): permitted = False if "network" in roles: permitted = self._permission_verifier.check_network_role( auth_challenge_submit.public_key) if not permitted: return AuthorizationChallengeSubmitHandler \ ._network_violation_result() self._network.update_connection_public_key( connection_id, auth_challenge_submit.public_key) if RoleType.Value("NETWORK") in auth_challenge_submit.roles: # Need to send ConnectionRequest to authorize ourself with the # connection if they initialized the connection try: is_outbound_connection = self._network.is_outbound_connection( connection_id) except KeyError: # Connection has gone away, drop message return HandlerResult(HandlerStatus.DROP) if not is_outbound_connection: self._network.send_connect_request(connection_id) else: # If this is an outbound connection, authorization is complete # for both connections and peering/topology build out can # begin. self._gossip.connect_success(connection_id) auth_challenge_result = AuthorizationChallengeResult( roles=[RoleType.Value("NETWORK")]) LOGGER.debug("Connection: %s is approved", connection_id) self._network.update_connection_status(connection_id, ConnectionStatus.CONNECTED) return HandlerResult( HandlerStatus.RETURN, message_out=auth_challenge_result, message_type=validator_pb2.Message.AUTHORIZATION_CHALLENGE_RESULT)
def handle(self, connection_id, message_content): """ When the validator receives an AuthorizationChallengeSubmit message, it will verify the public key against the signature. If the public key is verified, the requested roles will be checked against the stored roles to see if the public key is included in the policy. If the node’s response is accepted, the node’s public key will be stored and the requester may start sending messages for the approved roles. If the requester wanted a role that is either not available on the endpoint, the requester does not have access to one of the roles requested, or the previous message was not an AuthorizationChallengeRequest, the challenge will be rejected and the connection will be closed. """ if self._network.get_connection_status(connection_id) != \ ConnectionStatus.AUTH_CHALLENGE_REQUEST: LOGGER.debug( "Connection's previous message was not a" " AuthorizationChallengeRequest, Remove connection to" "%s", connection_id) violation = AuthorizationViolation( violation=RoleType.Value("NETWORK")) return HandlerResult( HandlerStatus.RETURN_AND_CLOSE, message_out=violation, message_type=validator_pb2.Message.AUTHORIZATION_VIOLATION) auth_challenge_submit = AuthorizationChallengeSubmit() auth_challenge_submit.ParseFromString(message_content) if not signing.verify(auth_challenge_submit.payload, auth_challenge_submit.signature, auth_challenge_submit.public_key): LOGGER.warning( "Signature was not able to be verifed. Remove " "connection to %s", connection_id) violation = AuthorizationViolation( violation=RoleType.Value("NETWORK")) return HandlerResult( HandlerStatus.RETURN_AND_CLOSE, message_out=violation, message_type=validator_pb2.Message.AUTHORIZATION_VIOLATION) roles = self._network.roles for role in auth_challenge_submit.roles: if role == RoleType.Value("NETWORK") or role == \ RoleType.Value("ALL"): permitted = False if "network" in roles: permitted = self._permission_verifier.check_network_role( auth_challenge_submit.public_key) if not permitted: violation = AuthorizationViolation( violation=RoleType.Value("NETWORK")) return HandlerResult(HandlerStatus.RETURN_AND_CLOSE, message_out=violation, message_type=validator_pb2.Message. AUTHORIZATION_VIOLATION) self._network.update_connection_public_key( connection_id, auth_challenge_submit.public_key) if RoleType.Value("NETWORK") in auth_challenge_submit.roles: # Need to send ConnectionRequest to authorize ourself with the # connection if they initialized the connection if not self._network.is_outbound_connection(connection_id): self._network.send_connect_request(connection_id) else: # If this is an outbound connection, authorization is complete # for both connections and peering/topology build out can # begin. self._gossip.connect_success(connection_id) auth_challenge_result = AuthorizationChallengeResult( roles=[RoleType.Value("NETWORK")]) LOGGER.debug("Connection: %s is approved", connection_id) self._network.update_connection_status(connection_id, ConnectionStatus.CONNECTED) return HandlerResult( HandlerStatus.RETURN, message_out=auth_challenge_result, message_type=validator_pb2.Message.AUTHORIZATION_CHALLENGE_RESULT)