Пример #1
0
    def setUp(self):
        logger = logging.getLogger()
        logger.level = logging.DEBUG
        self.log_file = tempfile.NamedTemporaryFile()
        logger.addHandler(logging.FileHandler(self.log_file.name))

        self.eap_output_queue = Queue()
        self.radius_output_queue = Queue()
        self.timer_scheduler = FakeTimerScheduler()
        self.src_mac = MacAddress.from_string("00:12:34:56:78:90")
        log_prefix = "chewie.SM - port: %s, client: %s" % (self.src_mac,
                                                           self.PORT_ID_MAC)

        self.sm = FullEAPStateMachine(self.eap_output_queue,
                                      self.radius_output_queue, self.src_mac,
                                      self.timer_scheduler, self.auth_handler,
                                      self.failure_handler,
                                      self.logoff_handler, log_prefix)
        # find ways to inject these - overriding consts isn't ideal
        self.MAX_RETRANSMITS = 3
        self.sm.MAX_RETRANS = self.MAX_RETRANSMITS
        self.sm.DEFAULT_TIMEOUT = 0.1
        self.sm.port_enabled = True
        self.sm.eap_restart = True

        self.auth_counter = 0
        self.failure_counter = 0
        self.logoff_counter = 0
Пример #2
0
    def setUp(self):
        logger = logging.getLogger()
        logger.level = logging.DEBUG
        self.log_file = tempfile.NamedTemporaryFile()

        logger.addHandler(logging.FileHandler(self.log_file.name))
        logger.addHandler(logging.StreamHandler(sys.stdout))

        self.chewie = Chewie('lo', logger, auth_handler, failure_handler,
                             logoff_handler, '127.0.0.1', 1812, 'SECRET',
                             '44:44:44:44:44:44')
        self.fake_scheduler = FakeTimerScheduler()
        self.chewie.timer_scheduler = self.fake_scheduler

        global FROM_SUPPLICANT  # pylint: disable=global-statement
        global TO_SUPPLICANT  # pylint: disable=global-statement
        global FROM_RADIUS  # pylint: disable=global-statement
        global TO_RADIUS  # pylint: disable=global-statement
        global FROM_SUPPLICANT_ACTIVITY  # pylint: disable=global-statement

        FROM_SUPPLICANT = Queue()
        FROM_SUPPLICANT_ACTIVITY = Queue()
        TO_SUPPLICANT = Queue()
        FROM_RADIUS = Queue()
        TO_RADIUS = Queue()
Пример #3
0
    def setUp(self):
        self.logger = logging.getLogger()
        self.logger.level = logging.DEBUG
        self.log_file = tempfile.NamedTemporaryFile()

        self.logger.addHandler(logging.FileHandler(self.log_file.name))
        self.logger.addHandler(logging.StreamHandler(sys.stdout))

        self.fake_scheduler = FakeTimerScheduler()
        self.timer_scheduler = self.fake_scheduler
        self.managed_port = None
        self.eap_output_messages = Queue()  # pylint: disable=global-statement
        self.radius_output_messages = Queue()  # pylint: disable=global-statement
