def test_disassociate_blocked_on_deny(self, mock_fmt_mac, mock_utils):
        # test with and without return value of the sudo_cmd call
        for message in ['message', None]:
            mock_fmt_mac.reset_mock()
            mock_utils.reset_mock()
            self._prepare_on_host_mocks(mock_fmt_mac,
                                        mock_utils,
                                        expected_msg=message)
            mock_utils.disassociate_user.return_value = 'OK'
            testuser = UserIdentifier('user', 'aabb')
            testuser.user_data = UserData()
            testuser.user_data.join_state = UserData.JOIN_STATE_BLOCKED

            handler = FirewallAuthHandler()
            result = handler.on_host_deny(testuser)

            # ensure the script also gets called when UserData is given
            self._assert_on_host_call(mock_fmt_mac,
                                      mock_utils,
                                      '/etc/radguestauth/fw_user_drop.sh',
                                      result,
                                      expected_msg=message)
            # blocked user needs to be disassociated as well
            mock_utils.disassociate_user.assert_called_once_with('aabb')
            self.assertIn('OK', result)
    def test_str_representation(self):
        # incrementally adds attributes and checks if they appear in str(item).
        # The str representation is important for several chat commands.
        identifier = UserIdentifier('foo', 'bar')
        # str needs to work without password and data
        self.assertIn('foo', str(identifier))
        self.assertIn('bar', str(identifier))

        identifier.password = '******'
        self.assertIn('passw0rd!', str(identifier))

        data = UserData()
        state_str = data.state_string()
        self.assertIn(state_str, str(data))

        # this is 1970-01-01 00:01:40
        data.valid_until = 100
        data.num_joins = 42
        data.max_num_joins = 1234
        # keep some freedoms on the actual output
        self.assertIn('1970', str(data))
        self.assertIn('00:01:40', str(data))
        self.assertIn('42', str(data))
        self.assertIn('1234', str(data))

        data_str = str(data)
        identifier.user_data = data
        self.assertIn(data_str, str(identifier))
    def test_allow_on_may_join(self, mock_usermgr, mock_chat, mock_loader):
        # prepare test data
        mock_usermgr_obj = Mock()
        test_user = UserIdentifier('user', 'aabb')
        test_user.password = '******'
        mock_usermgr_obj.find.return_value = test_user
        mock_usermgr_obj.may_join.return_value = UserData.JOIN_STATE_ALLOWED
        mock_usermgr.return_value = mock_usermgr_obj
        mock_auth = self._get_auth_handler_mock(mock_loader)
        gacore = self._init_and_start()

        expected_result = (auth.ALLOW, {
            'control:Cleartext-Password': '******'
        })
        mock_auth.handle_user_state.return_value = expected_result
        result = gacore.authorize({
            'User-Name': 'user',
            'Calling-Station-Id': 'aabb'
        })

        self._assert_called_once_with_user_id(mock_usermgr_obj.may_join,
                                              'user', 'aabb')
        self._assert_called_once_with_user_id(mock_auth.handle_user_state,
                                              'user', 'aabb')
        # User identifier handled above, session ID not given
        mock_auth.handle_user_state.assert_called_once_with(
            ANY, UserData.JOIN_STATE_ALLOWED, ANY)
        mock_usermgr_obj.find.assert_called_once_with('user')
        self.assertEqual(expected_result, result)
    def test_drop_expired_users(self, mock_usermgr, mock_chat, mock_loader):
        testuser1 = UserIdentifier('user', 'aabb')
        testuser2 = UserIdentifier('user2', 'aabb2')
        testuser3 = UserIdentifier('user3', 'aabb3')
        mock_usermgr_obj = Mock()
        mock_usermgr_obj.get_expired_users.return_value = [
            testuser1, testuser2
        ]
        mock_usermgr_obj.is_request_pending.return_value = True
        mock_usermgr_obj.get_request.return_value = testuser3
        mock_usermgr.return_value = mock_usermgr_obj
        mock_auth = self._get_auth_handler_mock(mock_loader)
        gacore = self._init_and_start()

        gacore.drop_expired_users()

        mock_usermgr_obj.remove.assert_has_calls(
            [call(testuser1), call(testuser2)], any_order=True)
        mock_usermgr_obj.finish_request.assert_called_once()

        mock_auth.on_host_deny.assert_has_calls(
            [call(testuser1),
             call(testuser2),
             call(testuser3)],
            any_order=True)

        # no more calls should have been made
        self.assertEqual(mock_usermgr_obj.remove.call_count, 2)
        self.assertEqual(mock_auth.on_host_deny.call_count, 3)
    def test_post_auth_timeout_no_valid_until(self, mock_usermgr, mock_chat,
                                              mock_loader):
        testuser = UserIdentifier('user', 'aabb')
        testuser.user_data = UserData()
        testuser.user_data.valid_until = None
        testuser.user_data.max_num_joins = 10
        mock_usermgr_obj = Mock()
        mock_usermgr_obj.find.return_value = testuser
        mock_usermgr.return_value = mock_usermgr_obj

        mock_auth = self._get_auth_handler_mock(mock_loader)
        expected_result = {'control:Test': 'val'}
        mock_auth.on_post_auth.return_value = expected_result.copy()
        gacore = self._init_and_start()

        result = gacore.post_auth({
            'User-Name': 'user',
            'Calling-Station-Id': 'aabb'
        })

        mock_auth.on_post_auth.assert_called_once_with(
            UserIdentifier('user', 'aabb'), ANY)
        mock_usermgr_obj.find.assert_called_once_with('user')
        # no timeout should be added without valid_until.
        self.assertEqual(expected_result, result)
        self.assertIsNone(result.get('reply:Session-Timeout'))
