diff --git a/Changes b/Changes index 203a2fc5..25874e71 100644 --- a/Changes +++ b/Changes @@ -1,3 +1,9 @@ +2.046001 - 2020-07-10 + + [ENHANCEMENTS] + + * #734 Multiple TACACS+/RADIUS servers now supported + 2.046000 - 2020-07-08 [ENHANCEMENTS] diff --git a/lib/App/Netdisco/Configuration.pm b/lib/App/Netdisco/Configuration.pm index 060dc37d..03a449cd 100644 --- a/lib/App/Netdisco/Configuration.pm +++ b/lib/App/Netdisco/Configuration.pm @@ -151,6 +151,42 @@ else { config->{'domain_suffix'} = qr//; } +# convert radius and tacacs from single to lists + +if (ref {} eq ref setting('radius') + and exists setting('radius')->{'secret'}) { + + my $servers = (ref [] eq ref setting('radius')->{'server'} + ? setting('radius')->{'server'} : [setting('radius')->{'server'}]); + config->{'radius'} = [ + Secret => setting('radius')->{'secret'}, + NodeList => $servers, + ]; +} + +if (ref {} eq ref setting('tacacs') + and exists setting('tacacs')->{'key'}) { + + config->{'tacacs'} = [ + Host => setting('tacacs')->{'server'}, + Key => setting('tacacs')->{'key'} || setting('tacacs')->{'secret'}, + Port => (setting('tacacs')->{'port'} || 'tacacs'), + Timeout => (setting('tacacs')->{'timeout'} || 15), + ]; +} +elsif (ref [] eq ref setting('tacacs')) { + my @newservers = (); + foreach my $server (@{ setting('tacacs') }) { + push @newservers, [ + Host => $server->{'server'}, + Key => $server->{'key'} || $server->{'secret'}, + Port => ($server->{'port'} || 'tacacs'), + Timeout => ($server->{'timeout'} || 15), + ]; + } + config->{'tacacs'} = [ @newservers ]; +} + # support unordered dictionary as if it were a single item list if (ref {} eq ref setting('device_identity')) { config->{'device_identity'} = [ setting('device_identity') ]; diff --git a/lib/App/Netdisco/Web/Auth/Provider/DBIC.pm b/lib/App/Netdisco/Web/Auth/Provider/DBIC.pm index 24a160c3..e92ddcd1 100644 --- a/lib/App/Netdisco/Web/Auth/Provider/DBIC.pm +++ b/lib/App/Netdisco/Web/Auth/Provider/DBIC.pm @@ -234,10 +234,10 @@ sub _ldap_search { sub match_with_radius { my($self, $pass, $user) = @_; - return unless setting('radius') and ref {} eq ref setting('radius'); + return unless setting('radius') and ref [] eq ref setting('radius'); my $conf = setting('radius'); - my $radius = Authen::Radius->new(Host => $conf->{server}, Secret => $conf->{secret}); + my $radius = Authen::Radius->new(@$conf); # my $dict_dir = Path::Class::Dir->new( dist_dir('App-Netdisco') ) #  ->subdir('radius_dictionaries')->stringify; Authen::Radius->load_dictionary(); # put $dict_dir in here once it's useful @@ -258,10 +258,10 @@ sub match_with_radius { sub match_with_tacacs { my($self, $pass, $user) = @_; - return unless setting('tacacs') and ref {} eq ref setting('tacacs'); + return unless setting('tacacs') and ref [] eq ref setting('tacacs'); my $conf = setting('tacacs'); - my $tacacs = new Authen::TacacsPlus(Host => $conf->{server}, Key => $conf->{key}); + my $tacacs = new Authen::TacacsPlus(@$conf); if (not $tacacs) { debug sprintf('auth error: Authen::TacacsPlus: %s', Authen::TacacsPlus::errmsg()); return undef; diff --git a/share/config.yml b/share/config.yml index 6b5842fd..59a78c63 100644 --- a/share/config.yml +++ b/share/config.yml @@ -29,7 +29,9 @@ navbar_autocomplete: true trust_remote_user: false trust_x_remote_user: false api_token_lifetime: 3600 -#ldap: +tacacs: {} +radius: {} +ldap: {} # servers: [] # user_string: 'MYDOMAIN\%USER%' # base: ""