Пример #4
0
class FullStateMachineStartTestCase(unittest.TestCase):
    # TODO tests could be more thorough, and test that
    # the correct packet (type/content) has been put in its respective queue.
    # Would also be nice to check that the states are correctly transitioned through,
    # and not just the final resting spot. Not sure how to do that - maybe parse the log??

    PORT_ID_MAC = MacAddress.from_string("00:00:00:00:00:01")

    def setUp(self):
        logger = logging.getLogger()
        logger.level = logging.DEBUG
        self.log_file = tempfile.NamedTemporaryFile()
        logger.addHandler(logging.FileHandler(self.log_file.name))

        self.eap_output_queue = Queue()
        self.radius_output_queue = Queue()
        self.timer_scheduler = FakeTimerScheduler()
        self.src_mac = MacAddress.from_string("00:12:34:56:78:90")
        log_prefix = "chewie.SM - port: %s, client: %s" % (self.src_mac,
                                                           self.PORT_ID_MAC)

        self.sm = FullEAPStateMachine(self.eap_output_queue,
                                      self.radius_output_queue, self.src_mac,
                                      self.timer_scheduler, self.auth_handler,
                                      self.failure_handler,
                                      self.logoff_handler, log_prefix)
        # find ways to inject these - overriding consts isn't ideal
        self.MAX_RETRANSMITS = 3
        self.sm.MAX_RETRANS = self.MAX_RETRANSMITS
        self.sm.DEFAULT_TIMEOUT = 0.1
        self.sm.port_enabled = True
        self.sm.eap_restart = True

        self.auth_counter = 0
        self.failure_counter = 0
        self.logoff_counter = 0

    def tearDown(self):
        with open(self.log_file.name) as log:
            self.assertNotIn(
                'aaaEapResp is true. but data is false. This should never happen',
                log.read())

    def auth_handler(self, client_mac, port_id_mac, *args, **kwargs):  # pylint: disable=unused-argument
        self.auth_counter += 1
        print('Successful auth from MAC %s' % str(client_mac))

    def failure_handler(self, client_mac, port_id_mac):  # pylint: disable=unused-argument
        self.failure_counter += 1
        print('failure from MAC %s' % str(client_mac))

    def logoff_handler(self, client_mac, port_id_mac):  # pylint: disable=unused-argument
        self.logoff_counter += 1
        print('logoff from MAC %s' % str(client_mac))

    @check_counters
    def test_eap_start(self):
        # input EAPStart packet.
        # output EAPIdentityRequest on eap_output_q
        message = EapolStartMessage(self.src_mac)
        self.sm.event(EventMessageReceived(message, self.PORT_ID_MAC))
        self.assertEqual(self.sm.state, self.sm.IDLE)

        self.assertEqual(self.eap_output_queue.qsize(), 1)
        output = self.eap_output_queue.get_nowait()[0]
        self.assertIsInstance(output, IdentityMessage)
        self.assertEqual(self.radius_output_queue.qsize(), 0)

        return output  # Used by test_identity_response

    @check_counters
    def test_eap_restart(self):
        self.test_eap_start()
        message = EapolStartMessage(self.src_mac)
        self.sm.event(EventMessageReceived(message, self.PORT_ID_MAC))
        self.assertEqual(self.sm.state, self.sm.IDLE)

        self.assertEqual(self.eap_output_queue.qsize(), 1)
        output = self.eap_output_queue.get_nowait()[0]
        self.assertIsInstance(output, IdentityMessage)
        self.assertEqual(self.radius_output_queue.qsize(), 0)

    @check_counters
    def test_no_radius_state_attribute_after_restart(self):
        """The RADIUS State Attribute is returned by the RADIUS server,
        and MUST be sent back in the next RADIUS Message.
        Unless the authentication process has been restarted or its a new one.
        Here we restart part way through another."""
        self.test_md5_challenge_request()

        self.assertEqual(self.sm.radius_state_attribute.data(),
                         b'random state')

        self.test_eap_restart()
        self.assertIsNone(self.sm.radius_state_attribute)

    @check_counters
    def test_timeout_failure_from_max_retransmits(self):
        """Go to timeout failure from exceeding max retransmits (also tests retransmitting)"""
        output0 = self.test_eap_start()

        old_radius_count = self.radius_output_queue.qsize()
        self.timer_scheduler.run_jobs()

        output1 = self.eap_output_queue.get_nowait()[0]
        output2 = self.eap_output_queue.get_nowait()[0]
        output3 = self.eap_output_queue.get_nowait()[0]
        self.assertIsInstance(output0, IdentityMessage)
        self.assertIsInstance(output1, IdentityMessage)
        self.assertEqual(output0, output1)
        self.assertEqual(output0, output2)
        self.assertEqual(output0, output3)
        self.assertEqual(self.radius_output_queue.qsize(), 0)

        self.assertEqual(self.sm.state, self.sm.TIMEOUT_FAILURE)
        self.assertEqual(self.eap_output_queue.qsize(), 0)
        self.assertEqual(old_radius_count, self.radius_output_queue.qsize())

    @check_counters(expected_auth_counter=1)
    def test_auth_success_after_timeout_failure2_from_max_retransmits(self):
        self.test_timeout_failure2_from_max_retransmits()
        self.eap_output_queue.queue.clear()
        self.test_success2()

    @check_counters(expected_auth_counter=1)
    def test_auth_success_after_timeout_failure2_from_aaa_timeout(self):
        self.test_timeout_failure2_from_aaa_timeout()
        self.test_success2()

    @check_counters(expected_auth_counter=1)
    def test_auth_success_after_timeout_failure_after_max_retransmits(self):
        self.test_timeout_failure_from_max_retransmits()
        self.test_success2()

    @check_counters()
    def test_leave_timeout_failure2_with_identiy_response(self):
        self.test_timeout_failure2_from_max_retransmits()
        start_eap_q_size = self.eap_output_queue.qsize()
        start_radius_q_size = self.radius_output_queue.qsize()
        message = IdentityMessage(self.src_mac, 25, Eap.RESPONSE, "host1user")
        self.sm.event(EventMessageReceived(message, self.PORT_ID_MAC))
        self.assertEqual(self.sm.state, self.sm.AAA_IDLE)

        self.assertEqual(self.eap_output_queue.qsize(), start_eap_q_size + 0)
        self.assertEqual(self.radius_output_queue.qsize(),
                         start_radius_q_size + 1)
        self.assertIsInstance(self.radius_output_queue.get_nowait()[0],
                              IdentityMessage)

    @check_counters
    def test_timeout_failure2_from_aaa_timeout(self):
        """no response from AAA server equals timeout_failure2"""
        self.test_md5_challenge_response()
        old_eap_count = self.eap_output_queue.qsize()
        old_radius_count = self.radius_output_queue.qsize()

        self.timer_scheduler.run_jobs()

        self.assertEqual(self.sm.state, self.sm.TIMEOUT_FAILURE2)
        self.assertEqual(old_eap_count, self.eap_output_queue.qsize())
        self.assertEqual(old_radius_count, self.radius_output_queue.qsize())

    @check_counters
    def test_timeout_failure2_from_max_retransmits(self):
        """If client does not respond when in passthrough mode,
         send again and again until max retransmit counter is reached."""
        self.test_md5_challenge_request()
        self.assertEqual(self.eap_output_queue.qsize(), 0)
        old_radius_count = self.radius_output_queue.qsize()

        self.timer_scheduler.run_jobs()

        self.assertEqual(self.sm.state, self.sm.TIMEOUT_FAILURE2)
        self.assertEqual(self.MAX_RETRANSMITS, self.eap_output_queue.qsize())
        self.assertEqual(old_radius_count, self.radius_output_queue.qsize())

    @check_counters(expected_auth_counter=1)
    def test_disabled_state(self):
        """move to disabled and then from disabled"""
        self.test_success2()
        # move to disabled. e.g. link down.
        self.sm.event(EventPortStatusChange(False))
        self.assertEqual(self.sm.state, self.sm.DISABLED)

        self.assertEqual(self.eap_output_queue.qsize(), 0)
        self.assertEqual(self.radius_output_queue.qsize(), 0)
        self.assertEqual(self.auth_counter, 1)
        # don't transition to initialize (still not enabled)
        message = EapolStartMessage(self.src_mac)
        self.sm.event(EventMessageReceived(message, self.PORT_ID_MAC))

        self.assertEqual(self.sm.state, self.sm.DISABLED)
        self.assertEqual(self.eap_output_queue.qsize(), 0)
        self.assertEqual(self.radius_output_queue.qsize(), 0)

        # port is enabled again
        self.sm.event(EventPortStatusChange(True))

        self.assertEqual(self.sm.state, self.sm.IDLE)

        self.assertEqual(self.eap_output_queue.qsize(), 1)
        self.assertEqual(self.radius_output_queue.qsize(), 0)

    @check_counters
    def test_identity_response(self):
        _id = self.test_eap_start().message_id
        # input EapIdentityResponse
        # output EapIdentityResponse on radius_output_q
        message = IdentityMessage(self.src_mac, _id, Eap.RESPONSE, "host1user")
        self.sm.event(EventMessageReceived(message, self.PORT_ID_MAC))

        self.assertEqual(self.sm.state, self.sm.AAA_IDLE)

        self.assertEqual(self.eap_output_queue.qsize(), 0)
        self.assertEqual(self.radius_output_queue.qsize(), 1)
        self.assertIsInstance(self.radius_output_queue.get_nowait()[0],
                              IdentityMessage)

    @check_counters
    def test_md5_challenge_request(self):
        self.test_identity_response()

        eap_message = Md5ChallengeMessage(
            self.src_mac, 2, Eap.REQUEST,
            bytes.fromhex("74d3db089b727d9cc5774599e4a32a29"), b"host1user")
        self.sm.event(
            EventRadiusMessageReceived(eap_message,
                                       State.create(b"random state")))

        self.assertEqual(self.sm.state, self.sm.IDLE2)

        self.assertEqual(self.eap_output_queue.qsize(), 1)
        output = self.eap_output_queue.get_nowait()[0]
        self.assertIsInstance(output, Md5ChallengeMessage)

        self.assertEqual(self.radius_output_queue.qsize(), 0)
        return output

    @check_counters
    def test_md5_challenge_response(self):
        self.test_md5_challenge_request()

        message = Md5ChallengeMessage(
            self.src_mac, 2, Eap.RESPONSE,
            bytes.fromhex("3a535f0ee8c6b34fe714aa7dad9a0e15"), b"host1user")
        self.sm.event(EventMessageReceived(message, self.PORT_ID_MAC))

        self.assertEqual(self.sm.state, self.sm.AAA_IDLE)
        self.assertEqual(self.eap_output_queue.qsize(), 0)
        self.assertEqual(self.radius_output_queue.qsize(), 1)
        self.assertIsInstance(self.radius_output_queue.get_nowait()[0],
                              Md5ChallengeMessage)

    @check_counters(expected_auth_counter=1)
    def test_success2(self):
        self.test_md5_challenge_response()

        message = SuccessMessage(self.src_mac, 3)
        self.sm.event(EventRadiusMessageReceived(message, None))

        self.assertEqual(self.sm.state, self.sm.SUCCESS2)
        self.assertEqual(self.eap_output_queue.qsize(), 1)
        self.assertIsInstance(self.eap_output_queue.get_nowait()[0],
                              SuccessMessage)
        self.assertEqual(self.radius_output_queue.qsize(), 0)

    @check_counters(expected_auth_counter=2)
    def test_two_success2(self):
        self.test_success2()

        expiry_job = self.sm.session_timeout_job
        self.assertFalse(expiry_job.cancelled())

        self.test_success2()
        self.assertTrue(expiry_job.cancelled())

        expiry_job = self.sm.session_timeout_job
        self.assertFalse(expiry_job.cancelled())

    @check_counters(expected_auth_counter=2, expected_logoff_counter=1)
    def test_logoff2(self):
        """Test logoff from success2 state."""
        self.test_success2()

        # test the second logon expires the firsts session timeout event.
        expiry_job = self.sm.session_timeout_job
        self.assertFalse(expiry_job.cancelled())

        message = EapolLogoffMessage(self.src_mac)
        self.sm.event(EventRadiusMessageReceived(message, self.PORT_ID_MAC))

        self.assertTrue(expiry_job.cancelled())

        self.assertEqual(self.sm.state, self.sm.LOGOFF2)
        self.assertEqual(self.eap_output_queue.qsize(), 0)
        self.assertEqual(self.radius_output_queue.qsize(), 0)

        self.test_success2()

    @check_counters
    def test_logoff_from_idle2(self):
        """Test logoff from middle of authentication. should be ignored"""
        self.test_md5_challenge_request()

        message = EapolLogoffMessage(self.src_mac)
        self.sm.event(EventRadiusMessageReceived(message, self.PORT_ID_MAC))

        # should be in same state as when test_md5_challenge_request returned.

        self.assertEqual(self.sm.state, self.sm.IDLE2)
        self.assertEqual(self.eap_output_queue.qsize(), 0)
        self.assertEqual(self.radius_output_queue.qsize(), 0)

    @check_counters(expected_failure_counter=1)
    def test_failure2(self):
        self.test_md5_challenge_response()
        message = FailureMessage(self.src_mac, 3)
        self.sm.event(EventRadiusMessageReceived(message, None))

        self.assertEqual(self.sm.state, self.sm.FAILURE2)
        self.assertEqual(self.eap_output_queue.qsize(), 1)
        self.assertIsInstance(self.eap_output_queue.get_nowait()[0],
                              FailureMessage)
        self.assertEqual(self.radius_output_queue.qsize(), 0)

    @check_counters
    def test_discard2(self):
        request = self.test_md5_challenge_request()

        message = Md5ChallengeMessage(
            self.src_mac, request.message_id + 10, Eap.RESPONSE,
            bytes.fromhex("3a535f0ee8c6b34fe714aa7dad9a0e15"), b"host1user")
        self.sm.event(EventMessageReceived(message, self.PORT_ID_MAC))
        self.assertEqual(self.sm.state, self.sm.IDLE2)
        self.assertEqual(self.eap_output_queue.qsize(), 0)
        self.assertEqual(self.radius_output_queue.qsize(), 0)

    @check_counters
    def test_discard(self):
        message = self.test_eap_start()
        # Make a message that will be discarded (id here is not sequential)
        message = IdentityMessage(self.src_mac, message.message_id + 10,
                                  Eap.RESPONSE, "host1user")
        self.sm.event(EventMessageReceived(message, self.PORT_ID_MAC))
        self.assertEqual(self.sm.state, self.sm.IDLE)

        self.assertEqual(self.eap_output_queue.qsize(), 0)
        self.assertEqual(self.radius_output_queue.qsize(), 0)

    @check_counters
    def test_ttls_request(self):
        self.test_md5_challenge_request()
        self.assertEqual(self.eap_output_queue.qsize(), 0)
        self.assertEqual(self.radius_output_queue.qsize(), 0)

        message = LegacyNakMessage(self.src_mac, 2, Eap.RESPONSE, 21)
        self.sm.event(EventMessageReceived(message, self.PORT_ID_MAC))
        self.assertEqual(self.sm.state, self.sm.AAA_IDLE)
        self.assertEqual(self.eap_output_queue.qsize(), 0)
        self.assertEqual(self.radius_output_queue.qsize(), 1)

        message = TtlsMessage(self.src_mac, 3, Eap.REQUEST, 0x20, b'')
        self.sm.event(
            EventRadiusMessageReceived(message,
                                       State.create(b"more random state")))
        self.assertEqual(self.sm.state, self.sm.IDLE2)
        self.assertEqual(self.eap_output_queue.qsize(), 1)
        self.assertEqual(self.radius_output_queue.qsize(), 1)

        message = TtlsMessage(
            self.src_mac, 3, Eap.RESPONSE, 0x00,
            bytes.fromhex(
                '16030101280100012403032c36dbf8ee16b94b28efdb8c5603e07823f9b716557b5ef2624b026daea115760000aac030c02cc028c024c014c00a00a500a300a1009f006b006a0069006800390038003700360088008700860085c032c02ec02ac026c00fc005009d003d00350084c02fc02bc027c023c013c00900a400a200a0009e00670040003f003e0033003200310030009a0099009800970045004400430042c031c02dc029c025c00ec004009c003c002f00960041c011c007c00cc00200050004c012c008001600130010000dc00dc003000a00ff01000051000b000403000102000a001c001a00170019001c001b0018001a0016000e000d000b000c0009000a000d0020001e060106020603050105020503040104020403030103020303020102020203000f000101'
            ))
        self.sm.event(EventMessageReceived(message, self.PORT_ID_MAC))
        self.assertEqual(self.sm.state, self.sm.AAA_IDLE)
        self.assertEqual(self.eap_output_queue.qsize(), 1)
        self.assertEqual(self.radius_output_queue.qsize(), 2)

        message = TtlsMessage(
            self.src_mac, 4, Eap.REQUEST, 0x00,
            bytes.fromhex(
                '160303003e0200003a03036bf75d277e59b04228197af91c1c32c78beb8a708193ab3ac23a9aed30f5390c00c030000012ff01000100000b000403000102000f00010116030308d30b0008cf0008cc0003de308203da308202c2a003020102020101300d06092a864886f70d01010b0500308193310b3009060355040613024652310f300d06035504080c065261646975733112301006035504070c09536f6d65776865726531153013060355040a0c0c4578616d706c6520496e632e3120301e06092a864886f70d010901161161646d696e406578616d706c652e6f72673126302406035504030c1d4578616d706c6520436572746966696361746520417574686f72697479301e170d3138303630353033353134345a170d3138303830343033353134345a307c310b3009060355040613024652310f300d06035504080c0652616469757331153013060355040a0c0c4578616d706c6520496e632e3123302106035504030c1a4578616d706c65205365727665722043657274696669636174653120301e06092a864886f70d010901161161646d696e406578616d706c652e6f726730820122300d06092a864886f70d01010105000382010f003082010a0282010100cf5456d7e6142383101cf79275f6396e2c9b3f7cb2878d35e5ecc6f47ee11ef20bc8a8b3217a89351c55856e5cd5eed2d10037c9bcce89fbdf927e4cc4f069863acbac4accee7e80f2105ad80d837fa50a931c5b41d03c993f5e338cfd8e69e23818360053501c34c08132ec3d6e14df89ff29c5cec5c7a87d48c4afdcf9d3f8290050be5b903ba6a2a5ce2eb79c922cae70869618c75923059f9a8d62144e8ecdaf0a9f02886afa0e73e3d68037ea9fdca2bdd0f0785e05f5ac88031010c105575dbb09eb4f307547622120ee384ab454376de8e14e0afea02f1211801b6c932324ef6dba7abf3f48f8e3e84716c40b59041ec936cb273d684b22aa1c9d24e10203010001a34f304d30130603551d25040c300a06082b0601050507030130360603551d1f042f302d302ba029a0278625687474703a2f2f7777772e6578616d706c652e636f6d2f6578616d706c655f63612e63726c300d06092a864886f70d01010b0500038201010054fdcdabdc3a153dc167d6b210d1b324ecfac0e3b8d385704463a7f8ebf46e2e6952f249f4436ec66760868860e5ed50b519ec14628179472c312f507bc9349971d21f8f2b7d6b329b02fab448bd90fd4ce4dfbc78f23a8c4eed74d5589f4c3bd11b552535b8ab8a1a6ab9d1dfda21f247a93354702c12fdde1113cb8dd0e46e2a3a94547c9871df2a88943751d8276dc43f7f6aed921f43f6a33f9beba804c3d2b5781d754abe36ba58461798be8585b8b24b5c4a26d1e0905eb5bbae6e139b06728406bfe31baa27852252c7b4711c35ec9a41945488ef8c79a8a201351189e65baed66300528b45dfbcad233cd045336d5b35331ee76360b58583884eb0aa0004e8308204e4308203cca003020102020900de5bbe2e4d41d7fd300d06092a864886f70d01010b0500308193310b3009060355040613024652310f300d06035504080c065261646975733112301006035504070c09536f6d65776865726531153013060355040a0c0c4578616d706c6520496e632e3120301e06092a864886f70d010901161161646d696e406578616d706c652e6f72673126302406035504030c1d4578616d706c6520436572746966696361746520417574686f72697479301e170d3138303630353033353134345a170d3138303830343033353134345a308193310b3009060355040613024652310f300d06035504080c065261646975733112301006035504070c09536f6d65776865726531153013060355040a0c0c4578616d706c6520496e632e3120301e06092a864886f70d010901161161646d696e406578616d706c652e6f72673126302406035504030c1d4578616d706c6520436572746966696361746520417574686f7269747930820122300d06092a864886f70d01010105000382010f003082010a02820101009b2190c32456e96ad8d08c6577839dcaf819f98a104bad079330714b7c12c765861c9a2e74eb0aec87a64eb58caa781f543eb2971db6b9e3b662952213aaf806fbb38c7a7fa46135c14a2e0e0a158162c2414e3c3f835bf4b80007c03df51746a04715dada1fb9fb155d479da9c34e40f192c65f64b16d4c742e66cbdc748ce0763cd45b7a88ff7d99d66449676a07116651394107c2ab5d654ad9a0315b78a2342a26790629fbe1e19a734e5e2eab933f3cef3e81c4413443988c8ccd9bc35b7ba3c6ec5571f4089ab07e401b2f21131316d4f8333782acc76d661f8440287c8e0a122200d9067b6b5d2af4cd5ab23f69cd689652c813fdd04f4f83544b4d450203010001a382013730820133301d0603551d0e0416041473fd7fcd4adc85cbfd85734c722335e7472b8df03081c80603551d230481c03081bd801473fd7fcd4adc85cbfd85734c722335e7472b8df0a18199a48196308193310b3009060355040613024652310f300d06035504080c065261646975733112301006035504070c09536f6d65776865726531153013060355040a0c0c4578616d706c6520496e632e3120301e06092a864886f70d010901161161646d696e406578616d706c652e6f72673126302406035504030c1d4578616d706c6520436572746966696361746520417574686f72697479820900de5bbe2e4d41d7fd300f0603551d130101ff040530030101ff30360603551d1f042f302d302ba029a0278625687474703a2f2f7777772e6578616d706c652e6f72672f6578616d706c655f63612e63726c300d06092a864886f70d01010b05000382010100139e9c2b1e9bf30c6567759ffb57af9f031a59b6a8adb1702a55de2e51f2286715ef1399ebdc593d38db3ad4794c3e78037d3de5612cba33cefc5b830c3a2118bfc0572d201c07105b7c0ef5bb64225d959afef6a4527a88d1e5fd552fd16775a5c90802d11ad793da157441f7a181f85a2908ebcb87a86960c6d3ae631019bc73f850bc5be494a97084ccaea1cc13c44a4fdf0ef123c067b688e47a4d223c15fd56798051ff4912c721f15c96061ef683b1ade02b5449b06184f59d4218f2287d35cfa0a3a4f65e40c8750d0c70dc00d65a8981e0a2cf6961b1355c10d399ce583a426e211b0feef37da67a57bbbc81d912d5379668cfdc3666bacf5e9d9c7d160303014d0c0001490300174104b275c284c5c067b9c3104305ba6704b4b0e083f0e285d9b205a8d7307e503907478f314679d084a0f1ccbc3ceaa6b6d56c588654d223fd16514bba463c5f8d7006010100bca760ef9aab5f1cf9239bab7d0bbf585e12f9c6440b9dd36affc87ff8f334b0dbea94686edbcff9143bd40a5136b065d5599742665fa27d5ec5e86898b7c8cc2c375d190646c644df7911f41a12a7219f667527cfc4ba99b684fb763a01f4dc361a891906e3ade0c6e787c096f868726a5aafafb76ce71ce896b50015c9db89e9c3d13c90e90b5d82a1327941404298c1e358cbc7bbbf8e4fe2e1ecafbcbddfbe0b1a7d3f0769306f16f3ed4972b14b8af0f51761053754ec73a1a41b294fe0d00a9281e3d9c0175651d2bbaf28df32a25bfbae85983a3935891f0a955b636b3540cde3aba4ec20d62988a81a608b450e87b3eefcb66f50cf3104a4b367122d16030300040e000000'
            ))
        self.sm.event(
            EventRadiusMessageReceived(
                message, State.create(b"some more random state")))
        self.assertEqual(self.sm.state, self.sm.IDLE2)
        self.assertEqual(self.eap_output_queue.qsize(), 2)
        self.assertEqual(self.radius_output_queue.qsize(), 2)

    @check_counters(expected_auth_counter=1, expected_logoff_counter=1)
    def test_deauth_timer(self):
        self.sm.DEFAULT_SESSION_TIMEOUT = 2
        self.test_success2()

        self.timer_scheduler.run_jobs()
        self.assertEqual(self.sm.state, self.sm.LOGOFF2)

    @check_counters(expected_auth_counter=2, expected_logoff_counter=0)
    def test_port_flap(self):
        """Test logoff from success2 state."""
        self.test_success2()
        # Put port down
        self.sm.event(EventPortStatusChange(False))
        self.sm.event(EventPortStatusChange(True))

        self.assertEqual(self.sm.state, self.sm.NO_STATE)
        self.assertFalse(self.sm.aaa_success)
        self.assertFalse(self.sm.eap_success)

        self.assertEqual(self.eap_output_queue.qsize(), 0)
        self.assertEqual(self.radius_output_queue.qsize(), 0)

        self.test_success2()