예제 #6
0
    def test_list_output(self):
        self.mock_um.list_users.return_value = [
            UserIdentifier('someone', '123'),
            UserIdentifier('someoneElse', 'deviceId1'),
        ]

        result = self._exec_list()
        self.assertFalse('[blocked]' in result)
    def test_may_join_other_name_request(self):
        # also reject if a device ID is used by the current request user
        mgr, testuser = self._get_mgr_with_one_user()
        mgr.add_request(UserIdentifier('testuser2', 'device'))

        result = mgr.may_join(UserIdentifier('other', 'device'))

        self.assert_state_blocked(result)
    def test_post_auth_waiting_add_timeout(self, mock_utils):
        handler = FirewallAuthHandler()
        handler.handle_user_state(UserIdentifier('user', 'aabb'),
                                  UserData.JOIN_STATE_WAITING, 'session')

        result = handler.on_post_auth(UserIdentifier('user', 'aabb'),
                                      'session')

        self.assertIsInstance(result, dict)
        self.assertIsNotNone(result.get('reply:Session-Timeout'))
    def _prepare_timeout_user(self, mock_usermgr):
        testuser = UserIdentifier('user', 'aabb')
        testuser.user_data = UserData()
        test_validity = 600
        testuser.user_data.valid_until = time.time() + test_validity
        mock_usermgr_obj = Mock()
        mock_usermgr_obj.find.return_value = testuser
        mock_usermgr.return_value = mock_usermgr_obj

        return mock_usermgr_obj, test_validity
    def test_post_auth_allowed_no_timeout(self, mock_utils):
        # no timeout should be set for allowed users
        handler = FirewallAuthHandler()
        handler.handle_user_state(UserIdentifier('user', 'aabb'),
                                  UserData.JOIN_STATE_ALLOWED, 'session')

        result = handler.on_post_auth(UserIdentifier('user', 'aabb'),
                                      'session')

        self.assertIsNone(result)
    def test_may_join_other_name_different_id_format(self):
        # also reject when the device IDs are formatted differently
        data = UserData()
        data.max_num_joins = 1
        data.valid_until = time.time() + 10000
        user = UserIdentifier('foo', 'AB-C0')
        mgr = self._get_mgr_with(user, data)

        result = mgr.may_join(UserIdentifier('other', 'ab:c0'))

        self.assert_state_blocked(result)
    def test_may_join_pending_request(self):
        mgr, testuser = self._get_mgr_with_one_user()
        mgr.add_request(UserIdentifier('other', 'device'))

        # request user should be in waiting state, but others
        # still in new state.
        result = mgr.may_join(UserIdentifier('other', 'device'))
        result_new_user = mgr.may_join(UserIdentifier('other2', 'device2'))

        self.assert_state_waiting(result)
        self.assert_state_new(result_new_user)
    def test_mac_formatting(self):
        test_mac = 'aa:bb:cc:dd:e0:12'
        items_to_check = [
            test_mac, 'AA:BB:CC:DD:E0:12', 'AA-BB-CC-DD-E0-12',
            'aa-bb-cc-dd-e0-12', 'aa-bb-cc:Dd-e0-12'
        ]

        for addr in items_to_check:
            formatted_obj = UserIdentifier('a', addr).device_id_as_mac()
            formatted_static = UserIdentifier.format_mac(addr)
            self.assertEqual(formatted_obj, test_mac)
            self.assertEqual(formatted_static, test_mac)
