diff --git a/clear/main.py b/clear/main.py index 5ffcd2dba4..2135152cb7 100755 --- a/clear/main.py +++ b/clear/main.py @@ -208,6 +208,31 @@ def dropcounters(): command = ["dropstat", "-c", "clear"] run_command(command) +# +# 'authentication' command ### +# + +@cli.group() +def authentication(): + """Clear authentication sessions""" + pass + + +@authentication.command('sessions') +@click.option('-i', '--interface') +@click.option('-m', '--mac') +def authentication_clear(interface, mac): + if interface is None and mac is None: + command = ['pacclear', '-a'] + run_command(command) + elif mac is not None: + command = ['pacclear', '-m {}'.format(mac)] + run_command(command) + elif interface is not None: + command = ['pacclear', '-i {}'.format(interface)] + run_command(command) + + @cli.command() def tunnelcounters(): """Clear Tunnel counters""" diff --git a/config/main.py b/config/main.py index f48c446adf..3376fe44c4 100644 --- a/config/main.py +++ b/config/main.py @@ -64,6 +64,7 @@ from . import switchport from . import dns from . import bgp_cli +from . import pac # mock masic APIs for unit test @@ -1412,6 +1413,7 @@ def config(ctx): config.add_command(nat.nat) config.add_command(vlan.vlan) config.add_command(vxlan.vxlan) +config.add_command(pac.dot1x) #add mclag commands config.add_command(mclag.mclag) @@ -6854,6 +6856,289 @@ def del_interface_storm(ctx,port_name,storm_type, namespace): if storm_control_delete_entry(port_name, storm_type) is False: ctx.fail("Unable to delete {} storm-control from interface {}".format(storm_type, port_name)) + +# +# 'authentication' group ('config interface authentication ...') +# +@interface.group('authentication') +@click.pass_context +def authentication(ctx): + """PAC authentication-related configuration tasks""" + pass + +# +# 'authentication port-control' command ('config interface authentication port-control ') +# +@authentication.command('port-control') +@click.pass_context +@click.argument('interface_name', metavar='', required=True) +@click.argument('control_mode', metavar='', required=True, type=click.Choice(['auto', 'force-authorized', 'force-unauthorized'])) +def add_portcontrol(ctx, control_mode, interface_name): + """Add port-control configutation""" + + config_db = ValidatedConfigDBConnector(ConfigDBConnector()) + config_db.connect() + + try: + config_db.mod_entry('PAC_PORT_CONFIG_TABLE', (interface_name), {'port_control_mode': control_mode }) + + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + + +# +# 'authentication host-mode' command ('config interface authentication host-mode ') +# +@authentication.command('host-mode') +@click.pass_context +@click.argument('interface_name', metavar='', required=True) +@click.argument('host_mode', metavar='', required=True, type=click.Choice(['single-host', 'multi-host', 'multi-auth'])) +def add_hostmode(ctx, host_mode, interface_name): + """Add host-mode configutation""" + + config_db = ValidatedConfigDBConnector(ConfigDBConnector()) + config_db.connect() + + try: + config_db.mod_entry('PAC_PORT_CONFIG_TABLE', (interface_name), {'host_control_mode': host_mode }) + + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + +# +# 'authentication max-users' command ('config interface authentication max-users ') +# +@authentication.command('max-users') +@click.pass_context +@click.argument('interface_name', metavar='', required=True) +@click.argument('max_users', metavar='', required=True, type=int) +def add_maxusers(ctx, max_users, interface_name): + """Add max-users configutation""" + if max_users not in range(1, 16): + ctx.fail("Given max_users {} is not allowed. Please enter a valid range <1-16>!!".format(max_users)) + + config_db = ValidatedConfigDBConnector(ConfigDBConnector()) + config_db.connect() + + try: + config_db.mod_entry('PAC_PORT_CONFIG_TABLE', (interface_name), {'max_users_per_port': max_users }) + + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + +# +# 'authentication periodic' command ('config interface authentication periodic ') +# +@authentication.command('periodic') +@click.pass_context +@click.argument('interface_name', metavar='', required=True) +@click.argument('status', metavar='', required=True, type=click.Choice(['enable', 'disable'])) +def add_periodic(ctx, status, interface_name): + """Add periodic authentication configutation""" + + config_db = ValidatedConfigDBConnector(ConfigDBConnector()) + config_db.connect() + + try: + config_db.mod_entry('PAC_PORT_CONFIG_TABLE', (interface_name), {'reauth_enable': True if status == 'enable' else False }) + + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + +# +# 'authentication reauth-period' command ('config interface authentication reauth-period ') +# +@authentication.command('reauth-period') +@click.pass_context +@click.argument('interface_name', metavar='', required=True) +@click.argument('status', metavar='', required=True) +def add_reauthperiod(ctx, status, interface_name): + """Add reauth-period configutation""" + + + config_db = ValidatedConfigDBConnector(ConfigDBConnector()) + config_db.connect() + is_server = False + val = 0 + if status == 'server': + is_server = True + else: + val = int(status) + if val not in range(1,65535): + ctx.fail("Input not in range <1-65535>") + try: + if is_server: + config_db.mod_entry('PAC_PORT_CONFIG_TABLE', (interface_name), {'reauth_period_from_server': True}) + else: + config_db.mod_entry('PAC_PORT_CONFIG_TABLE', (interface_name), {'reauth_period': val}) + config_db.mod_entry('PAC_PORT_CONFIG_TABLE', (interface_name), {'reauth_period_from_server': False}) + + + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + + +# +# 'authentication order' command ('config interface authentication order ') +# +@authentication.command('order') +@click.pass_context +@click.argument('interface_name', metavar='', required=True) +@click.argument('order_list', metavar='', required=True, type=click.Choice(['dot1x,mab', 'mab,dot1x', 'dot1x', 'mab'])) +def add_order(ctx, order_list, interface_name): + """Add order configutation""" + + config_db = ValidatedConfigDBConnector(ConfigDBConnector()) + config_db.connect() + + order_list.split() + try: + config_db.mod_entry('PAC_PORT_CONFIG_TABLE', (interface_name), {'method_list@': order_list }) + + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + + +# +# 'authentication priority' command ('config interface authentication priority ') +# +@authentication.command('priority') +@click.pass_context +@click.argument('interface_name', metavar='', required=True) +@click.argument('priority_list', metavar='', required=True, type=click.Choice(['dot1x,mab', 'mab,dot1x', 'dot1x', 'mab'])) +def add_priority(ctx, priority_list, interface_name): + """Add priority configutation""" + + config_db = ValidatedConfigDBConnector(ConfigDBConnector()) + config_db.connect() + + priority_list.split() + try: + config_db.mod_entry('PAC_PORT_CONFIG_TABLE', (interface_name), {'priority_list@': priority_list }) + + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + +# +# 'mab' group ('config interface mab ...') +# +@interface.group('mab') +@click.pass_context +def mab(ctx): + """Mac auth bypass authentication-related configuration tasks""" + pass + + + +# +# 'mab' command ('config interface mab [eap-md5|pap|chap]') +# +@interface.command('mab') +@click.pass_context +@click.argument('interface_name', metavar='', required=True) +@click.argument('status', metavar='', required=True, type=click.Choice(['enable', 'disable'])) +@click.option('-a', '--auth-type', required=False, type=click.Choice(['eap-md5', 'pap', 'chap'])) +def add_mab(ctx, status, auth_type, interface_name): + """Add mab configutation""" + + config_db = ValidatedConfigDBConnector(ConfigDBConnector()) + config_db.connect() + + print(status) + print(auth_type) + print(interface_name) + try: + config_db.mod_entry('MAB_PORT_CONFIG_TABLE', (interface_name), {'mab_enable': True if status == 'enable' else False}) + if auth_type == 'pap' or auth_type == 'chap': + config_db.mod_entry('MAB_PORT_CONFIG_TABLE', (interface_name), {'mab_auth_type': auth_type}) + else: + config_db.mod_entry('MAB_PORT_CONFIG_TABLE', (interface_name), {'mab_auth_type': 'eap-md5'}) + + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + + +def pac_is_port_any_vlan_member(config_db, port): + """Check if port is a member of any vlan""" + + vlan_ports_data = config_db.get_table('VLAN_MEMBER') + for key in vlan_ports_data: + if key[1] == port: + return True + + return False + + +def pac_interface_name_valid(ctx, config_db, interface_name): + """Check if the given interface is valid for pac config""" + + valid_interface = False + if interface_name.startswith("Ethernet"): + + valid_interface = True + if valid_interface and clicommon.is_port_router_interface(config_db, interface_name): + ctx.fail("{} is a router interface!".format(interface_name)) + valid_interface = False + + if valid_interface and clicommon.is_port_mirror_dst_port(config_db, interface_name): + ctx.fail("{} is configured as mirror destination port".format(interface_name)) + valid_interface = False + + portchannel_member_table = config_db.get_table('PORTCHANNEL_MEMBER') + + if valid_interface and clicommon.interface_is_in_portchannel(portchannel_member_table, interface_name): + ctx.fail("{} is part of portchannel!".format(interface_name)) + valid_interface = False + + if valid_interface and (pac_is_port_any_vlan_member(config_db, interface_name) is False): + ctx.fail("{} is not a member of any vlan".format(interface_name)) + valid_interface = False + + if valid_interface: + return True + else: + return False + + + +# +# 'dot1x' group ('config interface dot1x ...') +# +@interface.group('dot1x') +@click.pass_context +def dot1x(ctx): + """PAC authentication-related configuration tasks""" + pass + + + +# +# 'interface dot1x pae' command ('config interface dot1x pae ') +# +@dot1x.command('pae') +@click.pass_context +@click.argument('interface_name', metavar='', required=True) +@click.argument('role', metavar='', required=True, type=click.Choice(['authenticator', 'none'])) +def add_pae(ctx, role, interface_name): + """Add pae configutation""" + + config_db = ValidatedConfigDBConnector(ConfigDBConnector()) + config_db.connect() + + if role == 'authenticator' and pac_interface_name_valid(ctx, config_db, interface_name) is False: + ctx.fail("Given interface {} is not allowed. Please enter a valid interface for pac!!".format(interface_name)) + + try: + config_db.mod_entry('PAC_PORT_CONFIG_TABLE', (interface_name), {'port_pae_role': role}) + + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + + + + + + def is_loopback_name_valid(loopback_name): """Loopback name validation """ diff --git a/config/pac.py b/config/pac.py new file mode 100644 index 0000000000..c31a4b7d75 --- /dev/null +++ b/config/pac.py @@ -0,0 +1,37 @@ +import click +import utilities_common.cli as clicommon +from jsonpatch import JsonPatchConflict +from jsonpointer import JsonPointerException +from swsscommon.swsscommon import SonicV2Connector, ConfigDBConnector +from .validated_config_db_connector import ValidatedConfigDBConnector + + +############### PAC Configuration ################## +# +# 'dot1x' group ('config dot1x ...') +# +@click.group('dot1x') +def dot1x(): + """802.1x authentication-related configuration tasks""" + pass + + +# +# 'dot1x system-auth-control' command ('config dot1x system-auth-control ') +# +@dot1x.command('system-auth-control') +@click.pass_context +@click.argument('status', metavar='', required=True, type=click.Choice(['enable', 'disable'])) +def add_system_auth_control(ctx, status): + """Add dot1x system-auth-control related configutation""" + + config_db = ValidatedConfigDBConnector(ConfigDBConnector()) + config_db.connect() + + try: + config_db.mod_entry('HOSTAPD_GLOBAL_CONFIG_TABLE', ('GLOBAL'), {'dot1x_system_auth_control': "true" if status == 'enable' else "false"}) + + except ValueError as e: + ctx.fail("Invalid ConfigDB. Error: {}".format(e)) + + diff --git a/scripts/pacclear b/scripts/pacclear new file mode 100644 index 0000000000..bf534e2502 --- /dev/null +++ b/scripts/pacclear @@ -0,0 +1,98 @@ +#!/usr/bin/python3 + +""" + Script to clear pac information + Example of the output: + + root@sonic:/home/admin# sudo pacclear -a + + root@sonic:/home/admin# sudo pacclear -i Ethernet0 + + root@sonic:/home/admin# sudo pacclear -m 00:00:00:11:12:22 + +""" + +import json +import argparse +import sys + +from tabulate import tabulate +from swsscommon.swsscommon import ConfigDBConnector + +class pacClear(object): + + def __init__(self): + super(pacClear,self).__init__() + self.config_db = ConfigDBConnector() + self.config_db.connect() + + return + + + def clear_authentication_all(self): + """ + Clear Pac session related data. + """ + opdata = ['clear-pac','all'] + msg = json.dumps(opdata,separators=(',','|')) + self.config_db.publish('CONFIG_DB', "clearAuthSessions", msg) + + def clear_authentication_mac(self, mac): + """ + Clear Pac session related data. + """ + opdata = ['clear-pac', mac] + msg = json.dumps(opdata,separators=(',','|')) + self.config_db.publish('CONFIG_DB', "clearAuthSessions", msg) + + def clear_authentication_interface(self, interface): + """ + Clear Pac session related data. + """ + opdata = ['clear-pac', interface] + msg = json.dumps(opdata,separators=(',','|')) + self.config_db.publish('CONFIG_DB', "clearAuthSessions", msg) + + + + + + + +def main(): + parser = argparse.ArgumentParser(description='Display the PAC information', + formatter_class=argparse.RawTextHelpFormatter, + epilog=""" + Examples: + pacclear -m mac + pacclear -i interface + pacclear -a + """) + parser.add_argument('-a', '--all', action='store_true', help='Clear all sessions') + parser.add_argument('-i', '--interface', type=str, help='Clear all sessions on interface') + parser.add_argument('-m', '--mac', type=str, help='Clear sessions for mac') + + args = parser.parse_args() + + clear_all = args.all + clear_interface = args.interface + clear_mac = args.mac + + if clear_interface: + clear_interface = clear_interface.strip() + + try: + pac = pacClear() + if clear_mac: + pac.clear_authentication_mac(clear_mac) + if clear_interface: + pac.clear_authentication_interface(clear_interface) + if clear_all: + pac.clear_authentication_all() + except Exception as e: + print(str(e)) + sys.exit(1) + +if __name__ == "__main__": + main() + diff --git a/scripts/pacshow b/scripts/pacshow new file mode 100644 index 0000000000..f271918d78 --- /dev/null +++ b/scripts/pacshow @@ -0,0 +1,361 @@ +#!/usr/bin/python3 + +""" + Script to show pac information + Example of the output: + + root@sonic:/home/admin# sudo pacshow -t interface -a + + Interface Port-Control Host-Mode Pae-Role Max-Users Reauth Reauth-Period Reauth-from-Serer config-methods config-priority enabled-methods enabled-priority + ----------- -------------- ----------- ---------- ----------- -------- --------------- ------------------- ---------------- ----------------- ----------------- ------------------ + Ethernet1 auto multi-auth none 16 disabled 60 False ['dot1x', 'mab'] none none none + Ethernet2 auto multi-auth none 16 disabled 60 False none none none none + + root@sonic:/home/admin# sudo pacshow -t interface -i Ethernet1 + + Interface Port-Control Host-Mode Pae-Role Max-Users Reauth Reauth-Period Reauth-from-Serer config-methods config-priority enabled-methods enabled-priority + ----------- -------------- ----------- ---------- ----------- -------- --------------- ------------------- ---------------- ----------------- ----------------- ------------------ + Ethernet1 auto multi-auth none 16 disabled 60 False ['dot1x', 'mab'] none none none + + + root@sonic:/home/admin# sudo pacshow -t client -a + + Authenticated Clients : 2 + + Interface mac-addr user-name vlan + ----------- ----------------- ----------- ------ + Ethernet0 00:11:01:00:00:01 vijaya1 10 + Ethernet2 00:11:01:00:00:03 vijaya3 20 + + root@sonic:/home/admin# sudo pacshow -t client -i Ethernet2 + + Authenticated Clients : 2 + + Interface mac-addr user-name vlan + ----------- ----------------- ----------- ------ + Ethernet2 00:11:01:00:00:03 vijaya3 20 + + root@sonic:/home/admin# sudo pacshow -t mab -a + + Interface MAB Enabled auth-type + ----------- ------------- ----------- + Ethernet2 true eap-md5 + + root@sonic:/home/admin# sudo pacshow -t mab -a -i Ethernet2 + + Interface MAB Enabled auth-type + ----------- ------------- ----------- + Ethernet2 true eap-md5 + + root@sonic:/home/admin# sudo pacshow -t dot1x -a + + Admin Mode : disabled + +""" + +import argparse +import sys + +from tabulate import tabulate +from swsscommon.swsscommon import ConfigDBConnector, SonicV2Connector + +def pac_populate_dict(display_dict, port, config, oper): + + display_dict[port] = {} + for i in config.keys(): + if i == "port_control_mode": + display_dict[port]['port-control'] = config["port_control_mode"] + + if i == "host_control_mode": + display_dict[port]['host-control'] = config["host_control_mode"] + if i == "max_users_per_port": + display_dict[port]['max-users'] = config["max_users_per_port"] + if i == "port_pae_role": + display_dict[port]['port-role'] = config["port_pae_role"] + if i == "reauth_enable": + display_dict[port]['reauth-enable'] = 'enabled' if True == config["reauth_enable"] else 'disabled' + if i == "reauth_period": + display_dict[port]['reauth-period'] = config["reauth_period"] + if i == "reauth_period_from_server": + display_dict[port]['reauthperiod-from-server'] = config["reauth_period_from_server"] + if i == "method_list": + display_dict[port]['config-methods'] = config["method_list"] + if i == "priority_list": + display_dict[port]['config-priority'] = config["priority_list"] + + display_dict[port]['enabled-methods'] = ['none'] + display_dict[port]['enabled-priority'] = ['none'] + + if oper: + for i in oper.keys(): + if i == "enabled_method_list@": + display_dict[port]['enabled-methods'] = oper["enabled_method_list@"] + if i == "enabled_priority_list@": + display_dict[port]['enabled-priority'] = oper["enabled_priority_list@"] + + if 'port-control' not in display_dict[port].keys(): + display_dict[port]['port-control'] = 'none' + if 'host-control' not in display_dict[port].keys(): + display_dict[port]['host-control'] = 'none' + if 'max-users' not in display_dict[port].keys(): + display_dict[port]['max-users'] = '16' + if 'port-role' not in display_dict[port].keys(): + display_dict[port]['port-role'] = 'none' + if 'reauth-enable' not in display_dict[port].keys(): + display_dict[port]['reauth-enable'] = 'disabled' + if 'reauth-period' not in display_dict[port].keys(): + display_dict[port]['reauth-period'] = '60' + if 'reauthperiod-from-server' not in display_dict[port].keys(): + display_dict[port]['reauthperiod-from-server'] = False + if 'config-methods' not in display_dict[port].keys(): + display_dict[port]['config-methods'] = ['dot1x', 'mab'] + if 'config-priority' not in display_dict[port].keys(): + display_dict[port]['config-priority'] = ['dot1x', 'mab'] + + + + +class pacShow(object): + + def __init__(self): + super(pacShow,self).__init__() + self.config_db = ConfigDBConnector() + self.config_db.connect() + + self.state_db = SonicV2Connector(host='127.0.0.1') + self.state_db.connect(self.state_db.STATE_DB) + return + + + def fetch_authentication_interface(self, port): + """ + Fetch interface related data. + """ + self.display_dict = {} + + pac_tables = self.config_db.get_table('PAC_PORT_CONFIG_TABLE') + if not pac_tables: + return + if port == 'all': + for i in pac_tables: + pac_keys = [] + config_dict = {} + oper_dict = {} + pac_keys = i.split("|") + if pac_keys[0] not in self.display_dict.keys(): + if pac_tables[i].__len__() == 0: + continue + self.display_dict[pac_keys[0]] = {} + config_dict = pac_tables[i] + oper_dict = self.state_db.get_all(self.state_db.STATE_DB, 'PAC_PORT_OPER_TABLE|{}'.format(pac_keys[0])) + pac_populate_dict(self.display_dict, pac_keys[0],config_dict, oper_dict) + else: + config_dict = {} + oper_dict = {} + config_dict = pac_tables[port] + oper_dict = self.state_db.get_all(self.state_db.STATE_DB, 'PAC_PORT_OPER_TABLE|{}'.format(port)) + pac_populate_dict(self.display_dict, port,config_dict, oper_dict) + + + def fetch_mab_interface(self, port): + """ + Fetch interface related mab data. + """ + self.display_dict = {} + + mab_tables = self.config_db.get_table('MAB_PORT_CONFIG_TABLE') + if not mab_tables: + return + if port == 'all': + for i in mab_tables: + mab_keys = [] + mab_keys = i.split("|") + self.display_dict[mab_keys[0]]= mab_tables[i] + else: + self.display_dict[port] = mab_tables[port] + + + + def fetch_authentication_client_all(self): + """ + Fetch client related data per interface. + """ + self.client_dict = {} + + client_tables = self.state_db.keys(self.state_db.STATE_DB, 'PAC_AUTHENTICATED_CLIENT_OPER_TABLE|*') + for i in client_tables: + client_keys = [] + test_dict = {} + client_keys = i.split("|") + if client_keys[1]: + if client_keys[1] not in self.client_dict.keys(): + self.client_dict[client_keys[1]] = {} + test_dict = self.state_db.get_all(self.state_db.STATE_DB, i) + self.client_dict[client_keys[1]][client_keys[2]] = self.state_db.get_all(self.state_db.STATE_DB, i) + + + def fetch_authentication_client(self, port): + """ + Fetch client related data per interface. + """ + self.client_dict = {} + + client_tables = self.state_db.keys(self.state_db.STATE_DB, 'PAC_AUTHENTICATED_CLIENT_OPER_TABLE|*') + for i in client_tables: + client_keys = [] + client_keys = i.split("|") + if port in client_keys: + if client_keys[1] not in self.client_dict.keys(): + self.client_dict[client_keys[1]] = {} + self.client_dict[client_keys[1]][client_keys[2]] = self.state_db.get_all(self.state_db.STATE_DB, i) + + def display_authentication(self): + """ + display the number of authenticated clients. + """ + client_tables = self.state_db.keys(self.state_db.STATE_DB, 'PAC_AUTHENTICATED_CLIENT_OPER_TABLE|*') + print("Authenticated Clients : {}".format(len(client_tables))) + + def display_dot1x(self): + """ + display the dot1x system-auth-control status. + """ + self.display_dict = {} + + self.display_dict = self.config_db.get_all(self.config_db.CONFIG_DB, 'HOSTAPD_GLOBAL_CONFIG_TABLE|GLOBAL') + if 'dot1x_system_auth_control' not in self.display_dict.keys(): + status = False + else: + status = self.display_dict['dot1x_system_auth_control'] + print("802.1X admin mode : {}".format("Enabled" if status else "Disabled")) + + + + def display_authentication_interface(self): + """ + display interface related data. + """ + HEADER = ['Interface', 'Port-Control', 'Host-Mode', 'Pae-Role', 'Max-Users', 'Reauth', 'Reauth-Period', 'Reauth-from-Serer', 'config-methods', 'config-priority', 'enabled-methods', 'enabled-priority'] + output = [] + for i in self.display_dict.keys(): + data = {} + data = self.display_dict[i] + output.append([i, data['port-control'], data['host-control'], data['port-role'], data['max-users'], data['reauth-enable'], data['reauth-period'], data['reauthperiod-from-server'], ','.join(data['config-methods']), ','.join(data['config-priority']), data['enabled-methods'], data['enabled-priority']]) + print("") + print(tabulate(output, HEADER)) + print("") + + def display_authentication_client_interface(self): + """ + display per interface related client data. + """ + sorted_keys = sorted(self.client_dict.keys()) + for i in sorted_keys: + print("Interface : {}".format(i)) + for j in self.client_dict[i].keys(): + print("mac-addr : {}".format(j)) + for client_data in self.client_dict[i][j]: + for k in client_data.keys(): + print("{} : {}".format(k, client_data[k])) + + + def display_authentication_client_interface_all(self): + """ + display all client data. + """ + self.display_authentication() + HEADER = ['Interface', 'mac-addr', 'user-name', 'vlan'] + output = [] + sorted_keys = sorted(self.client_dict.keys()) + for i in sorted_keys: + for j in self.client_dict[i].keys(): + output.append([i, j, self.client_dict[i][j]['user_name'], self.client_dict[i][j]['vlan_id']]) + + print("") + print(tabulate(output, HEADER)) + print("") + + + def display_mab_interface(self): + """ + display mab data. + """ + HEADER = ['Interface', 'MAB Enabled', 'auth-type'] + output = [] + sorted_keys = sorted(self.display_dict.keys()) + for i in sorted_keys: + if 'mab_enable' not in self.display_dict[i].keys(): + self.display_dict[i]['mab_enable'] = False + continue + + if 'mab_auth_type' not in self.display_dict[i].keys(): + self.display_dict[i]['mab_auth_type'] = 'eap-md5' + output.append([i, self.display_dict[i]['mab_enable'], self.display_dict[i]['mab_auth_type']]) + print("") + print(tabulate(output, HEADER)) + print("") + + + + + + +def main(): + parser = argparse.ArgumentParser(description='Display the PAC information', + formatter_class=argparse.RawTextHelpFormatter, + epilog=""" + Examples: + authentication -p -a + authentication -p -i + authentication -c -a + authentication -c -i + authentication -d + authentication -m + authentication -m -i + """) + parser.add_argument('-t', '--type', required=True, action='store', + choices=['interface', 'client', 'dot1x', 'mab'], + help='The type of pac information') + parser.add_argument('-a', '--all', action='store_true', help='Show all entries') + parser.add_argument('-i', '--interface', type=str, help='Show interface related information') + + args = parser.parse_args() + + show_type = args.type + show_all = args.all + show_interface = args.interface + + if show_interface: + show_interface = show_interface.strip() + try: + pac = pacShow() + if show_type == 'interface': + if show_all: + pac.fetch_authentication_interface('all') + pac.display_authentication_interface() + elif show_interface: + pac.fetch_authentication_interface(show_interface) + pac.display_authentication_interface() + if show_type == 'client': + if show_all: + pac.fetch_authentication_client_all() + pac.display_authentication_client_interface_all() + elif show_interface: + pac.fetch_authentication_client(show_interface) + pac.display_authentication_client_interface_all() + if show_type == 'dot1x': + pac.display_dot1x() + if show_type == 'mab': + if show_all: + pac.fetch_mab_interface('all') + pac.display_mab_interface() + elif show_interface: + pac.fetch_mab_interface(show_interface) + pac.display_mab_interface() + except Exception as e: + print(str(e)) + sys.exit(1) + +if __name__ == "__main__": + main() + diff --git a/setup.py b/setup.py index 6a66f012f9..09265ced2f 100644 --- a/setup.py +++ b/setup.py @@ -151,6 +151,8 @@ 'scripts/natshow', 'scripts/nbrshow', 'scripts/neighbor_advertiser', + 'scripts/pacshow', + 'scripts/pacclear', 'scripts/pcmping', 'scripts/pg-drop', 'scripts/port2alias', diff --git a/show/main.py b/show/main.py index 06114eb79f..9ead419749 100755 --- a/show/main.py +++ b/show/main.py @@ -67,6 +67,7 @@ from . import syslog from . import dns from . import bgp_cli +from . import pac # Global Variables PLATFORM_JSON = 'platform.json' @@ -318,6 +319,9 @@ def cli(ctx): cli.add_command(system_health.system_health) cli.add_command(warm_restart.warm_restart) cli.add_command(dns.dns) +cli.add_command(pac.authentication) +cli.add_command(pac.dot1x) +cli.add_command(pac.mab) # syslog module cli.add_command(syslog.syslog) diff --git a/show/pac.py b/show/pac.py new file mode 100644 index 0000000000..5c558b4a6c --- /dev/null +++ b/show/pac.py @@ -0,0 +1,67 @@ +import click +import utilities_common.cli as clicommon + + +# +# 'authentication' group ("show authentication ...") +# + +@click.group(cls=clicommon.AliasedGroup) +def authentication(): + """Show details of the pac authentication """ + pass + + +# 'interface' subcommand ("show authentication interface") +@authentication.command('interface') +@click.option('-i', '--interface') +@click.option('--verbose', is_flag=True, help='Enable verbose output') +def authentication_interface(interface, verbose): + """ Show authentication interface """ + if interface is not None: + if interface.startswith("Ethernet"): + cmd = ['sudo', 'pacshow', '-t', 'interface', '-i {}'.format(interface)] + clicommon.run_command(cmd, display_cmd=verbose) + else: + cmd = ['sudo', 'pacshow', '-t', 'interface', '-a'] + clicommon.run_command(cmd, display_cmd=verbose) + +# 'clients' subcommand ("show authentication clients") +@authentication.command('clients') +@click.option('-i', '--interface') +@click.option('--verbose', is_flag=True, help="Enable verbose output") +def authentication_interface(interface, verbose): + """ Show authentication interface """ + if interface is not None: + if interface.startswith("Ethernet"): + cmd = ['sudo', 'pacshow', '-t', 'client', '-i {}'.format(interface)] + clicommon.run_command(cmd, display_cmd=verbose) + else: + cmd = ['sudo', 'pacshow', '-t', 'client', '-a'] + clicommon.run_command(cmd, display_cmd=verbose) + + +@click.group(cls=clicommon.AliasedGroup, invoke_without_command=True) +def dot1x(): + """Show details of the 802.1X """ + cmd = ['sudo', 'pacshow', '-t', 'dot1x', '-a'] + clicommon.run_command(cmd) + +@click.group(cls=clicommon.AliasedGroup) +def mab(): + """Show details of the MAB """ + pass + +# 'interface' subcommand ("show mab interface") +@mab.command('interface') +@click.option('-i', '--interface') +@click.option('--verbose', is_flag=True, help="Enable verbose output") +def mab_interface(interface, verbose): + """ Show mab interface """ + if interface is not None: + if interface.startswith("Ethernet"): + cmd = ['sudo', 'pacshow', '-t', 'mab', '-i {}'.format(interface)] + clicommon.run_command(cmd, display_cmd=verbose) + else: + cmd = ['sudo', 'pacshow', '-t', 'mab', '-a'] + clicommon.run_command(cmd, display_cmd=verbose)