Skip to content

Commit

Permalink
Bypass Authenticator for VLAN expiry (faucetsdn#196)
Browse files Browse the repository at this point in the history
  • Loading branch information
anurag6 authored Oct 20, 2020
1 parent 419b76a commit 4020e83
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 10 deletions.
7 changes: 5 additions & 2 deletions forch/forchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,11 +370,14 @@ def initialized(self):

def _process_device_placement(self, eth_src, device_placement, static=False, expired_vlan=None):
"""Call device placement API for faucetizer/authenticator"""
self._port_state_manager.handle_device_placement(
propagate_placement = self._port_state_manager.handle_device_placement(
eth_src, device_placement, static, expired_vlan)

if self._authenticator:
if self._authenticator and propagate_placement:
self._authenticator.process_device_placement(eth_src, device_placement)
else:
LOGGER.info(
'Ignored vlan expiration for device %s with expired vlan %d', eth_src, expired_vlan)

def handle_auth_result(self, mac, access, segment, role):
"""Method passed as callback to authenticator to forward auth results"""
Expand Down
9 changes: 3 additions & 6 deletions forch/port_state_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def handle_device_placement(self, mac, device_placement, static=False, expired_v
if device_placement.connected:
# if device is learned
self._process_device_placement(mac, device_placement, static=static)
return
return True

# if device vlan is expired
static_behavior = self._static_device_behaviors.get(mac)
Expand All @@ -138,11 +138,8 @@ def handle_device_placement(self, mac, device_placement, static=False, expired_v
if (not expired_vlan or not device_behavior or
self._get_vlan_from_segment(device_behavior.segment) == expired_vlan):
self._process_device_placement(mac, device_placement, static=False)
if dynamic_behavior:
self._process_device_behavior(mac, DeviceBehavior(), static=False)
else:
LOGGER.info(
'Ignoring vlan expiration for device %s with expired vlan %d', mac, expired_vlan)
return True
return False

def _handle_authenticated_device(self, mac, device_behavior, static):
"""Initialize or update the state machine for an authenticated device"""
Expand Down
1 change: 1 addition & 0 deletions forch/simple_auth_state_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def host_expired(self):
"""Host expired"""
with self._transition_lock:
self._reset_state_machine()
self._auth_callback(self.src_mac, self.UNAUTH, None, None)

def received_radius_accept(self, segment, role):
"""Received RADIUS accept message"""
Expand Down
66 changes: 64 additions & 2 deletions testing/python_lib/test_forchestrator.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
"""Unit tests for Faucet State Collector"""

from unittest.mock import Mock
import unittest
import yaml
from unit_base import ForchestratorTestBase
from forch.authenticator import Authenticator
from forch.port_state_manager import PortStateManager
from forch.utils import dict_proto
from forch.proto.devices_state_pb2 import DevicePlacement, DeviceBehavior
from forch.proto.forch_configuration_pb2 import OrchestrationConfig


# pylint: disable=protected-access
class ForchestratorUnitTestCase(ForchestratorTestBase):
"""Test cases for dataplane state"""

# pylint: disable=protected-access
def test_faucet_config_validation(self):
"""Test validation for faucet config"""
print(self._forchestrator)
faucet_config_str = """
dps:
nz-kiwi-t1sw1:
Expand Down Expand Up @@ -49,5 +54,62 @@ def test_faucet_config_validation(self):
self.assertFalse(self._forchestrator._validate_config(faucet_config))


# pylint: disable=protected-access
class ForchestratorAuthTestCase(ForchestratorTestBase):
"""Test case for forchestrator functionality with authenticator"""

# pylint: disable=invalid-name
def setUp(self):
"""setup fixture for each test method"""
self._initialize_forchestrator()
auth_config = dict_proto(
{
'radius_info': {
'server_ip': '0.0.0.0',
'server_port': 9999,
'source_port': 9999,
'radius_secret_helper': f'{"echo radius_secret"}'
}
},
OrchestrationConfig.AuthConfig
)

def handle_auth_result(src_mac, access, segment, role):
device_behavior = DeviceBehavior(segment=segment, role=role)
self._forchestrator._port_state_manager.handle_device_behavior(src_mac, device_behavior)

def get_vlan_from_segment(segment):
if segment == 'ACCEPT':
return 100
return 999

self._forchestrator._authenticator = Authenticator(auth_config, handle_auth_result,
radius_query_object=Mock())
self._forchestrator._port_state_manager = PortStateManager(
Mock(), Mock(), get_vlan_from_segment, 'SEQUESTER')

def _get_auth_sm_state(self, mac):
mac_sm = self._forchestrator._authenticator.sessions.get(mac)
if mac_sm:
return mac_sm.get_state()
return None

def test_auth_learn(self):
"""Test to validate MAC authentication status"""
device_placement = DevicePlacement(switch='switch', port=1, connected=True)
self._forchestrator._process_device_placement('00:11:22:33:44:55', device_placement)
self.assertEqual(self._get_auth_sm_state('00:11:22:33:44:55'), 'RADIUS Request')
self._forchestrator._authenticator.process_radius_result('00:11:22:33:44:55',
'ACCEPT', 'ACCEPT', None)
self.assertEqual(self._get_auth_sm_state('00:11:22:33:44:55'), 'Authorized')
device_placement = DevicePlacement(switch='switch', port=1, connected=False)
self._forchestrator._process_device_placement('00:11:22:33:44:55',
device_placement, expired_vlan=200)
self.assertEqual(self._get_auth_sm_state('00:11:22:33:44:55'), 'Authorized')
self._forchestrator._process_device_placement('00:11:22:33:44:55',
device_placement, expired_vlan=100)
self.assertEqual(self._get_auth_sm_state('00:11:22:33:44:55'), None)


if __name__ == '__main__':
unittest.main()

0 comments on commit 4020e83

Please sign in to comment.