예제 #14
0
    def test_user_allowed(self):
        user = UserIdentifier('user', '')
        user.password = '******'

        handler = DefaultAuthHandler()

        expected_result = (auth.ALLOW, {
            'control:Cleartext-Password': '******'
        })
        result = handler.handle_user_state(user, UserData.JOIN_STATE_ALLOWED,
                                           '')

        self.assertEqual(expected_result, result)
    def test_add_request_duplicate(self):
        mgr = UserManager()
        testuser = UserIdentifier('foo', 'bar')

        self.assertFalse(mgr.is_request_pending())
        res1 = mgr.add_request(testuser)
        res2 = mgr.add_request(UserIdentifier('test', '2'))

        self.assertTrue(res1)
        self.assertFalse(res2)
        self.assertTrue(mgr.is_request_pending())
        self.assertEqual(testuser, mgr.get_request())
        self.assertListEqual(list(mgr.list_users()), [])
    def _get_mgr_with_two_users(self):
        mgr = UserManager()
        testuser1 = UserIdentifier('foo', 'bar')
        testuser2 = UserIdentifier('john doe', 'phone')

        mgr.add_request(testuser1)
        mgr.update(testuser1)
        mgr.finish_request()

        mgr.add_request(testuser2)
        mgr.update(testuser2)
        mgr.finish_request()

        return mgr, testuser1, testuser2
    def test_check_expired_pass_to_data(self):
        # the UserIdentifier call should be forwarded to the
        # UserData item
        data_mock = Mock(UserData)
        data_mock.check_expired.return_value = True

        user_id = UserIdentifier('name', 'device')
        user_id.user_data = data_mock

        self.assertTrue(user_id.check_expired())
        data_mock.check_expired.assert_called_once()

        data_mock.reset_mock()
        self.assertTrue(user_id.check_expired(True))
        data_mock.check_expired.assert_called_once_with(True)
예제 #18
0
    def test_allow_known_on_pending_request(self, mock_usermgr, mock_chat,
                                            mock_loader):
        # prepare test data
        mock_usermgr_obj = Mock()
        # state WAITING means there is a request for this user
        mock_usermgr_obj.may_join.return_value = UserData.JOIN_STATE_WAITING
        mock_usermgr_obj.get_request.return_value = UserIdentifier(
            'user', 'aabb')
        mock_usermgr.return_value = mock_usermgr_obj
        mock_auth = self._get_auth_handler_mock(mock_loader)
        gacore = self._init_and_start()

        expected_result = (auth.ALLOW, {
            'control:Cleartext-Password': '******'
        })
        mock_auth.handle_user_state.return_value = expected_result
        result = gacore.authorize({
            'User-Name': 'user',
            'Calling-Station-Id': 'aabb'
        })

        # no request should have been added and the user should be rejected.
        self._assert_called_once_with_user_id(mock_usermgr_obj.may_join,
                                              'user', 'aabb')
        mock_usermgr_obj.get_request.assert_called_once()
        mock_usermgr_obj.add_request.assert_not_called()
        self._assert_called_once_with_user_id(mock_auth.handle_user_state,
                                              'user', 'aabb')
        # User identifier handled above, session ID not given
        mock_auth.handle_user_state.assert_called_once_with(
            ANY, UserData.JOIN_STATE_WAITING, ANY)
        self.assertEqual(expected_result, result)
예제 #19
0
    def test_reject_only_when_blocked(self):
        user = UserIdentifier('user', '')
        user.password = '******'

        expected_reject = (auth.REJECT, None)
        expected_accept = (auth.ALLOW, {'control:Cleartext-Password': '******'})

        result_block = AuthUtils.reject_only_when_blocked(
            user, UserData.JOIN_STATE_BLOCKED)
        result_waiting = AuthUtils.reject_only_when_blocked(
            user, UserData.JOIN_STATE_WAITING)
        result_ok = AuthUtils.reject_only_when_blocked(
            user, UserData.JOIN_STATE_ALLOWED)

        self.assertEqual(expected_reject, result_block)
        self.assertEqual(expected_accept, result_waiting)
        self.assertEqual(expected_accept, result_ok)