Пример #5
0
class ChewieTestCase(unittest.TestCase):
    """Main chewie.py test class"""

    no_radius_replies = []

    header = "0000000000010242ac17006f888e"
    sup_replies_success = [
        bytes.fromhex(header + "01000009027400090175736572"),
        bytes.fromhex(header +
                      "010000160275001604103abcadc86714b2d75d09dd7ff53edf6b")
    ]

    radius_replies_success = [
        bytes.fromhex(
            "0b000050066300262c8ee8a33f43ad4e837e63c54f180175001604101a16a3baa37a0238f33384f6c"
            "11067425012a3bf83bea0eeb69645088527dc491eed18126aa866456add628e3a55a4737872cad6"
        ),
        bytes.fromhex(
            "02010032ec22830bb2fbde37f635e91690410b334"
            "f060375000450129a08d246ec3da2f371ec4ff16eed9310010675736572")
    ]

    radius_replies_success_mab = [
        bytes.fromhex(
            "02000034187d6f5dc540a24efa738d2ba242ac5c50128f4b859e01a85b919b848421d0d369"
            "ad010e303234326163313730303666")
    ]

    radius_replies_failure_mab = [
        bytes.fromhex(
            "030000340b0a0f4ec71ebd0573180eb45161c2b7010e303234326163313730303666"
        )
    ]

    sup_replies_logoff = [
        bytes.fromhex(header + "01000009027400090175736572"),
        bytes.fromhex(header +
                      "010000160275001604103abcadc86714b2d75d09dd7ff53edf6b"),
        bytes.fromhex("0000000000010242ac17006f888e01020000")
    ]

    # packet id (0x84 is incorrect)
    sup_replies_failure_message_id = [
        bytes.fromhex(header + "01000009028400090175736572"),
        bytes.fromhex(header + "01000009029400090175736572"),
        bytes.fromhex(header + "01000009026400090175736572"),
        bytes.fromhex(header + "01000009025400090175736572")
    ]

    # the first response has correct code, second is wrong and will be dropped by radius
    sup_replies_failure2_response_code = [
        bytes.fromhex(header + "01000009027400090175736572"),
        bytes.fromhex(header + "01000009037400090175736572")
    ]

    def setUp(self):
        logger = logging.getLogger()
        logger.level = logging.DEBUG
        self.log_file = tempfile.NamedTemporaryFile()

        logger.addHandler(logging.FileHandler(self.log_file.name))
        logger.addHandler(logging.StreamHandler(sys.stdout))

        self.chewie = Chewie('lo', logger, auth_handler, failure_handler,
                             logoff_handler, '127.0.0.1', 1812, 'SECRET',
                             '44:44:44:44:44:44')
        self.fake_scheduler = FakeTimerScheduler()
        self.chewie.timer_scheduler = self.fake_scheduler

        global FROM_SUPPLICANT  # pylint: disable=global-statement
        global TO_SUPPLICANT  # pylint: disable=global-statement
        global FROM_RADIUS  # pylint: disable=global-statement
        global TO_RADIUS  # pylint: disable=global-statement
        global FROM_SUPPLICANT_ACTIVITY  # pylint: disable=global-statement

        FROM_SUPPLICANT = Queue()
        FROM_SUPPLICANT_ACTIVITY = Queue()
        TO_SUPPLICANT = Queue()
        FROM_RADIUS = Queue()
        TO_RADIUS = Queue()

    def tearDown(self):
        self.chewie.shutdown()

    def test_get_state_machine(self):
        """Tests Chewie.get_state_machine()"""
        self.assertEqual(len(self.chewie.state_machines), 0)
        # creates the state_machine if it doesn't exist
        state_machine = self.chewie.get_state_machine(
            '12:34:56:78:9a:bc',
            # pylint: disable=invalid-name
            '00:00:00:00:00:01')
        self.assertEqual(len(self.chewie.state_machines), 1)

        self.assertIs(
            state_machine,
            self.chewie.get_state_machine('12:34:56:78:9a:bc',
                                          '00:00:00:00:00:01'))

        self.assertIsNot(
            state_machine,
            self.chewie.get_state_machine('12:34:56:78:9a:bc',
                                          '00:00:00:00:00:02'))
        self.assertIsNot(
            state_machine,
            self.chewie.get_state_machine('ab:cd:ef:12:34:56',
                                          '00:00:00:00:00:01'))

        # 2 ports
        self.assertEqual(len(self.chewie.state_machines), 2)
        # port 1 has 2 macs
        self.assertEqual(len(self.chewie.state_machines['00:00:00:00:00:01']),
                         2)
        # port 2 has 1 mac
        self.assertEqual(len(self.chewie.state_machines['00:00:00:00:00:02']),
                         1)

    # TODO Stop Test from touching internal get_state_machine_from_radius_packet
    def test_get_state_machine_by_packet_id(self):
        """Tests Chewie.get_state_machine_by_packet_id()"""
        self.chewie.radius_lifecycle.packet_id_to_mac[56] = {
            'src_mac': '12:34:56:78:9a:bc',
            'port_id': '00:00:00:00:00:01'
        }
        state_machine = self.chewie.get_state_machine(
            '12:34:56:78:9a:bc',
            # pylint: disable=invalid-name
            '00:00:00:00:00:01')

        self.assertIs(self.chewie._get_state_machine_from_radius_packet_id(56),
                      state_machine)
        with self.assertRaises(KeyError):
            self.chewie._get_state_machine_from_radius_packet_id(20)

    @patch_things
    @setup_generators(sup_replies_success, radius_replies_success)
    def test_success_dot1x(self):
        """Test success api"""
        FROM_SUPPLICANT.put_nowait(
            bytes.fromhex("0000000000010242ac17006f888e01010000"))

        pool = eventlet.GreenPool()
        pool.spawn(self.chewie.run)

        eventlet.sleep(1)

        self.assertEqual(
            self.chewie.get_state_machine('02:42:ac:17:00:6f',
                                          '00:00:00:00:00:01').state,
            FullEAPStateMachine.SUCCESS2)

    @patch_things
    @setup_generators(sup_replies_success, radius_replies_success)
    def test_chewie_identity_response_dot1x(self):
        """test port status api and that identity request is sent after port up"""

        global TO_SUPPLICANT
        pool = eventlet.GreenPool()
        pool.spawn(self.chewie.run)
        eventlet.sleep(1)
        self.chewie.port_down("00:00:00:00:00:01")

        self.chewie.port_up("00:00:00:00:00:01")

        while not self.fake_scheduler.jobs:
            eventlet.sleep(SHORT_SLEEP)
        self.fake_scheduler.run_jobs(num_jobs=1)

        # check preemptive sent directly after port up
        out_packet = TO_SUPPLICANT.get()
        self.assertEqual(
            out_packet,
            bytes.fromhex('0180C2000003000000000001888e010000050167000501'))

        # Send a response to the request
        FROM_SUPPLICANT.put_nowait(
            bytes.fromhex("0000000000010242ac17006f888e010000050167000501"))
        eventlet.sleep(2)

        self.assertEqual(
            self.chewie.get_state_machine('02:42:ac:17:00:6f',
                                          '00:00:00:00:00:01').state,
            FullEAPStateMachine.AAA_IDLE)

    @patch_things
    def test_port_status_changes(self):
        """test port status api and that identity request is sent after port up"""

        global TO_SUPPLICANT
        pool = eventlet.GreenPool()
        pool.spawn(self.chewie.run)
        eventlet.sleep(1)
        self.chewie.port_down("00:00:00:00:00:01")

        self.chewie.port_up("00:00:00:00:00:01")

        while not self.fake_scheduler.jobs:
            eventlet.sleep(SHORT_SLEEP)
        self.fake_scheduler.run_jobs(num_jobs=1)
        # check preemptive sent directly after port up
        out_packet = TO_SUPPLICANT.get()
        self.assertEqual(
            out_packet,
            bytes.fromhex('0180C2000003000000000001888e010000050167000501'))

        # check there is a new job in the queue for sending the next id request.
        # This will keep adding jobs forever.
        self.assertEqual(len(self.fake_scheduler.jobs), 1)
        self.assertEqual(self.fake_scheduler.jobs[0].function.__name__,
                         ManagedPort.send_preemptive_identity_request.__name__)

    @patch_things
    def test_delete_state_on_port_down(self):
        """test port status api and that identity request is sent after port up"""
        self.test_chewie_identity_response_dot1x()
        self.chewie.port_down("00:00:00:00:00:01")
        self.assertIsNone(self.chewie.state_machines.get("00:00:00:00:00:01"),
                          "Not Removing state machines on port_down")

    @patch_things
    @setup_generators(sup_replies_logoff, radius_replies_success)
    def test_logoff_dot1x(self):
        """Test logoff"""
        self.chewie.get_state_machine(
            MacAddress.from_string('02:42:ac:17:00:6f'),
            MacAddress.from_string('00:00:00:00:00:01'))
        FROM_SUPPLICANT.put_nowait(
            bytes.fromhex("0000000000010242ac17006f888e01010000"))

        pool = eventlet.GreenPool()
        pool.spawn(self.chewie.run)

        eventlet.sleep(SHORT_SLEEP)

        self.assertEqual(
            self.chewie.get_state_machine('02:42:ac:17:00:6f',
                                          '00:00:00:00:00:01').state,
            FullEAPStateMachine.LOGOFF2)

    @patch_things
    @setup_generators(sup_replies_failure_message_id, no_radius_replies)
    def test_failure_message_id_dot1x(self):
        """Test incorrect message id results in timeout_failure"""
        # TODO not convinced this is transitioning through the correct states.
        # (should be discarding all packets)
        # But end result is correct (both packets sent/received, and end state)
        # self.chewie.get_state_machine(MacAddress.from_string('02:42:ac:17:00:6f'),
        self.chewie.get_state_machine(
            MacAddress.from_string('02:42:ac:17:00:6f'),
            MacAddress.from_string('00:00:00:00:00:01')).DEFAULT_TIMEOUT = 0.5

        FROM_SUPPLICANT.put_nowait(
            bytes.fromhex("0000000000010242ac17006f888e01010000"))

        pool = eventlet.GreenPool()
        pool.spawn(self.chewie.run)

        while not self.fake_scheduler.jobs:
            eventlet.sleep(SHORT_SLEEP)
        self.fake_scheduler.run_jobs()

        self.assertEqual(
            self.chewie.get_state_machine('02:42:ac:17:00:6f',
                                          '00:00:00:00:00:01').state,
            FullEAPStateMachine.TIMEOUT_FAILURE)

    @patch_things
    @setup_generators(sup_replies_failure2_response_code, no_radius_replies)
    def test_failure2_resp_code_dot1x(self):
        """Test incorrect eap.code results in timeout_failure2. RADIUS Server drops it.
        It is up to the supplicant to send another request - this supplicant doesnt"""
        self.chewie.get_state_machine(
            MacAddress.from_string('02:42:ac:17:00:6f'),
            MacAddress.from_string('00:00:00:00:00:01')).DEFAULT_TIMEOUT = 0.5

        FROM_SUPPLICANT.put_nowait(
            bytes.fromhex("0000000000010242ac17006f888e01010000"))

        pool = eventlet.GreenPool()
        pool.spawn(self.chewie.run)

        while not self.fake_scheduler.jobs:
            eventlet.sleep(SHORT_SLEEP)
        self.fake_scheduler.run_jobs()

        self.assertEqual(
            self.chewie.get_state_machine('02:42:ac:17:00:6f',
                                          '00:00:00:00:00:01').state,
            FullEAPStateMachine.TIMEOUT_FAILURE2)

    @patch_things
    def test_mab_receive(self):
        """Test ETH Receive Ability of MAB Functionality"""
        mab_sm = self.chewie.get_state_machine(
            MacAddress.from_string('02:42:ac:17:00:6f'),
            MacAddress.from_string('00:00:00:00:00:01'), -2)
        mab_sm.DEFAULT_TIMEOUT = 0.5

        FROM_SUPPLICANT_ACTIVITY.put_nowait(
            bytes.fromhex(
                "0000000000010242ac17006f08004500001c0001000040117cce7f0000017f0000010044004300080155"
            ))

        pool = eventlet.GreenPool()
        pool.spawn(self.chewie.run)

        eventlet.sleep(SHORT_SLEEP)

        self.assertEqual(
            self.chewie.get_state_machine('02:42:ac:17:00:6f',
                                          '00:00:00:00:00:01').state,
            MacAuthenticationBypassStateMachine.AAA_IDLE)

    @patch_things
    @setup_generators(None, radius_replies_success_mab)
    def test_mab_success_auth(self):
        """Test Successful MAB Attempt"""
        mab_sm = self.chewie.get_state_machine(
            MacAddress.from_string('02:42:ac:17:00:6f'),
            MacAddress.from_string('00:00:00:00:00:01'), -2)
        mab_sm.DEFAULT_TIMEOUT = 0.5

        FROM_SUPPLICANT_ACTIVITY.put_nowait(
            bytes.fromhex(
                "0000000000010242ac17006f08004500001c0001000040117cce7f0000017f0000010044004300080155"
            ))

        pool = eventlet.GreenPool()
        pool.spawn(self.chewie.run)

        eventlet.sleep(SHORT_SLEEP)

        self.assertEqual(
            self.chewie.get_state_machine('02:42:ac:17:00:6f',
                                          '00:00:00:00:00:01').state,
            MacAuthenticationBypassStateMachine.AAA_SUCCESS)

    @patch_things
    @setup_generators(None, radius_replies_failure_mab)
    def test_mab_failure_auth(self):
        """Test unsuccessful MAB Attempt"""
        mab_sm = self.chewie.get_state_machine(
            MacAddress.from_string('02:42:ac:17:00:6f'),
            MacAddress.from_string('00:00:00:00:00:01'), -2)
        mab_sm.DEFAULT_TIMEOUT = 0.5

        FROM_SUPPLICANT_ACTIVITY.put_nowait(
            bytes.fromhex(
                "0000000000010242ac17006f08004500001c0001000040117cce7f0000017f0000010044004300080155"
            ))

        pool = eventlet.GreenPool()
        pool.spawn(self.chewie.run)

        eventlet.sleep(SHORT_SLEEP)

        self.assertEqual(
            self.chewie.get_state_machine('02:42:ac:17:00:6f',
                                          '00:00:00:00:00:01').state,
            MacAuthenticationBypassStateMachine.AAA_FAILURE)

    @patch_things
    @setup_generators(sup_replies_success, radius_replies_success)
    def test_smoke_test_clients(self):
        """Test success api"""
        FROM_SUPPLICANT.put_nowait(
            bytes.fromhex("0000000000010242ac17006f888e01010000"))

        pool = eventlet.GreenPool()
        pool.spawn(self.chewie.run)

        eventlet.sleep(1)
        self.assertIsNotNone(self.chewie.clients)
        self.assertEqual(len(self.chewie.clients), 1)
