From a16043c5386689b5bfa6a677302248c381dcd088 Mon Sep 17 00:00:00 2001 From: Durand Fabrice Date: Fri, 28 Oct 2022 15:03:09 -0400 Subject: [PATCH 01/88] Added support for Wired port on Ruckus AP and for Disconnect --- lib/pf/Switch/Ruckus/SmartZone.pm | 65 +++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/lib/pf/Switch/Ruckus/SmartZone.pm b/lib/pf/Switch/Ruckus/SmartZone.pm index 6a4edddb9e2d..44b3167c3bcf 100644 --- a/lib/pf/Switch/Ruckus/SmartZone.pm +++ b/lib/pf/Switch/Ruckus/SmartZone.pm @@ -46,6 +46,8 @@ sub description { 'Ruckus SmartZone Wireless Controllers' } use pf::SwitchSupports qw( WirelessMacAuth -WebFormRegistration + WiredMacAuth + WirelessDot1x ); =over @@ -372,6 +374,69 @@ sub check_if_radius_request_psk_matches { ); } +=head2 wiredeauthTechniques + +Return the reference to the deauth technique or the default deauth technique. + +=cut + +sub wiredeauthTechniques { + my ($self, $method, $connection_type) = @_; + my $logger = $self->logger; + + if ($connection_type == $WIRED_802_1X) { + my $default = $SNMP::RADIUS; + my %tech = ( + $SNMP::RADIUS => 'deauthenticateMacDefault', + ); + + if (!defined($method) || !defined($tech{$method})) { + $method = $default; + } + return $method,$tech{$method}; + } + elsif ($connection_type == $WIRED_MAC_AUTH) { + my $default = $SNMP::RADIUS; + my %tech = ( + $SNMP::RADIUS => 'deauthenticateMacDefault', + ); + if (!defined($method) || !defined($tech{$method})) { + $method = $default; + } + return $method,$tech{$method}; + } + else{ + $logger->error("This authentication mode is not supported"); + } + +} + +=item deauthenticateMacDefault + +De-authenticate a MAC address from wire network (including 802.1x). + +New implementation using RADIUS Disconnect-Request. + +=cut + +sub deauthenticateMacDefault { + my ( $self, $ifindex, $mac, $is_dot1x ) = @_; + my $logger = $self->logger; + + if ( !$self->isProductionMode() ) { + $logger->info("not in production mode... we won't perform deauthentication"); + return 1; + } + + #Fetching the acct-session-id + my $dynauth = node_accounting_dynauth_attr($mac); + + $logger->debug("deauthenticate $mac using RADIUS Disconnect-Request deauth method"); + return $self->radiusDisconnect( + $mac, { 'User-Name' => $dynauth->{'username'} }, + ); +} + =back =head1 AUTHOR From 672655e9441c1eb3c3173798a8a5b731ce3ece3c Mon Sep 17 00:00:00 2001 From: Durand Fabrice Date: Mon, 31 Oct 2022 13:39:06 -0400 Subject: [PATCH 02/88] Added missing import --- lib/pf/Switch/Ruckus/SmartZone.pm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pf/Switch/Ruckus/SmartZone.pm b/lib/pf/Switch/Ruckus/SmartZone.pm index 44b3167c3bcf..443be7a7c103 100644 --- a/lib/pf/Switch/Ruckus/SmartZone.pm +++ b/lib/pf/Switch/Ruckus/SmartZone.pm @@ -35,6 +35,8 @@ use pf::config qw ( $WEBAUTH_WIRELESS $WIRELESS_MAC_AUTH %connection_type_to_str + $WIRED_802_1X + $WIRED_MAC_AUTH ); use pf::util::radius qw(perform_disconnect); use pf::log; From 6543bd9ad5e477a3dd3b1320f7227f7d7803c6f1 Mon Sep 17 00:00:00 2001 From: Durand Fabrice Date: Fri, 16 Apr 2021 11:20:19 -0400 Subject: [PATCH 03/88] First draft ContentKeeper firewall sso --- go/firewallsso/contentkeeper.go | 64 +++++++++++++++++++++++++++++++++ go/firewallsso/factory.go | 1 + 2 files changed, 65 insertions(+) create mode 100644 go/firewallsso/contentkeeper.go diff --git a/go/firewallsso/contentkeeper.go b/go/firewallsso/contentkeeper.go new file mode 100644 index 000000000000..5b84de15c99c --- /dev/null +++ b/go/firewallsso/contentkeeper.go @@ -0,0 +1,64 @@ +package firewallsso + +import ( + "context" + "fmt" + "net" + + "time" + + radius "github.com/inverse-inc/go-radius" + "github.com/inverse-inc/go-radius/rfc2865" + "github.com/inverse-inc/go-radius/rfc2866" + "github.com/inverse-inc/go-radius/rfc2869" + "github.com/inverse-inc/packetfence/go/log" + "github.com/inverse-inc/packetfence/go/sharedutils" +) + +type ContentKeeper struct { + FirewallSSO + Password string `json:"password"` + Port string `json:"port"` +} + +// Send an SSO start to the ContentKeeper firewall +// Returns an error unless there is a valid reply from the firewall +func (fw *ContentKeeper) Start(ctx context.Context, info map[string]string, timeout int) (bool, error) { + p := fw.startRadiusPacket(ctx, info, timeout) + client := fw.getRadiusClient(ctx) + + var err error + client.Dialer.LocalAddr, err = net.ResolveUDPAddr("udp", fw.getSourceIp(ctx).String()+":0") + sharedutils.CheckError(err) + + // Use the background context since we don't want the lib to use our context + ctx2, cancel := fw.RadiusContextWithTimeout() + defer cancel() + _, err = client.Exchange(ctx2, p, fw.PfconfigHashNS+":"+fw.Port) + if err != nil { + log.LoggerWContext(ctx).Error(fmt.Sprintf("Couldn't SSO to the ContentKeeper, got the following error: %s", err)) + return false, err + } else { + return true, nil + } +} + +// Build the RADIUS packet for an SSO start +func (fw *ContentKeeper) startRadiusPacket(ctx context.Context, info map[string]string, timeout int) *radius.Packet { + r := radius.New(radius.CodeAccountingRequest, []byte(fw.Password)) + rfc2866.AcctStatusType_Add(r, rfc2866.AcctStatusType_Value_Start) + rfc2865.UserName_AddString(r, info["username"]) + rfc2865.CalledStationID_AddString(r, "00:11:22:33:44:55") + rfc2865.FramedIPAddress_Add(r, net.ParseIP(info["ip"])) + rfc2865.CallingStationID_AddString(r, info["mac"]) + rfc2869.EventTimestamp_Add(r, time.Now()) + + return r +} + +// Send an SSO stop to the ContentKeeper firewall +// Returns an error unless there is a valid reply from the firewall +func (fw *ContentKeeper) Stop(ctx context.Context, info map[string]string) (bool, error) { + log.LoggerWContext(ctx).Info("Not supported sending SSO to ContentKeeper using RADIUS") + return true, nil +} diff --git a/go/firewallsso/factory.go b/go/firewallsso/factory.go index 614a6b601dd5..839e68dd5f37 100644 --- a/go/firewallsso/factory.go +++ b/go/firewallsso/factory.go @@ -29,6 +29,7 @@ func NewFactory(ctx context.Context) Factory { f.typeRegistry["JuniperSRX"] = reflect.TypeOf(&JuniperSRX{}).Elem() f.typeRegistry["FamilyZone"] = reflect.TypeOf(&FamilyZone{}).Elem() f.typeRegistry["CiscoIsePic"] = reflect.TypeOf(&CiscoIsePic{}).Elem() + f.typeRegistry["ContentKeeper"] = reflect.TypeOf(&ContentKeeper{}).Elem() return f } From c52f5526dcbb905fc5fcad6c0d98afe2385dd93e Mon Sep 17 00:00:00 2001 From: Durand Fabrice Date: Fri, 16 Apr 2021 11:45:09 -0400 Subject: [PATCH 04/88] Added form --- go/firewallsso/contentkeeper_test.go | 61 +++++++++++++ .../Form/Config/Firewall_SSO/ContentKeeper.pm | 61 +++++++++++++ .../_components/FormTypeContentKeeper.js | 91 +++++++++++++++++++ .../firewalls/_components/TheForm.vue | 4 + .../views/Configuration/firewalls/config.js | 1 + .../UnifiedApi/Controller/Config/Firewalls.pm | 2 + lib/pf/constants/firewallsso.pm | 1 + 7 files changed, 221 insertions(+) create mode 100644 go/firewallsso/contentkeeper_test.go create mode 100644 html/pfappserver/lib/pfappserver/Form/Config/Firewall_SSO/ContentKeeper.pm create mode 100644 html/pfappserver/root/src/views/Configuration/firewalls/_components/FormTypeContentKeeper.js diff --git a/go/firewallsso/contentkeeper_test.go b/go/firewallsso/contentkeeper_test.go new file mode 100644 index 000000000000..e9c9b8dc5acb --- /dev/null +++ b/go/firewallsso/contentkeeper_test.go @@ -0,0 +1,61 @@ +package firewallsso + +import ( + "testing" + + "github.com/inverse-inc/go-radius/rfc2865" + "github.com/inverse-inc/go-radius/rfc2866" + //"github.com/davecgh/go-spew/spew" +) + +func TestContentKeeperStartRadiusPacket(t *testing.T) { + f := WatchGuard{Password: "secret"} + + p := f.startRadiusPacket(ctx, sampleInfo, 86400) + + if rfc2866.AcctStatusType_Get(p) != 1 { + t.Errorf("Incorrect Acct-Status-Type in SSO packet.") + } + + if rfc2865.FramedIPAddress_Get(p).String() != sampleInfo["ip"] { + t.Errorf("Incorrect Framed-IP-Address in SSO packet.") + } + + if string(rfc2865.UserName_Get(p)) != sampleInfo["username"] { + t.Errorf("Incorrect User-Name in SSO packet.") + } + + if string(rfc2865.CallingStationID_Get(p)) != sampleInfo["mac"] { + t.Errorf("Incorrect Calling-Station-Id in SSO packet.") + } + + if string(rfc2865.FilterID_Get(p)) != sampleInfo["role"] { + t.Errorf("Incorrect Filter-Id in SSO packet.") + } +} + +func TestContentKeeperStopRadiusPacket(t *testing.T) { + f := WatchGuard{Password: "secret"} + + p := f.stopRadiusPacket(ctx, sampleInfo) + + if rfc2866.AcctStatusType_Get(p) != 2 { + t.Errorf("Incorrect Acct-Status-Type in SSO packet.") + } + + if rfc2865.FramedIPAddress_Get(p).String() != sampleInfo["ip"] { + t.Errorf("Incorrect Framed-IP-Address in SSO packet.") + } + + if string(rfc2865.UserName_Get(p)) != sampleInfo["username"] { + t.Errorf("Incorrect User-Name in SSO packet.") + } + + if string(rfc2865.CallingStationID_Get(p)) != sampleInfo["mac"] { + t.Errorf("Incorrect Calling-Station-Id in SSO packet.") + } + + if string(rfc2865.FilterID_Get(p)) != sampleInfo["role"] { + t.Errorf("Incorrect Filter-Id in SSO packet.") + } +} diff --git a/html/pfappserver/lib/pfappserver/Form/Config/Firewall_SSO/ContentKeeper.pm b/html/pfappserver/lib/pfappserver/Form/Config/Firewall_SSO/ContentKeeper.pm new file mode 100644 index 000000000000..1c77addab9b1 --- /dev/null +++ b/html/pfappserver/lib/pfappserver/Form/Config/Firewall_SSO/ContentKeeper.pm @@ -0,0 +1,61 @@ +package pfappserver::Form::Config::Firewall_SSO::ContentKeeper; + +=head1 NAME + +pfappserver::Form::Config::Firewall_SSO::ContentKeeper - Web form to add a Content Keeperd firewall + +=head1 DESCRIPTION + +Form definition to create or update a ContentKeeper firewall. + +=cut + +use HTML::FormHandler::Moose; +extends 'pfappserver::Form::Config::Firewall_SSO'; +with 'pfappserver::Base::Form::Role::Help'; + +use pf::config; +use pf::util; +use File::Find qw(find); + +has_field '+port' => + ( + default => 1813, + ); +has_field 'type' => + ( + type => 'Hidden', + default => 'ContentKeeper', + ); + +has_block definition => + ( + render_list => [ qw(id type password port categories networks cache_updates cache_timeout username_format default_realm) ], + ); + +=head1 COPYRIGHT + +Copyright (C) 2005-2021 Inverse inc. + +=head1 LICENSE + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +USA. + +=cut + +__PACKAGE__->meta->make_immutable unless $ENV{"PF_SKIP_MAKE_IMMUTABLE"}; + +1; diff --git a/html/pfappserver/root/src/views/Configuration/firewalls/_components/FormTypeContentKeeper.js b/html/pfappserver/root/src/views/Configuration/firewalls/_components/FormTypeContentKeeper.js new file mode 100644 index 000000000000..994c1220799a --- /dev/null +++ b/html/pfappserver/root/src/views/Configuration/firewalls/_components/FormTypeContentKeeper.js @@ -0,0 +1,91 @@ + + diff --git a/html/pfappserver/root/src/views/Configuration/firewalls/_components/TheForm.vue b/html/pfappserver/root/src/views/Configuration/firewalls/_components/TheForm.vue index 30c7b1683ae9..caf661c214e6 100644 --- a/html/pfappserver/root/src/views/Configuration/firewalls/_components/TheForm.vue +++ b/html/pfappserver/root/src/views/Configuration/firewalls/_components/TheForm.vue @@ -20,6 +20,7 @@ import { BaseContainerLoading } from '@/components/new/' import FormTypeBarracudaNg from './FormTypeBarracudaNg' import FormTypeCheckpoint from './FormTypeCheckpoint' +import FormTypeContentKeeper from './FormTypeContentKeeper' import FormTypeCiscoIsePic from './FormTypeCiscoIsePic' import FormTypeFamilyZone from './FormTypeFamilyZone' import FormTypeFortiGate from './FormTypeFortiGate' @@ -37,6 +38,7 @@ const components = { FormTypeBarracudaNg, FormTypeCheckpoint, FormTypeCiscoIsePic, + FormTypeContentKeeper, FormTypeFamilyZone, FormTypeFortiGate, FormTypeIboss, @@ -70,6 +72,8 @@ export const setup = (props) => { return FormTypeBarracudaNg // break case 'Checkpoint': return FormTypeCheckpoint // break + case 'ContentKeeper': + return FormTypeContentKeeper // break case 'CiscoIsePic': return FormTypeCiscoIsePic // break case 'FamilyZone': diff --git a/html/pfappserver/root/src/views/Configuration/firewalls/config.js b/html/pfappserver/root/src/views/Configuration/firewalls/config.js index 53d9f8bd329f..1ae0dacb25fc 100644 --- a/html/pfappserver/root/src/views/Configuration/firewalls/config.js +++ b/html/pfappserver/root/src/views/Configuration/firewalls/config.js @@ -3,6 +3,7 @@ import i18n from '@/utils/locale' export const types = { BarracudaNG: i18n.t('BarracudaNG'), Checkpoint: i18n.t('Checkpoint'), + ContentKeeper: i18n.t('ContentKeeper'), CiscoIsePic: i18n.t('Cisco ISE-PIC'), FamilyZone: i18n.t('FamilyZone'), FortiGate: i18n.t('FortiGate'), diff --git a/lib/pf/UnifiedApi/Controller/Config/Firewalls.pm b/lib/pf/UnifiedApi/Controller/Config/Firewalls.pm index 14034c32c0ae..63779743efde 100644 --- a/lib/pf/UnifiedApi/Controller/Config/Firewalls.pm +++ b/lib/pf/UnifiedApi/Controller/Config/Firewalls.pm @@ -35,6 +35,7 @@ use pfappserver::Form::Config::Firewall_SSO::LightSpeedRocket; use pfappserver::Form::Config::Firewall_SSO::SmoothWall; use pfappserver::Form::Config::Firewall_SSO::FamilyZone; use pfappserver::Form::Config::Firewall_SSO::CiscoIsePic; +use pfappserver::Form::Config::Firewall_SSO::ContentKeeper; our %TYPES_TO_FORMS = ( map { $_ => "pfappserver::Form::Config::Firewall_SSO::$_" } qw( @@ -50,6 +51,7 @@ our %TYPES_TO_FORMS = ( SmoothWall FamilyZone CiscoIsePic + ContentKeeper ) ); diff --git a/lib/pf/constants/firewallsso.pm b/lib/pf/constants/firewallsso.pm index 13d3a421d613..9d41bfaa2a39 100644 --- a/lib/pf/constants/firewallsso.pm +++ b/lib/pf/constants/firewallsso.pm @@ -36,6 +36,7 @@ Readonly::Scalar our $FIREWALL_TYPES => [ "SmoothWall", "FamilyZone", "CiscoIsePic", + "ContentKeeper", ]; =head1 AUTHOR From 7f041aa88c7956946d083dcc3d8f7a655c21ed6f Mon Sep 17 00:00:00 2001 From: Durand Fabrice Date: Fri, 16 Apr 2021 12:57:59 -0400 Subject: [PATCH 05/88] Renamed FormTypeContentKeeper.js to FormTypeContentKeeper.vue --- .../_components/FormTypeContentKeeper.js | 91 ------------------- 1 file changed, 91 deletions(-) delete mode 100644 html/pfappserver/root/src/views/Configuration/firewalls/_components/FormTypeContentKeeper.js diff --git a/html/pfappserver/root/src/views/Configuration/firewalls/_components/FormTypeContentKeeper.js b/html/pfappserver/root/src/views/Configuration/firewalls/_components/FormTypeContentKeeper.js deleted file mode 100644 index 994c1220799a..000000000000 --- a/html/pfappserver/root/src/views/Configuration/firewalls/_components/FormTypeContentKeeper.js +++ /dev/null @@ -1,91 +0,0 @@ - - From 7a0600e9f0aaa840b1c181073e48d940b8943397 Mon Sep 17 00:00:00 2001 From: Durand Fabrice Date: Fri, 16 Apr 2021 13:29:04 -0400 Subject: [PATCH 06/88] Added file --- .../_components/FormTypeContentKeeper.vue | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 html/pfappserver/root/src/views/Configuration/firewalls/_components/FormTypeContentKeeper.vue diff --git a/html/pfappserver/root/src/views/Configuration/firewalls/_components/FormTypeContentKeeper.vue b/html/pfappserver/root/src/views/Configuration/firewalls/_components/FormTypeContentKeeper.vue new file mode 100644 index 000000000000..994c1220799a --- /dev/null +++ b/html/pfappserver/root/src/views/Configuration/firewalls/_components/FormTypeContentKeeper.vue @@ -0,0 +1,91 @@ + + From 6a7cf67b289d680d6a05f9d30016480ad43ceaf9 Mon Sep 17 00:00:00 2001 From: Julien Semaan Date: Mon, 7 Nov 2022 20:16:22 +0000 Subject: [PATCH 07/88] allow to make the VLAN filters actions synchronous --- .../pfappserver/Form/Config/FilterEngines/VlanFilter.pm | 7 +++++++ .../Configuration/filterEngines/_components/TheForm.vue | 8 ++++++++ .../Configuration/filterEngines/_components/index.js | 1 + lib/pf/access_filter.pm | 7 ++++++- 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/html/pfappserver/lib/pfappserver/Form/Config/FilterEngines/VlanFilter.pm b/html/pfappserver/lib/pfappserver/Form/Config/FilterEngines/VlanFilter.pm index b0e1e1d475ff..ac698d2804c8 100644 --- a/html/pfappserver/lib/pfappserver/Form/Config/FilterEngines/VlanFilter.pm +++ b/html/pfappserver/lib/pfappserver/Form/Config/FilterEngines/VlanFilter.pm @@ -51,6 +51,13 @@ has_field 'run_actions' => ( default => 'enabled' ); +has_field 'actions_synchronous' => ( + type => 'Toggle', + checkbox_value => 'enabled', + unchecked_value => 'disabled', + default => 'disabled' +); + =head2 actions The list of action diff --git a/html/pfappserver/root/src/views/Configuration/filterEngines/_components/TheForm.vue b/html/pfappserver/root/src/views/Configuration/filterEngines/_components/TheForm.vue index 8fb49bf9c4b1..d6a934d1e352 100644 --- a/html/pfappserver/root/src/views/Configuration/filterEngines/_components/TheForm.vue +++ b/html/pfappserver/root/src/views/Configuration/filterEngines/_components/TheForm.vue @@ -40,6 +40,12 @@ :text="$i18n.t('Specify actions to perform when condition is met.')" /> + + {actions}//[]}) { my $param = $self->evalActionParams($action->{'api_parameters'}, $args); - $apiclient->notify($action->{'api_method'}, @{$param}); + if(isenabled($rule->{actions_synchronous})) { + $apiclient->call($action->{'api_method'}, @{$param}); + } + else { + $apiclient->notify($action->{'api_method'}, @{$param}); + } } } } From 1062246727296ffbf107bb7da28bd75b03df1aa7 Mon Sep 17 00:00:00 2001 From: Leon Greeff Date: Tue, 15 Nov 2022 16:00:55 +1300 Subject: [PATCH 08/88] Add support for Unifi OS controllers --- lib/pf/Switch/Ubiquiti/Unifi.pm | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/pf/Switch/Ubiquiti/Unifi.pm b/lib/pf/Switch/Ubiquiti/Unifi.pm index 23db93c6ec23..5a9b817fd011 100644 --- a/lib/pf/Switch/Ubiquiti/Unifi.pm +++ b/lib/pf/Switch/Ubiquiti/Unifi.pm @@ -42,9 +42,6 @@ use Try::Tiny; use JSON::MaybeXS; use pf::config::cluster; -# The port to reach the Unifi controller API -our $UNIFI_API_PORT = "8443"; - sub description { 'Unifi Controller' } =head1 SUBROUTINES @@ -196,17 +193,28 @@ sub _connect { $ua->cookie_jar({ file => "$var_dir/run/.ubiquiti.cookies.txt" }); $ua->ssl_opts(verify_hostname => 0); $ua->timeout(10); + $ua->default_header('Content-Type' => "application/json"); + + my $base_url = "$transport://$controllerIp"; + my $login_path = "/api/login"; + my $api_prefix = ""; + my $response = $ua->get($base_url."/proxy/network/status"); - my $base_url = "$transport://$controllerIp:$UNIFI_API_PORT"; + if ($response->code == 401) { + $login_path = "/api/auth/login"; + $api_prefix = "/proxy/network"; + } else { + $base_url .= ":8443"; + } - my $response = $ua->post("$base_url/api/login", Content => '{"username":"'.$username.'", "password":"'.$password.'"}'); + $response = $ua->post($base_url.$login_path, Content => '{"username":"'.$username.'", "password":"'.$password.'"}'); unless($response->is_success) { $logger->error("Can't login on the Unifi controller: ".$response->status_line); die; } - return ($ua, $base_url); + return ($ua, $base_url.$api_prefix); } From 1f01d3a084c87ae14c58cd9cd6e60082ed389cea Mon Sep 17 00:00:00 2001 From: James Rouzier Date: Wed, 30 Nov 2022 02:34:16 +0000 Subject: [PATCH 09/88] Escape password --- lib/pf/services/manager/radiusd_child.pm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/pf/services/manager/radiusd_child.pm b/lib/pf/services/manager/radiusd_child.pm index c7a7c5ce0ddd..5f59b32db9a2 100644 --- a/lib/pf/services/manager/radiusd_child.pm +++ b/lib/pf/services/manager/radiusd_child.pm @@ -779,7 +779,7 @@ EOT $edir_options = ''; } - if (scalar @{$ConfigAuthenticationLdap{$ldap}->{searchattributes}}) { + if (scalar @{$ConfigAuthenticationLdap{$ldap}->{searchattributes}//[]}) { foreach my $searchattribute (@{$ConfigAuthenticationLdap{$ldap}->{searchattributes}}) { $searchattributes .= '('.$searchattribute.'=%{User-Name})('.$searchattribute.'=%{Stripped-User-Name})'; } @@ -791,6 +791,8 @@ EOT $server_list .= " server = $ldap_server\n"; } my $append = ''; + my $password = $ConfigAuthenticationLdap{$ldap}{password}; + $password =~ s/"/\\"/g; if (defined($ConfigAuthenticationLdap{$ldap}->{append_to_searchattributes})) { $append = $ConfigAuthenticationLdap{$ldap}->{append_to_searchattributes}; } @@ -800,7 +802,7 @@ ldap $ldap { $server_list port = "$ConfigAuthenticationLdap{$ldap}->{port}" identity = "$ConfigAuthenticationLdap{$ldap}->{binddn}" - password = "$ConfigAuthenticationLdap{$ldap}->{password}" + password = "$password" base_dn = "$ConfigAuthenticationLdap{$ldap}->{basedn}" filter = "(userPrincipalName=%{User-Name})" scope = "$ConfigAuthenticationLdap{$ldap}->{scope}" From a2ef9673d04b212c7b0a8f1c61a0bd29a6b9ef3f Mon Sep 17 00:00:00 2001 From: Darren Satkunas Date: Mon, 5 Dec 2022 09:33:26 -0800 Subject: [PATCH 10/88] add pending status to network threats --- .../src/views/Status/network_threats/_api.js | 15 ++++ .../_components/BaseFilterSecurityEvents.vue | 6 +- .../network_threats/_components/TheView.vue | 8 +- .../views/Status/network_threats/_store.js | 73 +++++++++++++------ lib/pf/UnifiedApi.pm | 3 + .../UnifiedApi/Controller/SecurityEvents.pm | 15 ++++ 6 files changed, 96 insertions(+), 24 deletions(-) diff --git a/html/pfappserver/root/src/views/Status/network_threats/_api.js b/html/pfappserver/root/src/views/Status/network_threats/_api.js index 82b89581c9a0..7bc1673068bd 100644 --- a/html/pfappserver/root/src/views/Status/network_threats/_api.js +++ b/html/pfappserver/root/src/views/Status/network_threats/_api.js @@ -16,6 +16,11 @@ export default { return response.data }) }, + totalPending: () => { + return apiCall.get('security_events/total_pending').then(response => { + return response.data + }) + }, perDeviceClassOpen: () => { return apiCall.get('security_events/per_device_class_open').then(response => { return response.data @@ -26,6 +31,11 @@ export default { return response.data }) }, + perDeviceClassPending: () => { + return apiCall.get('security_events/per_device_class_pending').then(response => { + return response.data + }) + }, perSecurityEventOpen: () => { return apiCall.get('security_events/per_security_event_id_open').then(response => { return response.data @@ -36,6 +46,11 @@ export default { return response.data }) }, + perSecurityEventPending: () => { + return apiCall.get('security_events/per_security_event_id_pending').then(response => { + return response.data + }) + }, } diff --git a/html/pfappserver/root/src/views/Status/network_threats/_components/BaseFilterSecurityEvents.vue b/html/pfappserver/root/src/views/Status/network_threats/_components/BaseFilterSecurityEvents.vue index 3ae353df5912..14024a7e06e4 100644 --- a/html/pfappserver/root/src/views/Status/network_threats/_components/BaseFilterSecurityEvents.vue +++ b/html/pfappserver/root/src/views/Status/network_threats/_components/BaseFilterSecurityEvents.vue @@ -40,6 +40,8 @@ variant="danger" class="ml-1">{{ item._open }} {{ $i18n.t('open') }} {{ item._closed }} {{ $i18n.t('closed') }} + {{ item._pending }} {{ $i18n.t('pending') }} @@ -75,6 +77,7 @@ const setup = (props, context) => { const perSecurityEventOpen = computed(() => $store.getters['$_network_threats/perSecurityEventOpen']) const perSecurityEventClosed = computed(() => $store.getters['$_network_threats/perSecurityEventClosed']) + const perSecurityEventPending = computed(() => $store.getters['$_network_threats/perSecurityEventPending']) const items = ref([]) onMounted(() => { @@ -88,8 +91,9 @@ const setup = (props, context) => { const { id } = item const _open = perSecurityEventOpen.value[id] || 0 const _closed = perSecurityEventClosed.value[id] || 0 + const _pending = perSecurityEventPending.value[id] || 0 return { ...item, - _open, _closed } + _open, _closed, _pending } })) const filter = ref('') diff --git a/html/pfappserver/root/src/views/Status/network_threats/_components/TheView.vue b/html/pfappserver/root/src/views/Status/network_threats/_components/TheView.vue index 2d1f1f5ee9c9..907a7bf49691 100644 --- a/html/pfappserver/root/src/views/Status/network_threats/_components/TheView.vue +++ b/html/pfappserver/root/src/views/Status/network_threats/_components/TheView.vue @@ -101,9 +101,12 @@ - + + + + diff --git a/html/pfappserver/root/src/components/new/BaseSystemdUpdate.vue b/html/pfappserver/root/src/components/new/BaseSystemdUpdate.vue new file mode 100644 index 000000000000..a6c7ffa39f05 --- /dev/null +++ b/html/pfappserver/root/src/components/new/BaseSystemdUpdate.vue @@ -0,0 +1,96 @@ + + diff --git a/html/pfappserver/root/src/components/new/index.js b/html/pfappserver/root/src/components/new/index.js index 26f7400be800..4e057d938cc6 100644 --- a/html/pfappserver/root/src/components/new/index.js +++ b/html/pfappserver/root/src/components/new/index.js @@ -7,6 +7,7 @@ import BaseButtonSave from './BaseButtonSave' import BaseButtonSaveSearch from './BaseButtonSaveSearch' import BaseButtonService from './BaseButtonService' import BaseButtonSystemService from './BaseButtonSystemService' +import BaseButtonSystemdUpdate from './BaseButtonSystemdUpdate' import BaseButtonUpload from './BaseButtonUpload' import BaseContainerLoading from './BaseContainerLoading' import BaseCsvImport from './BaseCsvImport' @@ -154,6 +155,7 @@ export { BaseButtonSaveSearch, BaseButtonService, BaseButtonSystemService, + BaseButtonSystemdUpdate, BaseButtonUpload, // containers diff --git a/html/pfappserver/root/src/globals/pfLocales.js b/html/pfappserver/root/src/globals/pfLocales.js index 7b08ac0d9f39..ea01886eecbf 100644 --- a/html/pfappserver/root/src/globals/pfLocales.js +++ b/html/pfappserver/root/src/globals/pfLocales.js @@ -32,4 +32,7 @@ export const localeStrings = { SERVICES_STOPPED_SUCCESS: 'Stopped services {services}.', // i18n defer SERVICES_STOPPED_ERROR: 'Failed to stop services {services}. See the server error logs for more information.', // i18n defer + + SYSTEMD_UPDATED_SUCCESS: 'Updated systemd for {service}.', // i18n defer + SYSTEMD_UPDATED_ERROR: 'Failed to update systemd for {service}. See the server error logs for more information.', // i18n defer } diff --git a/html/pfappserver/root/src/store/modules/cluster.js b/html/pfappserver/root/src/store/modules/cluster.js index af8f22c33b25..26a583addeb7 100644 --- a/html/pfappserver/root/src/store/modules/cluster.js +++ b/html/pfappserver/root/src/store/modules/cluster.js @@ -155,6 +155,7 @@ const types = { RESTARTING: 'restarting', STARTING: 'starting', STOPPING: 'stopping', + UPDATING: 'updating', SUCCESS: 'success', ERROR: 'error' } @@ -227,14 +228,30 @@ const getters = { }, hasAlive: Object.values(state.servers).findIndex(({ services: { [id]: service } }) => service && service.alive && service.pid) > -1, hasDead: Object.values(state.servers).findIndex(({ services: { [id]: service } }) => service && !(service.alive || service.pid)) > -1, - hasEnabled: Object.values(state.servers).findIndex(({ services: { [id]: service } }) => service && service.enabled) > -1, - hasDisabled: Object.values(state.servers).findIndex(({ services: { [id]: service } }) => service && !service.enabled) > -1, - isProtected: !!protectedServices.find(listed => listed === id), } } }, sorted) }, {}) - } + }, + systemdByServer: state => { + return Object.entries(state.servers).reduce((sorted, [server, {systemd = {}}]) => { + return Object.entries(systemd).reduce((sorted, [id, service]) => { + return { + ...sorted, + [id]: { + servers: { + ...((id in sorted) ? sorted[id].servers : {} ), + [server]: { + ...service, + isUpdating: service.status === types.UPDATING, + } + } + } + } + }, sorted) + }, {}) + }, + servers: state => Object.keys(state.servers), } const actions = { @@ -323,7 +340,7 @@ const actions = { disableServiceCluster: ({ state, dispatch }, id) => { return new Promise((resolve, reject) => { dispatch('getConfig').then(() => { - // async requests + // serialize async requests const async = (idx = 0) => { const server = Object.keys(state.servers)[idx] const next = () => { @@ -363,7 +380,7 @@ const actions = { enableServiceCluster: ({ state, dispatch }, id) => { return new Promise((resolve, reject) => { dispatch('getConfig').then(() => { - // async requests + // serialize async requests const async = (idx = 0) => { const server = Object.keys(state.servers)[idx] const next = () => { @@ -403,7 +420,7 @@ const actions = { restartServiceCluster: ({ state, dispatch }, id) => { return new Promise((resolve, reject) => { dispatch('getConfig').then(() => { - // async requests + // serialize async requests const async = (idx = 0) => { const server = Object.keys(state.servers)[idx] const next = () => { @@ -443,7 +460,7 @@ const actions = { startServiceCluster: ({ state, dispatch }, id) => { return new Promise((resolve, reject) => { dispatch('getConfig').then(() => { - // async requests + // serialize async requests const async = (idx = 0) => { const server = Object.keys(state.servers)[idx] const next = () => { @@ -483,7 +500,7 @@ const actions = { stopServiceCluster: ({ state, dispatch }, id) => { return new Promise((resolve, reject) => { dispatch('getConfig').then(() => { - // async requests + // serialize async requests const async = (idx = 0) => { const server = Object.keys(state.servers)[idx] const next = () => { @@ -509,6 +526,7 @@ const actions = { }) }, + getSystemService: ({ state, commit }, { server, id }) => { commit('SYSTEM_SERVICE_REQUEST', { server, id }) return api(state, server).systemService(id).then(service => { @@ -546,6 +564,34 @@ const actions = { throw err }).finally(() => dispatch('getSystemService', { server, id })) }, + restartSystemServiceCluster: ({ state, dispatch }, id) => { + return new Promise((resolve, reject) => { + dispatch('getConfig').then(() => { + // serialize async requests + const async = (idx = 0) => { + const server = Object.keys(state.servers)[idx] + const next = () => { + if (idx < Object.keys(state.servers).length-1) { + async(++idx) + } + else { + resolve() + } + } + const { [server]: { system_services: { [id]: { alive = false, pid = false } = {} } = {} } = {} } = state.servers + if (alive && pid) { + dispatch('restartSystemService', { server, id }) + .catch(err => reject(err)) + .then(() => next()) + } + else { + next() + } + } + async() + }) + }) + }, startSystemService: ({ state, commit, dispatch }, { id, server = store.state.system.hostname }) => { commit('SYSTEM_SERVICE_REQUEST', { server, id }) commit('SYSTEM_SERVICE_STARTING', { server, id }) @@ -558,6 +604,34 @@ const actions = { throw err }).finally(() => dispatch('getSystemService', { server, id })) }, + startSystemServiceCluster: ({ state, dispatch }, id) => { + return new Promise((resolve, reject) => { + dispatch('getConfig').then(() => { + // serialize async requests + const async = (idx = 0) => { + const server = Object.keys(state.servers)[idx] + const next = () => { + if (idx < Object.keys(state.servers).length - 1) { + async(++idx) + } + else { + resolve() + } + } + const { [server]: { system_services: { [id]: { alive = false, pid = false } = {} } = {} } = {} } = state.servers + if (!(alive && pid)) { + dispatch('startSystemService', { server, id }) + .catch(err => reject(err)) + .then(() => next()) + } + else { + next() + } + } + async() + }) + }) + }, stopSystemService: ({ state, commit, dispatch }, { id, server = store.state.system.hostname }) => { commit('SYSTEM_SERVICE_REQUEST', { server, id }) commit('SYSTEM_SERVICE_STOPPING', { server, id }) @@ -570,6 +644,35 @@ const actions = { throw err }).finally(() => dispatch('getSystemService', { server, id })) }, + stopSystemServiceCluster: ({ state, dispatch }, id) => { + return new Promise((resolve, reject) => { + dispatch('getConfig').then(() => { + // serialize async requests + const async = (idx = 0) => { + const server = Object.keys(state.servers)[idx] + const next = () => { + if (idx < Object.keys(state.servers).length - 1) { + async(++idx) + } + else { + resolve() + } + } + const { [server]: { system_services: { [id]: { alive = false, pid = false } = {} } = {} } = {} } = state.servers + if (alive && pid) { + dispatch('stopSystemService', { server, id }) + .catch(err => reject(err)) + .then(() => next()) + } + else { + next() + } + } + async() + }) + }) + }, + updateSystemd: ({ state, commit }, { id, server = store.state.system.hostname }) => { commit('SYSTEMD_REQUEST', { server, id }) @@ -582,6 +685,28 @@ const actions = { throw err }) }, + updateSystemdCluster: ({ state, dispatch }, id) => { + return new Promise((resolve, reject) => { + dispatch('getConfig').then(() => { + // serialize async requests + const async = (idx = 0) => { + const server = Object.keys(state.servers)[idx] + const next = () => { + if (idx < Object.keys(state.servers).length - 1) { + async(++idx) + } + else { + resolve() + } + } + dispatch('updateSystemd', { server, id }) + .catch(err => reject(err)) + .then(() => next()) + } + async() + }) + }) + }, } const mutations = { @@ -593,7 +718,7 @@ const mutations = { }, CONFIG_SUCCESS: (state, items) => { items.map(server => { - Vue.set(state.servers, server.host, { services: {}, system_services: {}, ...state.servers[server.host], ...server }) + Vue.set(state.servers, server.host, { services: {}, system_services: {}, systemd: {}, ...state.servers[server.host], ...server }) }) state.status = types.SUCCESS state.message = '' @@ -625,7 +750,7 @@ const mutations = { SERVICE_REQUEST: (state, { server, id }) => { state.status = types.LOADING - Vue.set(state.servers, server, state.servers[server] || { services: {}, system_services: {} }) + Vue.set(state.servers, server, state.servers[server] || { services: {}, system_services: {}, systemd: {} }) Vue.set(state.servers[server].services, id, state.servers[server].services[id] || {}) Vue.set(state.servers[server].services[id], 'status', types.LOADING) }, @@ -703,7 +828,7 @@ const mutations = { SYSTEM_SERVICE_REQUEST: (state, { server, id }) => { state.status = types.LOADING - Vue.set(state.servers, server, state.servers[server] || { services: {}, system_services: {} }) + Vue.set(state.servers, server, state.servers[server] || { services: {}, system_services: {}, systemd: {} }) Vue.set(state.servers[server].system_services, id, state.servers[server].system_services[id] || {}) Vue.set(state.servers[server].system_services[id], 'status', types.LOADING) }, @@ -746,17 +871,23 @@ const mutations = { Vue.set(state.servers[server].system_services[id], 'status', types.ERROR) }, - SYSTEMD_REQUEST: state => { + SYSTEMD_REQUEST: (state, { server, id }) => { state.status = types.LOADING + Vue.set(state.servers, server, state.servers[server] || { services: {}, system_services: {}, systemd: {} }) + Vue.set(state.servers[server].systemd, id, state.servers[server].systemd[id] || {}) + Vue.set(state.servers[server].systemd[id], 'status', types.UPDATING) }, - SYSTEMD_SUCCESS: state => { + SYSTEMD_SUCCESS: (state, { server, id }) => { state.status = types.SUCCESS state.message = '' + Vue.set(state.servers[server].systemd, id, { ...state.servers[server].systemd[id], status: types.SUCCESS }) }, - SYSTEMD_ERROR: (state, error) => { + SYSTEMD_ERROR: (state, { server, id, error }) => { state.status = types.ERROR state.message = error + Vue.set(state.servers[server].systemd[id], 'status', types.ERROR) }, + $RESET: (state) => { // eslint-disable-next-line no-unused-vars state = initialState() diff --git a/html/pfappserver/root/src/views/Configuration/eventLoggers/_components/TheSearch.vue b/html/pfappserver/root/src/views/Configuration/eventLoggers/_components/TheSearch.vue index a54d35166b55..425830dde0c6 100644 --- a/html/pfappserver/root/src/views/Configuration/eventLoggers/_components/TheSearch.vue +++ b/html/pfappserver/root/src/views/Configuration/eventLoggers/_components/TheSearch.vue @@ -13,6 +13,10 @@ :to="{ name: 'newEventLogger', params: { eventLoggerType: value } }" >{{ text }} + + Date: Fri, 9 Dec 2022 06:04:41 -0800 Subject: [PATCH 15/88] add systemd button to monit and services --- .../Configuration/eventLoggers/_components/TheSearch.vue | 6 ------ .../Configuration/monit/_components/AlertServices.vue | 9 ++++++--- .../src/views/Status/services/_components/TheView.vue | 5 +++++ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/html/pfappserver/root/src/views/Configuration/eventLoggers/_components/TheSearch.vue b/html/pfappserver/root/src/views/Configuration/eventLoggers/_components/TheSearch.vue index 425830dde0c6..9f113f1ff6c0 100644 --- a/html/pfappserver/root/src/views/Configuration/eventLoggers/_components/TheSearch.vue +++ b/html/pfappserver/root/src/views/Configuration/eventLoggers/_components/TheSearch.vue @@ -4,9 +4,6 @@

{{ $t('Event Loggers') }}

-
{{ $t(`Creating, modifying or deleting an event logger entry requires to restart the packetfence-mariadb service using the following command: systemctl restart packetfence-mariadb`) }}
-

+ :disabled="isLoading" class="mr-1" size="sm" /> +