예제 #20
0
 def test_post_auth_without_handle_state(self):
     # without handle_user_state call, the VLAN assignment should always
     # be the network without connectivity to the outside world
     handler = VlanAuthHandler()
     result = handler.on_post_auth(
         UserIdentifier('user', 'aa-bb'), 'session1234'
     )
     self._assert_vlan(self.VLAN_PRIVATE, result)
    def test_drop_on_deny(self, mock_fmt_mac, mock_utils):
        self._prepare_on_host_mocks(mock_fmt_mac, mock_utils)

        handler = FirewallAuthHandler()
        result = handler.on_host_deny(UserIdentifier('user', 'aabb'))

        self._assert_on_host_call(mock_fmt_mac, mock_utils,
                                  '/etc/radguestauth/fw_user_drop.sh', result)
예제 #22
0
 def setUp(self):
     self.mock_um = Mock()
     self.mock_auth = Mock()
     self.cmd = ManageUserCommand(self.mock_um, self.mock_auth)
     self.testuser = UserIdentifier('user', 'device', 'pw')
     self.testdata = UserData()
     self.testuser.user_data = self.testdata
     self.mock_um.find.return_value = self.testuser
 def test_remove_user(self):
     mgr, testuser = self._get_mgr_with_one_user()
     mgr.remove(testuser)
     self.assertListEqual(list(mgr.list_users()), [])
     # check again with a separate object
     mgr, testuser = self._get_mgr_with_one_user()
     mgr.remove(UserIdentifier('foo', 'bar'))
     self.assertListEqual(list(mgr.list_users()), [])
 def test_reject_user_request(self):
     mgr = UserManager()
     # finish the request without update
     testuser = UserIdentifier('foo', 'bar')
     mgr.add_request(testuser)
     mgr.finish_request()
     self.assertListEqual(list(mgr.list_users()), [])
     self.assertFalse(mgr.is_request_pending())
    def test_user_state_waiting_drop(self, mock_fmt_mac, mock_utils):
        self._prepare_on_host_mocks(mock_fmt_mac, mock_utils)

        handler = FirewallAuthHandler()
        handler.handle_user_state(UserIdentifier('user', 'aabb'),
                                  UserData.JOIN_STATE_WAITING, '')

        self._assert_on_host_call(mock_fmt_mac, mock_utils,
                                  '/etc/radguestauth/fw_user_drop.sh')
    def test_add_request_user_has_password(self):
        mgr = UserManager()
        testuser = UserIdentifier('foo', 'bar')

        pw = mgr.generate_password()
        mgr.add_request(testuser)

        requested = mgr.get_request()
        self.assertEqual(pw, requested.password)
예제 #27
0
    def _run_cmd(self, cmd, device_id=None):
        full_cmd = '/etc/radguestauth/fw_%s.sh' % cmd
        args = None
        if device_id:
            args = [UserIdentifier.format_mac(device_id)]

        return AuthUtils.sudo_cmd(full_cmd,
                                  additional_args=args,
                                  error_return='Command failed: %s' % cmd)
    def test_may_join_other_name(self):
        # reject other users having the same device ID
        data = UserData()
        data.max_num_joins = 1
        data.valid_until = time.time() + 10000
        mgr, testuser = self._get_mgr_with_one_user_and_data(data)

        result = mgr.may_join(UserIdentifier('other', 'bar'))

        self.assert_state_blocked(result)

        # this should also apply if the stored user has no assigned data
        # (i.e. no state)
        mgr, testuser = self._get_mgr_with_one_user()

        result = mgr.may_join(UserIdentifier('other', 'bar'))

        self.assert_state_blocked(result)
예제 #29
0
    def test_notify_join(self, mock_loader):
        chatc, mock_chat_obj = self._startup_controller(mock_loader)
        # reset calls to ignore potential startup messages
        mock_chat_obj.reset_mock()

        chatc.notify_join(UserIdentifier('fooName', 'barDevice'))

        # device and username should have been sent, possibly in multiple
        # messages.
        self._assert_in_chat_messages(mock_chat_obj, ['fooName', 'barDevice'])
예제 #30
0
    def test_reject_blocked(self):
        user = UserIdentifier('user', '')

        handler = DefaultAuthHandler()

        expected_result = (auth.REJECT, None)
        result = handler.handle_user_state(user, UserData.JOIN_STATE_BLOCKED,
                                           '')

        self.assertEqual(expected_result, result)