Пример #6
0
class ChewieTestCase(unittest.TestCase):
    """Main chewie.py test class"""

    no_radius_replies = []

    header = "0000000000010242ac17006f888e"
    sup_replies_success = [
        bytes.fromhex(header + "01000009027400090175736572"),
        bytes.fromhex(header +
                      "010000160275001604103abcadc86714b2d75d09dd7ff53edf6b")
    ]

    radius_replies_success = [
        bytes.fromhex(
            "0b000050066300262c8ee8a33f43ad4e837e63c54f180175001604101a16a3baa37a0238f33384f6c11067425012a3bf83bea0eeb69645088527dc491eed18126aa866456add628e3a55a4737872cad6"
        ),
        bytes.fromhex(
            "02010032ec22830bb2fbde37f635e91690410b334f060375000450129a08d246ec3da2f371ec4ff16eed9310010675736572"
        )
    ]

    sup_replies_logoff = [
        bytes.fromhex(header + "01000009027400090175736572"),
        bytes.fromhex(header +
                      "010000160275001604103abcadc86714b2d75d09dd7ff53edf6b"),
        bytes.fromhex("0000000000010242ac17006f888e01020000")
    ]

    # packet id (0x84 is incorrect)
    sup_replies_failure_message_id = [
        bytes.fromhex(header + "01000009028400090175736572"),
        bytes.fromhex(header + "01000009029400090175736572"),
        bytes.fromhex(header + "01000009026400090175736572"),
        bytes.fromhex(header + "01000009025400090175736572")
    ]

    # the first response has correct code, second is wrong and will be dropped by radius
    sup_replies_failure2_response_code = [
        bytes.fromhex(header + "01000009027400090175736572"),
        bytes.fromhex(header + "01000009037400090175736572")
    ]

    def setUp(self):
        logger = logging.getLogger()
        logger.level = logging.DEBUG
        self.log_file = tempfile.NamedTemporaryFile()

        logger.addHandler(logging.FileHandler(self.log_file.name))
        logger.addHandler(logging.StreamHandler(sys.stdout))

        self.chewie = Chewie('lo', logger, auth_handler, failure_handler,
                             logoff_handler, '127.0.0.1', 1812, 'SECRET',
                             '44:44:44:44:44:44')
        self.fake_scheduler = FakeTimerScheduler()
        self.chewie.timer_scheduler = self.fake_scheduler

        global FROM_SUPPLICANT  # pylint: disable=global-statement
        global TO_SUPPLICANT  # pylint: disable=global-statement
        global FROM_RADIUS  # pylint: disable=global-statement
        global TO_RADIUS  # pylint: disable=global-statement

        FROM_SUPPLICANT = Queue()
        TO_SUPPLICANT = Queue()
        FROM_RADIUS = Queue()
        TO_RADIUS = Queue()

    def tearDown(self):
        self.chewie.shutdown()

    def test_get_state_machine(self):
        """Tests Chewie.get_state_machine()"""
        self.assertEqual(len(self.chewie.state_machines), 0)
        # creates the state_machine if it doesn't exist
        state_machine = self.chewie.get_state_machine(
            '12:34:56:78:9a:bc',  # pylint: disable=invalid-name
            '00:00:00:00:00:01')

        self.assertEqual(len(self.chewie.state_machines), 1)

        self.assertIs(
            state_machine,
            self.chewie.get_state_machine('12:34:56:78:9a:bc',
                                          '00:00:00:00:00:01'))

        self.assertIsNot(
            state_machine,
            self.chewie.get_state_machine('12:34:56:78:9a:bc',
                                          '00:00:00:00:00:02'))
        self.assertIsNot(
            state_machine,
            self.chewie.get_state_machine('ab:cd:ef:12:34:56',
                                          '00:00:00:00:00:01'))

        # 2 ports
        self.assertEqual(len(self.chewie.state_machines), 2)
        # port 1 has 2 macs
        self.assertEqual(len(self.chewie.state_machines['00:00:00:00:00:01']),
                         2)
        # port 2 has 1 mac
        self.assertEqual(len(self.chewie.state_machines['00:00:00:00:00:02']),
                         1)

    def test_get_state_machine_by_packet_id(self):
        """Tests Chewie.get_state_machine_by_packet_id()"""
        self.chewie.radius_lifecycle.packet_id_to_mac[56] = {
            'src_mac': '12:34:56:78:9a:bc',
            'port_id': '00:00:00:00:00:01'
        }
        state_machine = self.chewie.get_state_machine(
            '12:34:56:78:9a:bc',  # pylint: disable=invalid-name
            '00:00:00:00:00:01')

        self.assertIs(self.chewie.get_state_machine_from_radius_packet_id(56),
                      state_machine)
        with self.assertRaises(KeyError):
            self.chewie.get_state_machine_from_radius_packet_id(20)

    @patch_things
    @setup_generators(sup_replies_success, radius_replies_success)
    def test_success_dot1x(self):
        """Test success api"""
        FROM_SUPPLICANT.put_nowait(
            bytes.fromhex("0000000000010242ac17006f888e01010000"))

        pool = eventlet.GreenPool()
        pool.spawn(self.chewie.run)

        eventlet.sleep(1)

        self.assertEqual(
            self.chewie.get_state_machine('02:42:ac:17:00:6f',
                                          '00:00:00:00:00:01').state,
            FullEAPStateMachine.SUCCESS2)

    def test_port_status_changes(self):
        """test port status api"""
        # TODO what can actually be checked here?
        # the state machine tests already check the statemachine
        # could check that the preemptive identity request packet is sent. (once implemented)
        # for now just check api works under python version.

        self.chewie.port_down("00:00:00:00:00:01")

        self.chewie.port_up("00:00:00:00:00:01")

        self.chewie.port_down("00:00:00:00:00:01")

    @patch_things
    @setup_generators(sup_replies_logoff, radius_replies_success)
    def test_logoff_dot1x(self):
        """Test logoff"""
        self.chewie.get_state_machine(
            MacAddress.from_string('02:42:ac:17:00:6f'),
            MacAddress.from_string('00:00:00:00:00:01'))
        FROM_SUPPLICANT.put_nowait(
            bytes.fromhex("0000000000010242ac17006f888e01010000"))

        pool = eventlet.GreenPool()
        pool.spawn(self.chewie.run)

        eventlet.sleep(0.1)

        self.assertEqual(
            self.chewie.get_state_machine('02:42:ac:17:00:6f',
                                          '00:00:00:00:00:01').state,
            FullEAPStateMachine.LOGOFF2)

    @patch_things
    @setup_generators(sup_replies_failure_message_id, no_radius_replies)
    def test_failure_message_id_dot1x(self):
        """Test incorrect message id results in timeout_failure"""
        # TODO not convinced this is transitioning through the correct states.
        # (should be discarding all packets)
        # But end result is correct (both packets sent/received, and end state)self.chewie.get_state_machine(MacAddress.from_string('02:42:ac:17:00:6f'),
        self.chewie.get_state_machine(
            MacAddress.from_string('02:42:ac:17:00:6f'),
            MacAddress.from_string('00:00:00:00:00:01')).DEFAULT_TIMEOUT = 0.5

        FROM_SUPPLICANT.put_nowait(
            bytes.fromhex("0000000000010242ac17006f888e01010000"))

        pool = eventlet.GreenPool()
        pool.spawn(self.chewie.run)

        while not self.fake_scheduler.jobs:
            eventlet.sleep(0.1)
        self.fake_scheduler.run_jobs()

        self.assertEqual(
            self.chewie.get_state_machine('02:42:ac:17:00:6f',
                                          '00:00:00:00:00:01').state,
            FullEAPStateMachine.TIMEOUT_FAILURE)

    @patch_things
    @setup_generators(sup_replies_failure2_response_code, no_radius_replies)
    def test_failure2_resp_code_dot1x(self):
        """Test incorrect eap.code results in timeout_failure2. RADIUS Server drops it.
        It is up to the supplicant to send another request - this supplicant doesnt"""
        self.chewie.get_state_machine(
            MacAddress.from_string('02:42:ac:17:00:6f'),
            MacAddress.from_string('00:00:00:00:00:01')).DEFAULT_TIMEOUT = 0.5

        FROM_SUPPLICANT.put_nowait(
            bytes.fromhex("0000000000010242ac17006f888e01010000"))

        pool = eventlet.GreenPool()
        pool.spawn(self.chewie.run)

        while not self.fake_scheduler.jobs:
            eventlet.sleep(0.1)
        self.fake_scheduler.run_jobs()

        self.assertEqual(
            self.chewie.get_state_machine('02:42:ac:17:00:6f',
                                          '00:00:00:00:00:01').state,
            FullEAPStateMachine.TIMEOUT_FAILURE2)