From b6f4e41bfa78c0a622d754d6200a3d909f99f710 Mon Sep 17 00:00:00 2001 From: Tim Shockley Date: Wed, 2 Aug 2023 15:53:10 -0700 Subject: [PATCH 01/29] feat: add local wifi config --- config-wifi.yaml | 25 ++++++++++++++++ internal/config/local.go | 15 ++++++++++ internal/flags/configure.go | 15 ++++++++++ internal/flags/configure_test.go | 16 +++++----- internal/flags/flags_test.go | 2 +- internal/local/configure.go | 50 +++++++++++++++++++++++++------- internal/local/configure_test.go | 28 ++++++++++++++++++ internal/local/lps.go | 3 ++ 8 files changed, 134 insertions(+), 20 deletions(-) create mode 100644 config-wifi.yaml diff --git a/config-wifi.yaml b/config-wifi.yaml new file mode 100644 index 00000000..0103959d --- /dev/null +++ b/config-wifi.yaml @@ -0,0 +1,25 @@ +wifiConfigs: + - priority: 1 + profileName: 'name_1' # friendly name (ex. Profile name) + ssid: 'ssid' + pskPassphrase: '' + authenticationMethod: 5 + encryptionMethod: 4 + clientCert: 'test' + caCert: 'test' + privateKey: 'test' + username: "test" # 8021x username + password: "" # 8021x password if MSCHAP PEAP + authenticationProtocol: 0 #8021x profile (ex. EAP-TLS(0)) + - priority: 2 + profileName: 'name_2' # friendly name (ex. Profile name) + ssid: 'ssid' + pskPassphrase: '' + authenticationMethod: 5 + encryptionMethod: 4 + clientCert: 'test' + caCert: 'test' + privateKey: 'test' + username: "test" # 8021x username + password: "" # 8021x password if MSCHAP PEAP + authenticationProtocol: 0 #8021x profile (ex. EAP-TLS(0)) diff --git a/internal/config/local.go b/internal/config/local.go index c145a1b9..5c118933 100644 --- a/internal/config/local.go +++ b/internal/config/local.go @@ -4,6 +4,7 @@ type ( Config struct { Password string IEEE8021XSettings `yaml:"ieee801xConfig"` + WifiConfigs `yaml:"wifiConfigs"` } IEEE8021XSettings struct { Name string `yaml:"name"` @@ -17,4 +18,18 @@ type ( CACert string `yaml:"caCert"` PrivateKey string `yaml:"privateKey"` } + WifiConfigs []struct { + Priority int `yaml:"priority"` + ProfileName string `yaml:"profileName"` + AuthenticationMethod int `yaml:"authenticationMethod"` + EncryptionMethod int `yaml:"encryptionMethod"` + SSID string `yaml:"ssid"` + PskPassphrase string `yaml:"pskPassphrase"` + Username string `yaml:"username"` + Password string `yaml:"password"` + AuthenticationProtocol int `yaml:"authenticationProtocol"` + ClientCert string `yaml:"clientCert"` + CACert string `yaml:"caCert"` + PrivateKey string `yaml:"privateKey"` + } ) diff --git a/internal/flags/configure.go b/internal/flags/configure.go index 038f9193..60252b57 100644 --- a/internal/flags/configure.go +++ b/internal/flags/configure.go @@ -1,14 +1,29 @@ package flags import ( + "fmt" + "github.com/ilyakaznacheev/cleanenv" + log "github.com/sirupsen/logrus" "rpc/pkg/utils" ) func (f *Flags) handleConfigureCommand() int { + f.amtConfigureCommand.StringVar(&f.configContent, "config", "", "specify a config file ") if err := f.amtConfigureCommand.Parse(f.commandLineArgs[2:]); err != nil { + f.amtConfigureCommand.Usage() return utils.IncorrectCommandLineParameters } // runs locally f.Local = true + if f.configContent == "" { + fmt.Println("-config flag is required and cannot be empty") + return utils.IncorrectCommandLineParameters + } + err := cleanenv.ReadConfig(f.configContent, &f.LocalConfig) + if err != nil { + log.Error("config error: ", err) + return utils.IncorrectCommandLineParameters + } + return utils.Success } diff --git a/internal/flags/configure_test.go b/internal/flags/configure_test.go index 9fca597e..826710d1 100644 --- a/internal/flags/configure_test.go +++ b/internal/flags/configure_test.go @@ -2,18 +2,18 @@ package flags import ( "rpc/pkg/utils" + "strings" "testing" "github.com/stretchr/testify/assert" ) func TestHandleConfigureCommand(t *testing.T) { - f := NewFlags([]string{ - "rpc", - "configure", - }) - - result := f.handleConfigureCommand() - assert.Equal(t, utils.Success, result) - assert.Equal(t, true, f.Local) + cmdLine := "rpc configure --config ../../config-wifi.yaml " + args := strings.Fields(cmdLine) + flags := NewFlags(args) + gotResult := flags.ParseFlags() + assert.Equal(t, flags.Local, true) + assert.Equal(t, utils.Success, gotResult) + assert.Equal(t, utils.CommandConfigure, flags.Command) } diff --git a/internal/flags/flags_test.go b/internal/flags/flags_test.go index 67b44ee3..7925cc91 100644 --- a/internal/flags/flags_test.go +++ b/internal/flags/flags_test.go @@ -220,7 +220,7 @@ func TestParseFlagsVersion(t *testing.T) { assert.Equal(t, false, flags.JsonOutput) } func TestParseFlagsConfigure(t *testing.T) { - args := []string{"./rpc", "configure"} + args := []string{"./rpc", "configure", "-config", "../../config-wifi.yaml"} flags := NewFlags(args) result := flags.ParseFlags() assert.EqualValues(t, result, utils.Success) diff --git a/internal/local/configure.go b/internal/local/configure.go index c90fb5ff..3e284839 100644 --- a/internal/local/configure.go +++ b/internal/local/configure.go @@ -15,19 +15,47 @@ func (service *ProvisioningService) Configure() int { service.setupWsmanClient("admin", service.flags.Password) - resultCode := utils.Success - var err error - switch service.flags.SubCommand { - case utils.SubCommandAddWifiSettings: - err = service.Configure8021xWiFi() - break - default: - resultCode = utils.InvalidParameters + if service.flags.SubCommand == utils.SubCommandAddWifiSettings { + err := service.Configure8021xWiFi() + if err != nil { + return utils.WiFiConfigurationFailed + } } - if err != nil { - resultCode = utils.WiFiConfigurationFailed + if len(service.flags.LocalConfig.WifiConfigs) > 0 { + return service.ConfigureWiFi() + } + return utils.InvalidParameters +} + +func (service *ProvisioningService) ConfigureWiFi() int { + if result := service.EnableWifiOnAMT(); result != utils.Success { + return result } - return resultCode + // loop through the configurations and add them accordingly + fmt.Println("loop through the configurations and add them accordingly") + return utils.Success +} + +func (service *ProvisioningService) EnableWifiOnAMT() int { + + fmt.Println("get the WiFiPortConfigurationService") + // context.xmlMessage = context.amt.WiFiPortConfigurationService.Get() + // wifiPortConfigurationService = post the message + + fmt.Println("if local sync not enable, enable it") + // if wifiPortConfigurationService.localProfileSynchronizationEnabled == 0 { + // wifiPortConfigurationService.localProfileSynchronizationEnabled = 3 + // result = post the message + // check result for errors + // } + + fmt.Println("always turn wifi on") + // Enumeration 32769 - WiFi is enabled in S0 + Sx/AC + // msg = cim.WiFiPort.RequestStateChange(32769) + // result = post the message + // check result for errors + + return utils.Success } func (service *ProvisioningService) Configure8021xWiFi() error { diff --git a/internal/local/configure_test.go b/internal/local/configure_test.go index f8faffa1..a3e5377e 100644 --- a/internal/local/configure_test.go +++ b/internal/local/configure_test.go @@ -183,8 +183,36 @@ func TestAddWifiSettings(t *testing.T) { lps := setupWithWsmanClient(f, handler) err := lps.AddWifiSettings("certHandle", "rootHandle") assert.NotNil(t, err) +} + +func TestConfigureWiFi(t *testing.T) { + f := &flags.Flags{} + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Check the request method and URL path. + assert.Equal(t, "POST", r.Method) + // Return an error response + w.WriteHeader(http.StatusInternalServerError) + }) + + lps := setupWithWsmanClient(f, handler) + err := lps.ConfigureWiFi() + assert.NotNil(t, err) +} + +func TestEnableWifiOnAMT(t *testing.T) { + f := &flags.Flags{} + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Check the request method and URL path. + assert.Equal(t, "POST", r.Method) + // Return an error response + w.WriteHeader(http.StatusInternalServerError) + }) + lps := setupWithWsmanClient(f, handler) + err := lps.EnableWifiOnAMT() + assert.NotNil(t, err) } + func TestRollbackAddedItems(t *testing.T) { f := &flags.Flags{} t.Run("returns no error when rollback is successful", func(t *testing.T) { diff --git a/internal/local/lps.go b/internal/local/lps.go index 08289112..97991fbb 100644 --- a/internal/local/lps.go +++ b/internal/local/lps.go @@ -47,6 +47,9 @@ func ExecuteCommand(flags *flags.Flags) int { case utils.CommandDeactivate: resultCode = service.Deactivate() break + case utils.CommandConfigure: + resultCode = service.Configure() + break case utils.CommandMaintenance: resultCode = service.Configure() break From eddd467da3d090bd478d4c6db193a5334cc49e06 Mon Sep 17 00:00:00 2001 From: Tim Shockley Date: Thu, 3 Aug 2023 11:06:13 -0700 Subject: [PATCH 02/29] feat: normalized config file for wifi and 8021x --- config-wifi.yaml | 32 +++++++++++++++----------------- internal/config/local.go | 15 ++++++++++----- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/config-wifi.yaml b/config-wifi.yaml index 0103959d..9fd6b517 100644 --- a/config-wifi.yaml +++ b/config-wifi.yaml @@ -1,25 +1,23 @@ wifiConfigs: - - priority: 1 - profileName: 'name_1' # friendly name (ex. Profile name) + - profileName: 'wifi-8021x' # friendly name (ex. Profile name) ssid: 'ssid' - pskPassphrase: '' - authenticationMethod: 5 + priority: 1 + authenticationMethod: 6 encryptionMethod: 4 - clientCert: 'test' - caCert: 'test' - privateKey: 'test' - username: "test" # 8021x username - password: "" # 8021x password if MSCHAP PEAP - authenticationProtocol: 0 #8021x profile (ex. EAP-TLS(0)) - - priority: 2 - profileName: 'name_2' # friendly name (ex. Profile name) + pskPassphrase: 'Passw0rd!@#' + ieee8021xProfileName: '' + - profileName: 'wifi-8021x' # friendly name (ex. Profile name) ssid: 'ssid' - pskPassphrase: '' - authenticationMethod: 5 + priority: 2 + authenticationMethod: 7 # WPA IEEE 802.1x encryptionMethod: 4 + pskPassphrase: '' + ieee8021xProfileName: 'profile-01' +ieee8021xConfigs: + - profileName: 'profile-01' + username: "test" # 8021x username + password: "" # 8021x password if authenticationProtocol is PEAPv0/EAP-MSCHAPv2(2) + authenticationProtocol: 0 #8021x profile (ex. EAP-TLS(0)) clientCert: 'test' caCert: 'test' privateKey: 'test' - username: "test" # 8021x username - password: "" # 8021x password if MSCHAP PEAP - authenticationProtocol: 0 #8021x profile (ex. EAP-TLS(0)) diff --git a/internal/config/local.go b/internal/config/local.go index 5c118933..c44b215f 100644 --- a/internal/config/local.go +++ b/internal/config/local.go @@ -5,6 +5,7 @@ type ( Password string IEEE8021XSettings `yaml:"ieee801xConfig"` WifiConfigs `yaml:"wifiConfigs"` + Ieee8021xConfigs `yaml:"ieee8021xConfigs"` } IEEE8021XSettings struct { Name string `yaml:"name"` @@ -19,12 +20,16 @@ type ( PrivateKey string `yaml:"privateKey"` } WifiConfigs []struct { - Priority int `yaml:"priority"` + ProfileName string `yaml:"profileName"` + SSID string `yaml:"ssid"` + Priority int `yaml:"priority"` + AuthenticationMethod int `yaml:"authenticationMethod"` + EncryptionMethod int `yaml:"encryptionMethod"` + PskPassphrase string `yaml:"pskPassphrase"` + Ieee8021xProfileName string `yaml:"ieee8021xProfileName"` + } + Ieee8021xConfigs []struct { ProfileName string `yaml:"profileName"` - AuthenticationMethod int `yaml:"authenticationMethod"` - EncryptionMethod int `yaml:"encryptionMethod"` - SSID string `yaml:"ssid"` - PskPassphrase string `yaml:"pskPassphrase"` Username string `yaml:"username"` Password string `yaml:"password"` AuthenticationProtocol int `yaml:"authenticationProtocol"` From 6fd7a37372f049576c4785ed8dfb3165c5d2ed1c Mon Sep 17 00:00:00 2001 From: Walt Date: Thu, 3 Aug 2023 16:30:12 -0700 Subject: [PATCH 03/29] feat: adds checks for wifi config file --- internal/flags/configure.go | 52 +++++++++++++++++++++++++++++++++++- internal/flags/flags_test.go | 16 +++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/internal/flags/configure.go b/internal/flags/configure.go index 60252b57..18f44f98 100644 --- a/internal/flags/configure.go +++ b/internal/flags/configure.go @@ -2,9 +2,10 @@ package flags import ( "fmt" + "rpc/pkg/utils" + "github.com/ilyakaznacheev/cleanenv" log "github.com/sirupsen/logrus" - "rpc/pkg/utils" ) func (f *Flags) handleConfigureCommand() int { @@ -25,5 +26,54 @@ func (f *Flags) handleConfigureCommand() int { return utils.IncorrectCommandLineParameters } + var matchedIeeeProfileName int = 0 + + for _, wifiConfigs := range f.LocalConfig.WifiConfigs { + //Check profile name is not empty + if wifiConfigs.ProfileName == "" { + log.Error("missing profile name") + return utils.MissingOrIncorrectProfile + } + //Check ssid is not empty + if wifiConfigs.SSID == "" { + log.Error("missing ssid for profile: ", wifiConfigs.ProfileName) + return utils.MissingOrIncorrectProfile + } + //Check priority is not empty + if wifiConfigs.Priority == 0 { + log.Error("missing priority for profile: ", wifiConfigs.ProfileName) + return utils.MissingOrIncorrectProfile + } + //Check authenticationMethod is not empty + if wifiConfigs.AuthenticationMethod == 0 { + log.Error("missing authenticationMethod for profile: ", wifiConfigs.ProfileName) + return utils.MissingOrIncorrectProfile + } + //Check encryptionMethod is not empty + if wifiConfigs.EncryptionMethod == 0 { + log.Error("missing encryptionMethod for profile: ", wifiConfigs.ProfileName) + return utils.MissingOrIncorrectProfile + } + //Check authentication method + if wifiConfigs.AuthenticationMethod == 7 { + //Check for ieee8021xProfileName in IEEE8021XSettings + for _, ieee802xSettings := range f.LocalConfig.Ieee8021xConfigs { + if wifiConfigs.Ieee8021xProfileName == ieee802xSettings.ProfileName { + matchedIeeeProfileName++ + } + fmt.Println("ieee:", ieee802xSettings) + } + //Check if more than on ieee profile name matched. + if matchedIeeeProfileName > 1 { + log.Error("duplicate IEEE802x Profile names") + return utils.MissingOrIncorrectProfile + } + } + if wifiConfigs.AuthenticationMethod != 7 && wifiConfigs.PskPassphrase == "" { + log.Error("wifi configuration missing passphrase: ", wifiConfigs.ProfileName) + return utils.MissingOrIncorrectProfile + } + fmt.Println("wifi: ", wifiConfigs) + } return utils.Success } diff --git a/internal/flags/flags_test.go b/internal/flags/flags_test.go index 7925cc91..c13fc829 100644 --- a/internal/flags/flags_test.go +++ b/internal/flags/flags_test.go @@ -228,6 +228,22 @@ func TestParseFlagsConfigure(t *testing.T) { assert.Equal(t, false, flags.JsonOutput) } +func TestParseFlagsConfigureEmpty(t *testing.T) { + args := []string{"./rpc", "configure"} + flags := NewFlags(args) + result := flags.ParseFlags() + assert.EqualValues(t, result, utils.IncorrectCommandLineParameters) + assert.Equal(t, "configure", flags.Command) +} + +func TestParseFlagsConfigureNoFile(t *testing.T) { + args := []string{"./rpc", "configure", "-config"} + flags := NewFlags(args) + result := flags.ParseFlags() + assert.EqualValues(t, result, utils.IncorrectCommandLineParameters) + assert.Equal(t, "configure", flags.Command) +} + func TestParseFlagsVersionJSON(t *testing.T) { args := []string{"./rpc", "version", "-json"} flags := NewFlags(args) From 6547d9b5e764a387064ab1d93fb70514c0ec4a6f Mon Sep 17 00:00:00 2001 From: Tim Shockley Date: Mon, 7 Aug 2023 10:23:08 -0700 Subject: [PATCH 04/29] feat: implementation and test cases for EnableWifiOnAMT --- go.mod | 2 +- internal/config/local.go | 6 +- internal/local/configure.go | 54 ++++++++++--- internal/local/configure_test.go | 131 +++++++++++++++++++++++-------- internal/local/lps.go | 3 + 5 files changed, 149 insertions(+), 47 deletions(-) diff --git a/go.mod b/go.mod index 139e2149..68641b71 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module rpc go 1.20 // uncomment if developing with go-wsman-messages locally -// replace github.com/open-amt-cloud-toolkit/go-wsman-messages => ../go-wsman-messages +replace github.com/open-amt-cloud-toolkit/go-wsman-messages => ../go-wsman-messages require ( github.com/gorilla/websocket v1.5.0 diff --git a/internal/config/local.go b/internal/config/local.go index c44b215f..bd0fc64f 100644 --- a/internal/config/local.go +++ b/internal/config/local.go @@ -19,7 +19,8 @@ type ( CACert string `yaml:"caCert"` PrivateKey string `yaml:"privateKey"` } - WifiConfigs []struct { + WifiConfigs []WifiConfig + WifiConfig struct { ProfileName string `yaml:"profileName"` SSID string `yaml:"ssid"` Priority int `yaml:"priority"` @@ -28,7 +29,8 @@ type ( PskPassphrase string `yaml:"pskPassphrase"` Ieee8021xProfileName string `yaml:"ieee8021xProfileName"` } - Ieee8021xConfigs []struct { + Ieee8021xConfigs []Ieee8021xConfig + Ieee8021xConfig struct { ProfileName string `yaml:"profileName"` Username string `yaml:"username"` Password string `yaml:"password"` diff --git a/internal/local/configure.go b/internal/local/configure.go index 3e284839..90c929f8 100644 --- a/internal/local/configure.go +++ b/internal/local/configure.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/amt/publickey" + "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/amt/wifiportconfiguration" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim/models" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/common" log "github.com/sirupsen/logrus" @@ -12,7 +13,6 @@ import ( ) func (service *ProvisioningService) Configure() int { - service.setupWsmanClient("admin", service.flags.Password) if service.flags.SubCommand == utils.SubCommandAddWifiSettings { @@ -39,21 +39,53 @@ func (service *ProvisioningService) ConfigureWiFi() int { func (service *ProvisioningService) EnableWifiOnAMT() int { fmt.Println("get the WiFiPortConfigurationService") - // context.xmlMessage = context.amt.WiFiPortConfigurationService.Get() - // wifiPortConfigurationService = post the message + msg := service.amtMessages.WiFiPortConfigurationService.Get() + rsp, err := service.client.Post(msg) + if err != nil { + log.Error(err) + return utils.WiFiConfigurationFailed + } + var wifiPortConfigResponse wifiportconfiguration.Response + err = xml.Unmarshal([]byte(rsp), &wifiPortConfigResponse) + if err != nil { + log.Error(err) + return utils.WiFiConfigurationFailed + } + + pcs := wifiPortConfigResponse.Body.WiFiPortConfigurationService fmt.Println("if local sync not enable, enable it") - // if wifiPortConfigurationService.localProfileSynchronizationEnabled == 0 { - // wifiPortConfigurationService.localProfileSynchronizationEnabled = 3 - // result = post the message - // check result for errors - // } + if pcs.LocalProfileSynchronizationEnabled == wifiportconfiguration.LocalSyncDisabled { + pcs.LocalProfileSynchronizationEnabled = wifiportconfiguration.UnrestrictedSync + msg = service.amtMessages.WiFiPortConfigurationService.Put(pcs) + // not sure why it's accepted to not check the response for success code? this is what RPS does also + // no response struct in wsmang messages + rsp, err = service.client.Post(msg) + if err != nil { + log.Error(err) + return utils.WiFiConfigurationFailed + } + err = xml.Unmarshal([]byte(rsp), &wifiPortConfigResponse) + if err != nil { + log.Error(err) + return utils.WiFiConfigurationFailed + } + pcs = wifiPortConfigResponse.Body.WiFiPortConfigurationService + if pcs.LocalProfileSynchronizationEnabled == 0 { + log.Error("failed to enable wifi local profile synchronization") + return utils.WiFiConfigurationFailed + } + } fmt.Println("always turn wifi on") // Enumeration 32769 - WiFi is enabled in S0 + Sx/AC - // msg = cim.WiFiPort.RequestStateChange(32769) - // result = post the message - // check result for errors + msg = service.cimMessages.WiFiPort.RequestStateChange(32769) + // TODO: no return code checking + _, err = service.client.Post(msg) + if err != nil { + log.Error(err) + return utils.WiFiConfigurationFailed + } return utils.Success } diff --git a/internal/local/configure_test.go b/internal/local/configure_test.go index a3e5377e..befb0368 100644 --- a/internal/local/configure_test.go +++ b/internal/local/configure_test.go @@ -1,9 +1,14 @@ package local import ( + "encoding/xml" "errors" "fmt" + "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/amt/wifiportconfiguration" + "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim/wifi" + "io/ioutil" "net/http" + "rpc/internal/config" "rpc/internal/flags" "rpc/pkg/utils" "strings" @@ -19,25 +24,113 @@ const clientCertXMLResponse = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous0http://intel.com/wbem/wscim/1/amt-schema/1/AMT_PublicKeyManagementlps/AddKeyResponseuuid:00000000-8086-8086-8086-00000003A89Bhttp://intel.com/wbem/wscim/1/amt-schema/1/AMT_PublicKeyManagementlpshttp://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymoushttp://intel.com/wbem/wscim/1/amt-schema/1/AMT_PublicPrivateKeyPairIntel(r) AMT Key: Handle: 00" const addWifiSettingsResponse = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous0http://intel.com/wbem/wscim/1/amt-schema/1/AMT_PublicKeyManagementlps/AddKeyResponseuuid:00000000-8086-8086-8086-00000003A89Bhttp://intel.com/wbem/wscim/1/amt-schema/1/AMT_PublicKeyManagementlpshttp://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymoushttp://intel.com/wbem/wscim/1/amt-schema/1/AMT_PublicPrivateKeyPairIntel(r) AMT Key: Handle: 0a" +var wifiCfgWPA = config.WifiConfig{ + ProfileName: "WPA Wifi Config", + SSID: "testssid", + Priority: 1, + AuthenticationMethod: 4, + EncryptionMethod: 4, + PskPassphrase: "testPassPhrase", + Ieee8021xProfileName: "", +} + +// TODO: remove these when local-acm-activation branch is available in main +func respondServerError(w http.ResponseWriter) { + w.WriteHeader(http.StatusInternalServerError) +} + +func respondBadXml(t *testing.T, w http.ResponseWriter) { + _, err := w.Write([]byte(`not really xml is it?`)) + assert.Nil(t, err) +} + +func respondMsg(t *testing.T, w http.ResponseWriter, msg any) { + bytes, err := xml.Marshal(msg) + assert.Nil(t, err) + _, err = w.Write(bytes) + assert.Nil(t, err) + +} + +func TestXML(t *testing.T) { + pcsResponse := wifiportconfiguration.Response{} + pcsResponse.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled = 15 + data, err := xml.MarshalIndent(pcsResponse, " ", " ") + if err != nil { + fmt.Println(err) + } + err = ioutil.WriteFile("/tmp/rsp.xml", data, 0666) + if err != nil { + fmt.Println(err) + } +} + func TestConfigure(t *testing.T) { f := &flags.Flags{} - f.Command = utils.CommandMaintenance handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "POST", r.Method) - w.WriteHeader(http.StatusInternalServerError) + respondServerError(w) }) - t.Run("returns error when SubCommand is not handled", func(t *testing.T) { - f.SubCommand = "notvalid" + t.Run("returns InvalidParameters with no sub command and not wifi configs", func(t *testing.T) { lps := setupWithWsmanClient(f, handler) resultCode := lps.Configure() assert.Equal(t, utils.InvalidParameters, resultCode) }) - t.Run("returns error when SubCommand is not handled", func(t *testing.T) { + t.Run("returns WiFiConfigurationFailed from err in Configure8021xWiFi", func(t *testing.T) { f.SubCommand = utils.SubCommandAddWifiSettings lps := setupWithWsmanClient(f, handler) resultCode := lps.Configure() assert.Equal(t, utils.WiFiConfigurationFailed, resultCode) }) + t.Run("returns WiFiConfigurationFailed handling WifiConfigs from LocalConfig", func(t *testing.T) { + f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfgWPA) + lps := setupWithWsmanClient(f, handler) + resultCode := lps.Configure() + assert.Equal(t, utils.WiFiConfigurationFailed, resultCode) + }) +} + +func TestConfigureWiFi(t *testing.T) { + f := &flags.Flags{} + + pcsResponse := wifiportconfiguration.Response{} + + t.Run("returns success on happy path", func(t *testing.T) { + count := 0 + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, "POST", r.Method) + count++ + switch count { + case 1: + respondMsg(t, w, pcsResponse) + break + case 2: + pcsResponse.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled = 1 + respondMsg(t, w, pcsResponse) + break + case 3: + respondMsg(t, w, wifi.RequestStateChangeResponse{}) + break + } + }) + lps := setupWithWsmanClient(f, handler) + resultCode := lps.ConfigureWiFi() + assert.Equal(t, utils.Success, resultCode) + }) +} + +func TestEnableWifiOnAMT(t *testing.T) { + f := &flags.Flags{} + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Check the request method and URL path. + assert.Equal(t, "POST", r.Method) + // Return an error response + w.WriteHeader(http.StatusInternalServerError) + }) + + lps := setupWithWsmanClient(f, handler) + err := lps.EnableWifiOnAMT() + assert.NotNil(t, err) } func TestConfigure8021xWiFi(t *testing.T) { @@ -185,34 +278,6 @@ func TestAddWifiSettings(t *testing.T) { assert.NotNil(t, err) } -func TestConfigureWiFi(t *testing.T) { - f := &flags.Flags{} - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Check the request method and URL path. - assert.Equal(t, "POST", r.Method) - // Return an error response - w.WriteHeader(http.StatusInternalServerError) - }) - - lps := setupWithWsmanClient(f, handler) - err := lps.ConfigureWiFi() - assert.NotNil(t, err) -} - -func TestEnableWifiOnAMT(t *testing.T) { - f := &flags.Flags{} - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Check the request method and URL path. - assert.Equal(t, "POST", r.Method) - // Return an error response - w.WriteHeader(http.StatusInternalServerError) - }) - - lps := setupWithWsmanClient(f, handler) - err := lps.EnableWifiOnAMT() - assert.NotNil(t, err) -} - func TestRollbackAddedItems(t *testing.T) { f := &flags.Flags{} t.Run("returns no error when rollback is successful", func(t *testing.T) { diff --git a/internal/local/lps.go b/internal/local/lps.go index 97991fbb..02867be1 100644 --- a/internal/local/lps.go +++ b/internal/local/lps.go @@ -2,6 +2,7 @@ package local import ( "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/amt" + "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/ips" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/wsman" internalAMT "rpc/internal/amt" @@ -17,6 +18,7 @@ type ProvisioningService struct { config *config.Config amtCommand internalAMT.Interface amtMessages amt.Messages + cimMessages cim.Messages ipsMessages ips.Messages } @@ -30,6 +32,7 @@ func NewProvisioningService(flags *flags.Flags) ProvisioningService { config: &flags.LocalConfig, amtCommand: internalAMT.NewAMTCommand(), amtMessages: amt.NewMessages(), + cimMessages: cim.NewMessages(), ipsMessages: ips.NewMessages(), } } From 56ef4258097466ea35010b75d49ca228a61905d4 Mon Sep 17 00:00:00 2001 From: Walt Date: Mon, 7 Aug 2023 16:42:27 -0700 Subject: [PATCH 05/29] feat: WIP adds more unit tests --- internal/flags/configure.go | 20 +++- internal/flags/configure_test.go | 197 +++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+), 4 deletions(-) diff --git a/internal/flags/configure.go b/internal/flags/configure.go index 18f44f98..373640c5 100644 --- a/internal/flags/configure.go +++ b/internal/flags/configure.go @@ -25,7 +25,15 @@ func (f *Flags) handleConfigureCommand() int { log.Error("config error: ", err) return utils.IncorrectCommandLineParameters } + configFileStatus := f.verifyWifiConfigurationFile() + if configFileStatus != 0 { + log.Error("config error: ", err) + return utils.IncorrectCommandLineParameters + } + return utils.Success +} +func (f *Flags) verifyWifiConfigurationFile() int { var matchedIeeeProfileName int = 0 for _, wifiConfigs := range f.LocalConfig.WifiConfigs { @@ -55,6 +63,14 @@ func (f *Flags) handleConfigureCommand() int { return utils.MissingOrIncorrectProfile } //Check authentication method + if wifiConfigs.AuthenticationMethod == 6 && wifiConfigs.PskPassphrase == "" { + log.Error("wifi configuration missing passphrase: ", wifiConfigs.ProfileName) + return utils.MissingOrIncorrectProfile + } + if wifiConfigs.AuthenticationMethod == 7 && wifiConfigs.PskPassphrase != "" { + log.Error("wifi configuration contains passphrase: ", wifiConfigs.ProfileName) + return utils.MissingOrIncorrectProfile + } if wifiConfigs.AuthenticationMethod == 7 { //Check for ieee8021xProfileName in IEEE8021XSettings for _, ieee802xSettings := range f.LocalConfig.Ieee8021xConfigs { @@ -69,10 +85,6 @@ func (f *Flags) handleConfigureCommand() int { return utils.MissingOrIncorrectProfile } } - if wifiConfigs.AuthenticationMethod != 7 && wifiConfigs.PskPassphrase == "" { - log.Error("wifi configuration missing passphrase: ", wifiConfigs.ProfileName) - return utils.MissingOrIncorrectProfile - } fmt.Println("wifi: ", wifiConfigs) } return utils.Success diff --git a/internal/flags/configure_test.go b/internal/flags/configure_test.go index 826710d1..ab472cc3 100644 --- a/internal/flags/configure_test.go +++ b/internal/flags/configure_test.go @@ -1,6 +1,7 @@ package flags import ( + "rpc/internal/config" "rpc/pkg/utils" "strings" "testing" @@ -17,3 +18,199 @@ func TestHandleConfigureCommand(t *testing.T) { assert.Equal(t, utils.Success, gotResult) assert.Equal(t, utils.CommandConfigure, flags.Command) } + +func TestVerifyWifiConfigurationFile(t *testing.T) { + + cases := []struct { + description string + testConfiguration Flags + expected int + }{ + { + description: "Missing ProfileName", + testConfiguration: Flags{ + LocalConfig: config.Config{ + WifiConfigs: config.WifiConfigs{ + { + ProfileName: "", + }, + }, + }, + }, + expected: utils.MissingOrIncorrectProfile, + }, + { + description: "Missing SSID", + testConfiguration: Flags{ + LocalConfig: config.Config{ + WifiConfigs: config.WifiConfigs{ + { + ProfileName: "Test-Profile-1", + SSID: "", + }, + }, + }, + }, + expected: utils.MissingOrIncorrectProfile, + }, + { + description: "Missing Priority", + testConfiguration: Flags{ + LocalConfig: config.Config{ + WifiConfigs: config.WifiConfigs{ + { + ProfileName: "Test-Profile-1", + SSID: "Test-SSID-1", + }, + }, + }, + }, + expected: utils.MissingOrIncorrectProfile, + }, + { + description: "Missing AuthenticationMethod", + testConfiguration: Flags{ + LocalConfig: config.Config{ + WifiConfigs: config.WifiConfigs{ + { + ProfileName: "Test-Profile-1", + SSID: "Test-SSID-1", + Priority: 1, + }, + }, + }, + }, + expected: utils.MissingOrIncorrectProfile, + }, + { + description: "Missing EncryptionMethod", + testConfiguration: Flags{ + LocalConfig: config.Config{ + WifiConfigs: config.WifiConfigs{ + { + ProfileName: "Test-Profile-1", + SSID: "Test-SSID-1", + Priority: 1, + AuthenticationMethod: 6, + }, + }, + }, + }, + expected: utils.MissingOrIncorrectProfile, + }, + { + description: "Missing Passphrase when AuthenticationMethod is 6", + testConfiguration: Flags{ + LocalConfig: config.Config{ + WifiConfigs: config.WifiConfigs{ + { + ProfileName: "Test-Profile-1", + SSID: "Test-SSID-1", + Priority: 1, + AuthenticationMethod: 6, + EncryptionMethod: 4, + }, + }, + }, + }, + expected: utils.MissingOrIncorrectProfile, + }, + { + description: "Properly formed config", + testConfiguration: Flags{ + LocalConfig: config.Config{ + WifiConfigs: config.WifiConfigs{ + { + ProfileName: "Test-Profile-1", + SSID: "Test-SSID-1", + Priority: 1, + AuthenticationMethod: 6, + EncryptionMethod: 4, + PskPassphrase: "Test-Passphrase-1", + Ieee8021xProfileName: "", + }, + }, + }, + }, + expected: utils.Success, + }, + { + description: "Passphrase present when AuthenticationMethod is 7", + testConfiguration: Flags{ + LocalConfig: config.Config{ + WifiConfigs: config.WifiConfigs{ + { + ProfileName: "Test-Profile-1", + SSID: "Test-SSID-1", + Priority: 1, + AuthenticationMethod: 7, + EncryptionMethod: 4, + PskPassphrase: "Test-Passphrase-1", + }, + }, + }, + }, + expected: utils.MissingOrIncorrectProfile, + }, + { + description: "Successfully matches IEEE802.1 ProfileName", + testConfiguration: Flags{ + LocalConfig: config.Config{ + WifiConfigs: config.WifiConfigs{ + { + ProfileName: "Test-Profile-1", + SSID: "Test-SSID-1", + Priority: 1, + AuthenticationMethod: 7, + EncryptionMethod: 4, + PskPassphrase: "", + Ieee8021xProfileName: "Test-IEEE-Profile", + }, + }, + Ieee8021xConfigs: config.Ieee8021xConfigs{ + { + ProfileName: "Test-IEEE-Profile", + }, + }, + }, + }, + expected: utils.Success, + }, + { + description: "Found duplicate IEEE802.1 ProfileName", + testConfiguration: Flags{ + LocalConfig: config.Config{ + WifiConfigs: config.WifiConfigs{ + { + ProfileName: "Test-Profile-1", + SSID: "Test-SSID-1", + Priority: 1, + AuthenticationMethod: 7, + EncryptionMethod: 4, + PskPassphrase: "", + Ieee8021xProfileName: "Test-IEEE-Profile", + }, + }, + Ieee8021xConfigs: config.Ieee8021xConfigs{ + { + ProfileName: "Test-IEEE-Profile", + }, + { + ProfileName: "Test-IEEE-Profile", + }, + }, + }, + }, + expected: utils.MissingOrIncorrectProfile, + }, + } + + for _, tt := range cases { + t.Run(tt.description, func(t *testing.T) { + gotResult := tt.testConfiguration.verifyWifiConfigurationFile() + if gotResult != tt.expected { + t.Errorf("expected %d but got %d", tt.expected, gotResult) + } + }) + } +} From b9820861e2618bf2c29fd0b94583b97bcf5676a8 Mon Sep 17 00:00:00 2001 From: Walt Date: Thu, 10 Aug 2023 11:13:58 -0700 Subject: [PATCH 06/29] feat: adds subcommand addwifisettings and tests --- internal/flags/configure.go | 48 +++++++++++++++---------- internal/flags/configure_test.go | 62 ++++++++++++++++++++++++++++++-- internal/flags/flags.go | 2 ++ 3 files changed, 92 insertions(+), 20 deletions(-) diff --git a/internal/flags/configure.go b/internal/flags/configure.go index 373640c5..cc853d02 100644 --- a/internal/flags/configure.go +++ b/internal/flags/configure.go @@ -10,25 +10,30 @@ import ( func (f *Flags) handleConfigureCommand() int { f.amtConfigureCommand.StringVar(&f.configContent, "config", "", "specify a config file ") - if err := f.amtConfigureCommand.Parse(f.commandLineArgs[2:]); err != nil { + if err := f.amtConfigureAddWiFiSettingsCommand.Parse(f.commandLineArgs[2:]); err != nil { f.amtConfigureCommand.Usage() return utils.IncorrectCommandLineParameters } // runs locally f.Local = true - if f.configContent == "" { - fmt.Println("-config flag is required and cannot be empty") - return utils.IncorrectCommandLineParameters - } - err := cleanenv.ReadConfig(f.configContent, &f.LocalConfig) - if err != nil { - log.Error("config error: ", err) - return utils.IncorrectCommandLineParameters - } - configFileStatus := f.verifyWifiConfigurationFile() - if configFileStatus != 0 { - log.Error("config error: ", err) - return utils.IncorrectCommandLineParameters + + f.SubCommand = f.commandLineArgs[2] + switch f.SubCommand { + case "addwifisettings": + if f.configContent == "" { + fmt.Println("-config flag is required and cannot be empty") + return utils.IncorrectCommandLineParameters + } + err := cleanenv.ReadConfig(f.configContent, &f.LocalConfig) + if err != nil { + log.Error("config error: ", err) + return utils.IncorrectCommandLineParameters + } + configFileStatus := f.verifyWifiConfigurationFile() + if configFileStatus != 0 { + log.Error("config error: ", err) + return utils.IncorrectCommandLineParameters + } } return utils.Success } @@ -67,17 +72,17 @@ func (f *Flags) verifyWifiConfigurationFile() int { log.Error("wifi configuration missing passphrase: ", wifiConfigs.ProfileName) return utils.MissingOrIncorrectProfile } - if wifiConfigs.AuthenticationMethod == 7 && wifiConfigs.PskPassphrase != "" { + if (wifiConfigs.AuthenticationMethod == 5 || wifiConfigs.AuthenticationMethod == 7) && wifiConfigs.PskPassphrase != "" { log.Error("wifi configuration contains passphrase: ", wifiConfigs.ProfileName) return utils.MissingOrIncorrectProfile } - if wifiConfigs.AuthenticationMethod == 7 { + if wifiConfigs.AuthenticationMethod == 5 || wifiConfigs.AuthenticationMethod == 7 { //Check for ieee8021xProfileName in IEEE8021XSettings for _, ieee802xSettings := range f.LocalConfig.Ieee8021xConfigs { if wifiConfigs.Ieee8021xProfileName == ieee802xSettings.ProfileName { matchedIeeeProfileName++ } - fmt.Println("ieee:", ieee802xSettings) + // fmt.Println("ieee:", ieee802xSettings) } //Check if more than on ieee profile name matched. if matchedIeeeProfileName > 1 { @@ -85,7 +90,14 @@ func (f *Flags) verifyWifiConfigurationFile() int { return utils.MissingOrIncorrectProfile } } - fmt.Println("wifi: ", wifiConfigs) + // fmt.Println("wifi: ", wifiConfigs) + } + for _, ieee8021xConfigs := range f.LocalConfig.Ieee8021xConfigs { + //Check profile name is not empty in IEEE802.1x config + if ieee8021xConfigs.ProfileName == "" { + log.Error("missing profile name in IEEE802.1x config") + return utils.MissingOrIncorrectProfile + } } return utils.Success } diff --git a/internal/flags/configure_test.go b/internal/flags/configure_test.go index ab472cc3..d822e6c7 100644 --- a/internal/flags/configure_test.go +++ b/internal/flags/configure_test.go @@ -10,7 +10,7 @@ import ( ) func TestHandleConfigureCommand(t *testing.T) { - cmdLine := "rpc configure --config ../../config-wifi.yaml " + cmdLine := "rpc configure addwifisettings --config ../../config-wifi.yaml " args := strings.Fields(cmdLine) flags := NewFlags(args) gotResult := flags.ParseFlags() @@ -134,6 +134,24 @@ func TestVerifyWifiConfigurationFile(t *testing.T) { }, expected: utils.Success, }, + { + description: "Passphrase present when AuthenticationMethod is 5", + testConfiguration: Flags{ + LocalConfig: config.Config{ + WifiConfigs: config.WifiConfigs{ + { + ProfileName: "Test-Profile-1", + SSID: "Test-SSID-1", + Priority: 1, + AuthenticationMethod: 5, + EncryptionMethod: 4, + PskPassphrase: "Test-Passphrase-1", + }, + }, + }, + }, + expected: utils.MissingOrIncorrectProfile, + }, { description: "Passphrase present when AuthenticationMethod is 7", testConfiguration: Flags{ @@ -177,7 +195,34 @@ func TestVerifyWifiConfigurationFile(t *testing.T) { expected: utils.Success, }, { - description: "Found duplicate IEEE802.1 ProfileName", + description: "Found duplicate IEEE802.1 ProfileName when AuthenticationMethod is 5", + testConfiguration: Flags{ + LocalConfig: config.Config{ + WifiConfigs: config.WifiConfigs{ + { + ProfileName: "Test-Profile-1", + SSID: "Test-SSID-1", + Priority: 1, + AuthenticationMethod: 7, + EncryptionMethod: 4, + PskPassphrase: "", + Ieee8021xProfileName: "Test-IEEE-Profile", + }, + }, + Ieee8021xConfigs: config.Ieee8021xConfigs{ + { + ProfileName: "Test-IEEE-Profile", + }, + { + ProfileName: "Test-IEEE-Profile", + }, + }, + }, + }, + expected: utils.MissingOrIncorrectProfile, + }, + { + description: "Found duplicate IEEE802.1 ProfileName when AuthenticationMethod is 7", testConfiguration: Flags{ LocalConfig: config.Config{ WifiConfigs: config.WifiConfigs{ @@ -203,6 +248,19 @@ func TestVerifyWifiConfigurationFile(t *testing.T) { }, expected: utils.MissingOrIncorrectProfile, }, + { + description: "Missing ProfileName in IEEE802.1x config", + testConfiguration: Flags{ + LocalConfig: config.Config{ + Ieee8021xConfigs: config.Ieee8021xConfigs{ + { + ProfileName: "", + }, + }, + }, + }, + expected: utils.MissingOrIncorrectProfile, + }, } for _, tt := range cases { diff --git a/internal/flags/flags.go b/internal/flags/flags.go index cdae4073..8e6a09c6 100644 --- a/internal/flags/flags.go +++ b/internal/flags/flags.go @@ -76,6 +76,7 @@ type Flags struct { amtMaintenanceChangePasswordCommand *flag.FlagSet versionCommand *flag.FlagSet amtConfigureCommand *flag.FlagSet + amtConfigureAddWiFiSettingsCommand *flag.FlagSet amtCommand amt.AMTCommand netEnumerator NetEnumerator IpConfiguration IPConfiguration @@ -106,6 +107,7 @@ func NewFlags(args []string) *Flags { flags.amtConfigureCommand = flag.NewFlagSet(utils.CommandConfigure, flag.ContinueOnError) flags.amtConfigureCommand.BoolVar(&flags.JsonOutput, "json", false, "json output") + flags.amtConfigureAddWiFiSettingsCommand = flag.NewFlagSet("addwifisettings", flag.ContinueOnError) flags.amtCommand = amt.NewAMTCommand() flags.netEnumerator = NetEnumerator{} From 1341f751f58743d2c30efc44f052a8dc3db92727 Mon Sep 17 00:00:00 2001 From: Tim Shockley Date: Tue, 8 Aug 2023 11:18:36 -0700 Subject: [PATCH 07/29] feat: refactored main flow --- internal/local/configure.go | 335 +++++++++++-------- internal/local/configure_test.go | 548 +++++++++++++++---------------- 2 files changed, 454 insertions(+), 429 deletions(-) diff --git a/internal/local/configure.go b/internal/local/configure.go index 90c929f8..5a4bf5d5 100644 --- a/internal/local/configure.go +++ b/internal/local/configure.go @@ -7,20 +7,22 @@ import ( "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/amt/publickey" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/amt/wifiportconfiguration" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim/models" + "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim/wifi" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/common" log "github.com/sirupsen/logrus" + "rpc/internal/config" "rpc/pkg/utils" ) func (service *ProvisioningService) Configure() int { service.setupWsmanClient("admin", service.flags.Password) - if service.flags.SubCommand == utils.SubCommandAddWifiSettings { - err := service.Configure8021xWiFi() - if err != nil { - return utils.WiFiConfigurationFailed - } - } + //if service.flags.SubCommand == utils.SubCommandAddWifiSettings { + // err := service.Configure8021xWiFi() + // if err != nil { + // return utils.WiFiConfigurationFailed + // } + //} if len(service.flags.LocalConfig.WifiConfigs) > 0 { return service.ConfigureWiFi() } @@ -28,236 +30,279 @@ func (service *ProvisioningService) Configure() int { } func (service *ProvisioningService) ConfigureWiFi() int { - if result := service.EnableWifiOnAMT(); result != utils.Success { - return result + err := service.EnableWifi() + if err != nil { + log.Error(err) + return utils.WiFiConfigurationFailed + } + lc := service.flags.LocalConfig + var successes []string + var failures []string + for _, cfg := range lc.WifiConfigs { + err = service.ProcessWifiConfig(&cfg) + if err != nil { + log.Error("failed configuring: ", cfg.ProfileName, " ", err) + failures = append(failures, cfg.ProfileName) + } else { + log.Info("successfully configured ", cfg.ProfileName) + successes = append(successes, cfg.ProfileName) + } + } + if len(failures) > 0 { + // TODO: return the new warnings code + return utils.WiFiConfigurationFailed } - // loop through the configurations and add them accordingly - fmt.Println("loop through the configurations and add them accordingly") return utils.Success } -func (service *ProvisioningService) EnableWifiOnAMT() int { +func (service *ProvisioningService) ProcessWifiConfig(wifiCfg *config.WifiConfig) error { - fmt.Println("get the WiFiPortConfigurationService") - msg := service.amtMessages.WiFiPortConfigurationService.Get() - rsp, err := service.client.Post(msg) + wiFiEndpointSettings := models.WiFiEndpointSettings{ + ElementName: wifiCfg.ProfileName, + InstanceID: fmt.Sprintf("Intel(r) AMT:WiFi Endpoint Settings %s", wifiCfg.ProfileName), + SSID: wifiCfg.SSID, + Priority: wifiCfg.Priority, + AuthenticationMethod: models.AuthenticationMethod(wifiCfg.AuthenticationMethod), + EncryptionMethod: models.EncryptionMethod(wifiCfg.EncryptionMethod), + } + var ieee8021xSettings *models.IEEE8021xSettings + handles := Handles{} + + if wiFiEndpointSettings.AuthenticationMethod == models.AuthenticationMethod_WPA_IEEE8021x || + wiFiEndpointSettings.AuthenticationMethod == models.AuthenticationMethod_WPA2_IEEE8021x { + + ieee8021xSettings = &models.IEEE8021xSettings{} + err := service.ProcessIeee8012xConfig(wifiCfg.Ieee8021xProfileName, ieee8021xSettings, &handles) + if err != nil { + service.RollbackAddedItems(&handles) + return err + } + + } + xmlMsg := service.amtMessages.WiFiPortConfigurationService.AddWiFiSettings( + wiFiEndpointSettings, + ieee8021xSettings, + "WiFi Endpoint 0", + handles.clientCertHandle, + handles.rootCertHandle) + xmlRsp, err := service.client.Post(xmlMsg) if err != nil { - log.Error(err) - return utils.WiFiConfigurationFailed + service.RollbackAddedItems(&handles) + return err } - var wifiPortConfigResponse wifiportconfiguration.Response - err = xml.Unmarshal([]byte(rsp), &wifiPortConfigResponse) + var addWifiSettingsRsp wifiportconfiguration.AddWiFiSettingsResponse + err = xml.Unmarshal(xmlRsp, &addWifiSettingsRsp) if err != nil { - log.Error(err) - return utils.WiFiConfigurationFailed + service.RollbackAddedItems(&handles) + return err + } + returnValue := addWifiSettingsRsp.Body.AddWiFiSettings_OUTPUT.ReturnValue + if returnValue != 0 { + return fmt.Errorf("AddWiFiSettings_OUTPUT.ReturnValue: %d", returnValue) } + return nil +} - pcs := wifiPortConfigResponse.Body.WiFiPortConfigurationService +func (service *ProvisioningService) ProcessIeee8012xConfig(profileName string, settings *models.IEEE8021xSettings, handles *Handles) error { - fmt.Println("if local sync not enable, enable it") - if pcs.LocalProfileSynchronizationEnabled == wifiportconfiguration.LocalSyncDisabled { - pcs.LocalProfileSynchronizationEnabled = wifiportconfiguration.UnrestrictedSync - msg = service.amtMessages.WiFiPortConfigurationService.Put(pcs) - // not sure why it's accepted to not check the response for success code? this is what RPS does also - // no response struct in wsmang messages - rsp, err = service.client.Post(msg) - if err != nil { - log.Error(err) - return utils.WiFiConfigurationFailed - } - err = xml.Unmarshal([]byte(rsp), &wifiPortConfigResponse) - if err != nil { - log.Error(err) - return utils.WiFiConfigurationFailed - } - pcs = wifiPortConfigResponse.Body.WiFiPortConfigurationService - if pcs.LocalProfileSynchronizationEnabled == 0 { - log.Error("failed to enable wifi local profile synchronization") - return utils.WiFiConfigurationFailed + // find the matching configuration + var ieee8021xConfig *config.Ieee8021xConfig + for _, curCfg := range service.flags.LocalConfig.Ieee8021xConfigs { + if curCfg.ProfileName == profileName { + ieee8021xConfig = &curCfg } } - - fmt.Println("always turn wifi on") - // Enumeration 32769 - WiFi is enabled in S0 + Sx/AC - msg = service.cimMessages.WiFiPort.RequestStateChange(32769) - // TODO: no return code checking - _, err = service.client.Post(msg) - if err != nil { - log.Error(err) - return utils.WiFiConfigurationFailed + if ieee8021xConfig == nil { + errMsg := fmt.Sprintf("missing Ieee8021xConfig %s", profileName) + return errors.New(errMsg) } - return utils.Success -} + // translate from configuration to settings + settings.ElementName = ieee8021xConfig.ProfileName + settings.InstanceID = fmt.Sprintf("Intel(r) AMT: 8021X Settings %s", ieee8021xConfig.ProfileName) + settings.AuthenticationProtocol = models.AuthenticationProtocol(ieee8021xConfig.AuthenticationProtocol) + settings.Username = ieee8021xConfig.Username + if settings.AuthenticationProtocol == models.AuthenticationProtocolPEAPv0_EAPMSCHAPv2 { + settings.Password = ieee8021xConfig.Password + } -func (service *ProvisioningService) Configure8021xWiFi() error { - privateKeyHandle, err := service.AddPrivateKey() + // add key and certs + var err error + handles.privateKeyHandle, err = service.AddPrivateKey(ieee8021xConfig.PrivateKey) if err != nil { return err } - - certHandle, err := service.AddClientCert() + handles.clientCertHandle, err = service.AddClientCert(ieee8021xConfig.ClientCert) if err != nil { return err } - - rootHandle, err := service.AddTrustedRootCert() + handles.rootCertHandle, err = service.AddTrustedRootCert(ieee8021xConfig.CACert) if err != nil { return err } + return nil +} - err = service.AddWifiSettings(certHandle, rootHandle) +func (service *ProvisioningService) EnableWifi() error { + xmlMsg := service.amtMessages.WiFiPortConfigurationService.Get() + xmlRsp, err := service.client.Post(xmlMsg) if err != nil { - log.Error("error adding wifi settings", err) - err = service.RollbackAddedItems(certHandle, rootHandle, privateKeyHandle) - if err != nil { - log.Error("error rolling back added certificates", err) - } return err } - return nil -} + var wifiPortConfigResponse wifiportconfiguration.PortConfigurationResponse + err = xml.Unmarshal(xmlRsp, &wifiPortConfigResponse) + if err != nil { + return err + } + + // pcs := wifiPortConfigResponse.Body.WiFiPortConfigurationService -func (service *ProvisioningService) AddWifiSettings(certHandle string, rootHandle string) error { - wifiEndpointSettings := models.WiFiEndpointSettings{ - ElementName: service.config.Name, - InstanceID: fmt.Sprintf("Intel(r) AMT:WiFi Endpoint Settings %s", service.config.Name), - SSID: service.config.SSID, - Priority: service.config.Priority, - AuthenticationMethod: models.AuthenticationMethod(service.config.AuthenticationMethod), - EncryptionMethod: models.EncryptionMethod(service.config.EncryptionMethod), - } - ieee8021xSettings := &models.IEEE8021xSettings{ - ElementName: service.config.Name, - InstanceID: fmt.Sprintf("Intel(r) AMT: 8021X Settings %s", service.config.Name), - AuthenticationProtocol: models.AuthenticationProtocol(service.config.AuthenticationProtocol), - Username: service.config.Username, + // if local sync not enable, enable it + if wifiPortConfigResponse.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled == wifiportconfiguration.LocalSyncDisabled { + wifiPortConfigResponse.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled = wifiportconfiguration.UnrestrictedSync + xmlMsg = service.amtMessages.WiFiPortConfigurationService.Put(wifiPortConfigResponse.Body.WiFiPortConfigurationService) + // not sure why it's accepted to not check the response for success code? this is what RPS does also + // no response struct in wsmang messages + xmlRsp, err = service.client.Post(xmlMsg) + if err != nil { + return err + } + err = xml.Unmarshal(xmlRsp, &wifiPortConfigResponse) + if err != nil { + return err + } + //pcs = wifiPortConfigResponse.Body.WiFiPortConfigurationService + if wifiPortConfigResponse.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled == 0 { + return errors.New("failed to enable wifi local profile synchronization") + } } - addWiFiSettingsMessage := service.amtMessages.WiFiPortConfigurationService.AddWiFiSettings(wifiEndpointSettings, ieee8021xSettings, "WiFi Endpoint 0", certHandle, rootHandle) - addWiFiSettingsResponse, err := service.client.Post(addWiFiSettingsMessage) + // always turn wifi on via state change request + // Enumeration 32769 - WiFi is enabled in S0 + Sx/AC + xmlMsg = service.cimMessages.WiFiPort.RequestStateChange(32769) + xmlRsp, err = service.client.Post(xmlMsg) if err != nil { return err } - var gs publickey.Response - err = xml.Unmarshal([]byte(addWiFiSettingsResponse), &gs) + var stateChangeRsp wifi.RequestStateChangeResponse + err = xml.Unmarshal(xmlRsp, &stateChangeRsp) if err != nil { return err } + returnValue := stateChangeRsp.Body.RequestStateChange_OUTPUT.ReturnValue + if returnValue != 0 { + return fmt.Errorf("AddWiFiSettings_OUTPUT.ReturnValue: %d", returnValue) + } + return nil } -func (service *ProvisioningService) RollbackAddedItems(certHandle, rootHandle, privateKeyHandle string) error { + +type Handles struct { + privateKeyHandle string + clientCertHandle string + rootCertHandle string +} + +func (service *ProvisioningService) RollbackAddedItems(handles *Handles) { log.Debug("rolling back added keys and certificates") - if privateKeyHandle != "" { - deleteMessage := service.amtMessages.PublicPrivateKeyPair.Delete(privateKeyHandle) + if handles.privateKeyHandle != "" { + deleteMessage := service.amtMessages.PublicPrivateKeyPair.Delete(handles.privateKeyHandle) _, err := service.client.Post(deleteMessage) if err != nil { - return err + log.Error(err) + } else { + log.Debug("successfully deleted private key") } - log.Debug("successfully removed private key") } - if certHandle != "" { - deleteMessage := service.amtMessages.PublicKeyCertificate.Delete(certHandle) + if handles.clientCertHandle != "" { + deleteMessage := service.amtMessages.PublicKeyCertificate.Delete(handles.clientCertHandle) _, err := service.client.Post(deleteMessage) if err != nil { - return err + log.Error(err) + } else { + log.Debug("successfully deleted client certificate") } - log.Debug("successfully removed client certificate") } - if rootHandle != "" { - deleteMessage := service.amtMessages.PublicKeyCertificate.Delete(rootHandle) + if handles.rootCertHandle != "" { + deleteMessage := service.amtMessages.PublicKeyCertificate.Delete(handles.rootCertHandle) _, err := service.client.Post(deleteMessage) if err != nil { - return err + log.Error(err) + } else { + log.Debug("successfully deleted root certificate") } - log.Debug("successfully removed trusted root certificate") } - - return nil } -func (service *ProvisioningService) AddTrustedRootCert() (string, error) { - var gs publickey.Response - addRootCertMessage := service.amtMessages.PublicKeyManagementService.AddTrustedRootCertificate(service.config.CACert) - caCertResponse, err := service.client.Post(addRootCertMessage) + +func (service *ProvisioningService) AddTrustedRootCert(caCert string) (string, error) { + xmlMsg := service.amtMessages.PublicKeyManagementService.AddTrustedRootCertificate(caCert) + xmlRsp, err := service.client.Post(xmlMsg) if err != nil { return "", err } - err = xml.Unmarshal([]byte(caCertResponse), &gs) + var pkResponse publickey.Response + err = xml.Unmarshal(xmlRsp, &pkResponse) if err != nil { - fmt.Println(err) return "", err } - fmt.Println(string(caCertResponse)) - - shouldReturn, err := checkReturnValue(gs.Body.AddTrustedRootCertificate_OUTPUT.ReturnValue, "root certificate") - if shouldReturn { + err = checkReturnValue(pkResponse.Body.AddTrustedRootCertificate_OUTPUT.ReturnValue, "root certificate") + if err != nil { return "", err } - - rootHandle := gs.Body.AddTrustedRootCertificate_OUTPUT.CreatedCertificate.ReferenceParameters.SelectorSet.Selector[0].Value - - return rootHandle, nil + handle := pkResponse.Body.AddTrustedRootCertificate_OUTPUT.CreatedCertificate.ReferenceParameters.SelectorSet.Selector[0].Value + return handle, nil } -func (service *ProvisioningService) AddClientCert() (string, error) { - addCertMessage := service.amtMessages.PublicKeyManagementService.AddCertificate(service.config.ClientCert) - clientCertResponse, err := service.client.Post(addCertMessage) +func (service *ProvisioningService) AddClientCert(clientCert string) (string, error) { + xmlMsg := service.amtMessages.PublicKeyManagementService.AddCertificate(clientCert) + xmlRsp, err := service.client.Post(xmlMsg) if err != nil { return "", err } - - var gs publickey.Response - err = xml.Unmarshal([]byte(clientCertResponse), &gs) + var pkResponse publickey.Response + err = xml.Unmarshal(xmlRsp, &pkResponse) if err != nil { - fmt.Println(err) return "", err } - - shouldReturn, err := checkReturnValue(gs.Body.AddTrustedCertificate_OUTPUT.ReturnValue, "client certificate") - if shouldReturn { + err = checkReturnValue(pkResponse.Body.AddTrustedCertificate_OUTPUT.ReturnValue, "client certificate") + if err != nil { return "", err } - certHandle := gs.Body.AddTrustedCertificate_OUTPUT.CreatedCertificate.ReferenceParameters.SelectorSet.Selector[0].Value - return certHandle, nil + handle := pkResponse.Body.AddTrustedCertificate_OUTPUT.CreatedCertificate.ReferenceParameters.SelectorSet.Selector[0].Value + return handle, nil } -func (service *ProvisioningService) AddPrivateKey() (handle string, err error) { - message := service.amtMessages.PublicKeyManagementService.AddKey([]byte(service.config.PrivateKey)) - addKeyOutput, err := service.client.Post(message) +func (service *ProvisioningService) AddPrivateKey(privateKey string) (string, error) { + xmlMsg := service.amtMessages.PublicKeyManagementService.AddKey([]byte(privateKey)) + xmlRsp, err := service.client.Post(xmlMsg) if err != nil { - fmt.Println(err) return "", err } - - var addKeyOutputStuff publickey.Response - err = xml.Unmarshal([]byte(addKeyOutput), &addKeyOutputStuff) + var pkResponse publickey.Response + err = xml.Unmarshal(xmlRsp, &pkResponse) if err != nil { - fmt.Println(err) return "", err } - fmt.Println(string(addKeyOutput)) - shouldReturn, err := checkReturnValue(addKeyOutputStuff.Body.AddKey_OUTPUT.ReturnValue, "private key") - if shouldReturn { + err = checkReturnValue(pkResponse.Body.AddKey_OUTPUT.ReturnValue, "private key") + if err != nil { return "", err } - privateKeyHandle := addKeyOutputStuff.Body.AddKey_OUTPUT.CreatedKey.ReferenceParameters.SelectorSet.Selector[0].Value - - return privateKeyHandle, nil + handle := pkResponse.Body.AddKey_OUTPUT.CreatedKey.ReferenceParameters.SelectorSet.Selector[0].Value + return handle, nil } -func checkReturnValue(returnValue int, item string) (bool, error) { +func checkReturnValue(returnValue int, item string) error { if returnValue != 0 { if returnValue == common.PT_STATUS_DUPLICATE { - fmt.Printf("%s already exists", item) - return true, errors.New("item already exists. You must remove it manually before continuing") + return errors.New("item already exists. You must remove it manually before continuing") } else if returnValue == common.PT_STATUS_INVALID_CERT { - return true, fmt.Errorf("%s invalid cert", item) + return fmt.Errorf("%s invalid cert", item) } else { - return true, fmt.Errorf("non-zero return code: %d", returnValue) + return fmt.Errorf("non-zero return code: %d", returnValue) } } - return false, nil + return nil } diff --git a/internal/local/configure_test.go b/internal/local/configure_test.go index befb0368..65fdcd20 100644 --- a/internal/local/configure_test.go +++ b/internal/local/configure_test.go @@ -6,12 +6,10 @@ import ( "fmt" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/amt/wifiportconfiguration" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim/wifi" - "io/ioutil" "net/http" "rpc/internal/config" "rpc/internal/flags" "rpc/pkg/utils" - "strings" "testing" "github.com/stretchr/testify/assert" @@ -52,19 +50,6 @@ func respondMsg(t *testing.T, w http.ResponseWriter, msg any) { } -func TestXML(t *testing.T) { - pcsResponse := wifiportconfiguration.Response{} - pcsResponse.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled = 15 - data, err := xml.MarshalIndent(pcsResponse, " ", " ") - if err != nil { - fmt.Println(err) - } - err = ioutil.WriteFile("/tmp/rsp.xml", data, 0666) - if err != nil { - fmt.Println(err) - } -} - func TestConfigure(t *testing.T) { f := &flags.Flags{} handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -76,12 +61,12 @@ func TestConfigure(t *testing.T) { resultCode := lps.Configure() assert.Equal(t, utils.InvalidParameters, resultCode) }) - t.Run("returns WiFiConfigurationFailed from err in Configure8021xWiFi", func(t *testing.T) { - f.SubCommand = utils.SubCommandAddWifiSettings - lps := setupWithWsmanClient(f, handler) - resultCode := lps.Configure() - assert.Equal(t, utils.WiFiConfigurationFailed, resultCode) - }) + //t.Run("returns WiFiConfigurationFailed from err in Configure8021xWiFi", func(t *testing.T) { + // f.SubCommand = utils.SubCommandAddWifiSettings + // lps := setupWithWsmanClient(f, handler) + // resultCode := lps.Configure() + // assert.Equal(t, utils.WiFiConfigurationFailed, resultCode) + //}) t.Run("returns WiFiConfigurationFailed handling WifiConfigs from LocalConfig", func(t *testing.T) { f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfgWPA) lps := setupWithWsmanClient(f, handler) @@ -93,7 +78,7 @@ func TestConfigure(t *testing.T) { func TestConfigureWiFi(t *testing.T) { f := &flags.Flags{} - pcsResponse := wifiportconfiguration.Response{} + pcsResponse := wifiportconfiguration.PortConfigurationResponse{} t.Run("returns success on happy path", func(t *testing.T) { count := 0 @@ -119,152 +104,7 @@ func TestConfigureWiFi(t *testing.T) { }) } -func TestEnableWifiOnAMT(t *testing.T) { - f := &flags.Flags{} - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Check the request method and URL path. - assert.Equal(t, "POST", r.Method) - // Return an error response - w.WriteHeader(http.StatusInternalServerError) - }) - - lps := setupWithWsmanClient(f, handler) - err := lps.EnableWifiOnAMT() - assert.NotNil(t, err) -} - -func TestConfigure8021xWiFi(t *testing.T) { - f := &flags.Flags{} - t.Run("returns error when AddPrivateKey fails", func(t *testing.T) { - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "POST", r.Method) - w.WriteHeader(http.StatusInternalServerError) - }) - lps := setupWithWsmanClient(f, handler) - err := lps.Configure8021xWiFi() - assert.NotNil(t, err) - }) - - t.Run("returns error when AddClientCert fails", func(t *testing.T) { - calls := 0 - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Simulate AddPrivateKey success and AddClientCert failure - if calls == 0 { - calls++ - assert.Equal(t, "POST", r.Method) - _, err := w.Write([]byte(addKeyXMLResponse)) - assert.Nil(t, err) - - } else { - assert.Equal(t, "POST", r.Method) - w.WriteHeader(http.StatusInternalServerError) - } - }) - - lps := setupWithWsmanClient(f, handler) - err := lps.Configure8021xWiFi() - assert.NotNil(t, err) - }) - - t.Run("returns error when AddTrustedRootCert fails", func(t *testing.T) { - calls := 0 - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Simulate AddPrivateKey and AddClientCert success and AddTrustedRootCert failure - if calls == 0 { - calls++ - assert.Equal(t, "POST", r.Method) - _, err := w.Write([]byte(addKeyXMLResponse)) - assert.Nil(t, err) - } else if calls == 1 { - calls++ - assert.Equal(t, "POST", r.Method) - _, err := w.Write([]byte(clientCertXMLResponse)) - assert.Nil(t, err) - } else { - assert.Equal(t, "POST", r.Method) - w.WriteHeader(http.StatusInternalServerError) - } - }) - - lps := setupWithWsmanClient(f, handler) - err := lps.Configure8021xWiFi() - assert.NotNil(t, err) - }) - - t.Run("returns error when AddWifiSettings fails", func(t *testing.T) { - calls := 0 - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Simulate AddPrivateKey and AddClientCert success and AddTrustedRootCert failure - if calls == 0 { - calls++ - assert.Equal(t, "POST", r.Method) - _, err := w.Write([]byte(addKeyXMLResponse)) - assert.Nil(t, err) - } else if calls == 1 { - calls++ - assert.Equal(t, "POST", r.Method) - _, err := w.Write([]byte(clientCertXMLResponse)) - assert.Nil(t, err) - } else if calls == 2 { - calls++ - assert.Equal(t, "POST", r.Method) - _, err := w.Write([]byte(trustedRootXMLResponse)) - assert.Nil(t, err) - } else { - assert.Equal(t, "POST", r.Method) - w.WriteHeader(http.StatusInternalServerError) - } - }) - - lps := setupWithWsmanClient(f, handler) - err := lps.Configure8021xWiFi() - assert.NotNil(t, err) - }) - - t.Run("returns error when RollbackAddedItems fails", func(t *testing.T) { - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Simulate all steps before RollbackAddedItems success and RollbackAddedItems failure - if strings.Contains(r.URL.Path, "RollbackAddedItems") { - assert.Equal(t, "POST", r.Method) - w.WriteHeader(http.StatusInternalServerError) - } else if strings.Contains(r.URL.Path, "WifiSettings") { - w.WriteHeader(http.StatusInternalServerError) - } else { - w.WriteHeader(http.StatusOK) - } - }) - - lps := setupWithWsmanClient(f, handler) - err := lps.Configure8021xWiFi() - assert.NotNil(t, err) - }) - - t.Run("returns nil on happy path", func(t *testing.T) { - calls := 0 - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "POST", r.Method) - var err error - // Simulate AddPrivateKey and AddClientCert success and AddTrustedRootCert failure - if calls == 0 { - _, err = w.Write([]byte(addKeyXMLResponse)) - } else if calls == 1 { - _, err = w.Write([]byte(clientCertXMLResponse)) - } else if calls == 2 { - _, err = w.Write([]byte(trustedRootXMLResponse)) - } else { - _, err = w.Write([]byte(addWifiSettingsResponse)) - } - assert.Nil(t, err) - calls++ - }) - - lps := setupWithWsmanClient(f, handler) - err := lps.Configure8021xWiFi() - assert.Nil(t, err) - }) -} - -func TestAddWifiSettings(t *testing.T) { +func TestEnableWifi(t *testing.T) { f := &flags.Flags{} handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Check the request method and URL path. @@ -274,136 +114,276 @@ func TestAddWifiSettings(t *testing.T) { }) lps := setupWithWsmanClient(f, handler) - err := lps.AddWifiSettings("certHandle", "rootHandle") + err := lps.EnableWifi() assert.NotNil(t, err) } -func TestRollbackAddedItems(t *testing.T) { - f := &flags.Flags{} - t.Run("returns no error when rollback is successful", func(t *testing.T) { - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "POST", r.Method) - w.WriteHeader(http.StatusOK) - }) - - lps := setupWithWsmanClient(f, handler) - err := lps.RollbackAddedItems("certHandle", "rootHandle", "privateKeyHandle") - assert.Nil(t, err) - }) - - t.Run("returns error when server returns non-200 status code", func(t *testing.T) { - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "POST", r.Method) - w.WriteHeader(http.StatusInternalServerError) - }) - - lps := setupWithWsmanClient(f, handler) - err := lps.RollbackAddedItems("certHandle", "rootHandle", "privateKeyHandle") - assert.NotNil(t, err) - }) -} - -func TestAddTrustedRootCert(t *testing.T) { - f := &flags.Flags{} - t.Run("returns handle when adding cert is successful", func(t *testing.T) { - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "POST", r.Method) - _, err := w.Write([]byte(trustedRootXMLResponse)) - assert.Nil(t, err) - }) - - lps := setupWithWsmanClient(f, handler) - handle, err := lps.AddTrustedRootCert() - assert.Nil(t, err) - assert.NotEmpty(t, handle) - }) - - t.Run("returns error when server returns non-200 status code", func(t *testing.T) { - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "POST", r.Method) - w.WriteHeader(http.StatusInternalServerError) - }) - - lps := setupWithWsmanClient(f, handler) - _, err := lps.AddTrustedRootCert() - assert.NotNil(t, err) - }) -} - -func TestAddClientCert(t *testing.T) { - f := &flags.Flags{} - t.Run("returns handle when adding cert is successful", func(t *testing.T) { - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "POST", r.Method) - _, err := w.Write([]byte(clientCertXMLResponse)) - assert.Nil(t, err) - }) - - lps := setupWithWsmanClient(f, handler) - handle, err := lps.AddClientCert() - assert.Nil(t, err) - assert.NotEmpty(t, handle) - }) - - t.Run("returns error when server returns non-200 status code", func(t *testing.T) { - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "POST", r.Method) - w.WriteHeader(http.StatusInternalServerError) - }) - - lps := setupWithWsmanClient(f, handler) - _, err := lps.AddClientCert() - assert.NotNil(t, err) - }) -} - -func TestAddPrivateKey(t *testing.T) { - f := &flags.Flags{} - t.Run("returns handle when adding cert is successful", func(t *testing.T) { - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "POST", r.Method) - _, err := w.Write([]byte(addKeyXMLResponse)) - assert.Nil(t, err) - }) - - lps := setupWithWsmanClient(f, handler) - handle, err := lps.AddPrivateKey() - assert.Nil(t, err) - assert.NotEmpty(t, handle) - }) - - t.Run("returns error when server returns non-200 status code", func(t *testing.T) { - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "POST", r.Method) - w.WriteHeader(http.StatusInternalServerError) - }) - - lps := setupWithWsmanClient(f, handler) - _, err := lps.AddPrivateKey() - assert.NotNil(t, err) - }) -} +//func TestConfigure8021xWiFi(t *testing.T) { +// f := &flags.Flags{} +// t.Run("returns error when AddPrivateKey fails", func(t *testing.T) { +// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, "POST", r.Method) +// w.WriteHeader(http.StatusInternalServerError) +// }) +// lps := setupWithWsmanClient(f, handler) +// err := lps.Configure8021xWiFi() +// assert.NotNil(t, err) +// }) +// +// t.Run("returns error when AddClientCert fails", func(t *testing.T) { +// calls := 0 +// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// // Simulate AddPrivateKey success and AddClientCert failure +// if calls == 0 { +// calls++ +// assert.Equal(t, "POST", r.Method) +// _, err := w.Write([]byte(addKeyXMLResponse)) +// assert.Nil(t, err) +// +// } else { +// assert.Equal(t, "POST", r.Method) +// w.WriteHeader(http.StatusInternalServerError) +// } +// }) +// +// lps := setupWithWsmanClient(f, handler) +// err := lps.Configure8021xWiFi() +// assert.NotNil(t, err) +// }) +// +// t.Run("returns error when AddTrustedRootCert fails", func(t *testing.T) { +// calls := 0 +// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// // Simulate AddPrivateKey and AddClientCert success and AddTrustedRootCert failure +// if calls == 0 { +// calls++ +// assert.Equal(t, "POST", r.Method) +// _, err := w.Write([]byte(addKeyXMLResponse)) +// assert.Nil(t, err) +// } else if calls == 1 { +// calls++ +// assert.Equal(t, "POST", r.Method) +// _, err := w.Write([]byte(clientCertXMLResponse)) +// assert.Nil(t, err) +// } else { +// assert.Equal(t, "POST", r.Method) +// w.WriteHeader(http.StatusInternalServerError) +// } +// }) +// +// lps := setupWithWsmanClient(f, handler) +// err := lps.Configure8021xWiFi() +// assert.NotNil(t, err) +// }) +// +// t.Run("returns error when AddWifiSettings fails", func(t *testing.T) { +// calls := 0 +// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// // Simulate AddPrivateKey and AddClientCert success and AddTrustedRootCert failure +// if calls == 0 { +// calls++ +// assert.Equal(t, "POST", r.Method) +// _, err := w.Write([]byte(addKeyXMLResponse)) +// assert.Nil(t, err) +// } else if calls == 1 { +// calls++ +// assert.Equal(t, "POST", r.Method) +// _, err := w.Write([]byte(clientCertXMLResponse)) +// assert.Nil(t, err) +// } else if calls == 2 { +// calls++ +// assert.Equal(t, "POST", r.Method) +// _, err := w.Write([]byte(trustedRootXMLResponse)) +// assert.Nil(t, err) +// } else { +// assert.Equal(t, "POST", r.Method) +// w.WriteHeader(http.StatusInternalServerError) +// } +// }) +// +// lps := setupWithWsmanClient(f, handler) +// err := lps.Configure8021xWiFi() +// assert.NotNil(t, err) +// }) +// +// t.Run("returns error when RollbackAddedItems fails", func(t *testing.T) { +// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// // Simulate all steps before RollbackAddedItems success and RollbackAddedItems failure +// if strings.Contains(r.URL.Path, "RollbackAddedItems") { +// assert.Equal(t, "POST", r.Method) +// w.WriteHeader(http.StatusInternalServerError) +// } else if strings.Contains(r.URL.Path, "WifiSettings") { +// w.WriteHeader(http.StatusInternalServerError) +// } else { +// w.WriteHeader(http.StatusOK) +// } +// }) +// +// lps := setupWithWsmanClient(f, handler) +// err := lps.Configure8021xWiFi() +// assert.NotNil(t, err) +// }) +// +// t.Run("returns nil on happy path", func(t *testing.T) { +// calls := 0 +// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, "POST", r.Method) +// var err error +// // Simulate AddPrivateKey and AddClientCert success and AddTrustedRootCert failure +// if calls == 0 { +// _, err = w.Write([]byte(addKeyXMLResponse)) +// } else if calls == 1 { +// _, err = w.Write([]byte(clientCertXMLResponse)) +// } else if calls == 2 { +// _, err = w.Write([]byte(trustedRootXMLResponse)) +// } else { +// _, err = w.Write([]byte(addWifiSettingsResponse)) +// } +// assert.Nil(t, err) +// calls++ +// }) +// +// lps := setupWithWsmanClient(f, handler) +// err := lps.Configure8021xWiFi() +// assert.Nil(t, err) +// }) +//} +// +//func TestAddWifiSettings(t *testing.T) { +// f := &flags.Flags{} +// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// // Check the request method and URL path. +// assert.Equal(t, "POST", r.Method) +// // Return an error response +// w.WriteHeader(http.StatusInternalServerError) +// }) +// +// lps := setupWithWsmanClient(f, handler) +// err := lps.AddWifiSettings("certHandle", "rootHandle") +// assert.NotNil(t, err) +//} + +//func TestRollbackAddedItems(t *testing.T) { +// f := &flags.Flags{} +// t.Run("returns no error when rollback is successful", func(t *testing.T) { +// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, "POST", r.Method) +// w.WriteHeader(http.StatusOK) +// }) +// +// lps := setupWithWsmanClient(f, handler) +// err := lps.RollbackAddedItems("certHandle", "rootHandle", "privateKeyHandle") +// assert.Nil(t, err) +// }) +// +// t.Run("returns error when server returns non-200 status code", func(t *testing.T) { +// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, "POST", r.Method) +// w.WriteHeader(http.StatusInternalServerError) +// }) +// +// lps := setupWithWsmanClient(f, handler) +// err := lps.RollbackAddedItems("certHandle", "rootHandle", "privateKeyHandle") +// assert.NotNil(t, err) +// }) +//} + +// func TestAddTrustedRootCert(t *testing.T) { +// f := &flags.Flags{} +// t.Run("returns handle when adding cert is successful", func(t *testing.T) { +// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, "POST", r.Method) +// _, err := w.Write([]byte(trustedRootXMLResponse)) +// assert.Nil(t, err) +// }) +// +// lps := setupWithWsmanClient(f, handler) +// handle, err := lps.AddTrustedRootCert() +// assert.Nil(t, err) +// assert.NotEmpty(t, handle) +// }) +// +// t.Run("returns error when server returns non-200 status code", func(t *testing.T) { +// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, "POST", r.Method) +// w.WriteHeader(http.StatusInternalServerError) +// }) +// +// lps := setupWithWsmanClient(f, handler) +// _, err := lps.AddTrustedRootCert() +// assert.NotNil(t, err) +// }) +// } +// +// func TestAddClientCert(t *testing.T) { +// f := &flags.Flags{} +// t.Run("returns handle when adding cert is successful", func(t *testing.T) { +// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, "POST", r.Method) +// _, err := w.Write([]byte(clientCertXMLResponse)) +// assert.Nil(t, err) +// }) +// +// lps := setupWithWsmanClient(f, handler) +// handle, err := lps.AddClientCert() +// assert.Nil(t, err) +// assert.NotEmpty(t, handle) +// }) +// +// t.Run("returns error when server returns non-200 status code", func(t *testing.T) { +// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, "POST", r.Method) +// w.WriteHeader(http.StatusInternalServerError) +// }) +// +// lps := setupWithWsmanClient(f, handler) +// _, err := lps.AddClientCert() +// assert.NotNil(t, err) +// }) +// } +// +// func TestAddPrivateKey(t *testing.T) { +// f := &flags.Flags{} +// t.Run("returns handle when adding cert is successful", func(t *testing.T) { +// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, "POST", r.Method) +// _, err := w.Write([]byte(addKeyXMLResponse)) +// assert.Nil(t, err) +// }) +// +// lps := setupWithWsmanClient(f, handler) +// handle, err := lps.AddPrivateKey() +// assert.Nil(t, err) +// assert.NotEmpty(t, handle) +// }) +// +// t.Run("returns error when server returns non-200 status code", func(t *testing.T) { +// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// assert.Equal(t, "POST", r.Method) +// w.WriteHeader(http.StatusInternalServerError) +// }) +// +// lps := setupWithWsmanClient(f, handler) +// _, err := lps.AddPrivateKey() +// assert.NotNil(t, err) +// }) +// } func TestCheckReturnValue(t *testing.T) { tests := []struct { name string in int item string - want bool wantErr error }{ - {"TestNoError", 0, "item", false, nil}, - {"TestAlreadyExists", common.PT_STATUS_DUPLICATE, "item", true, errors.New("item already exists. You must remove it manually before continuing")}, - {"TestInvalidItem", common.PT_STATUS_INVALID_CERT, "item", true, fmt.Errorf("%s invalid cert", "item")}, - {"TestNonZeroReturnCode", 9999, "item", true, fmt.Errorf("non-zero return code: %d", 9999)}, + {"TestNoError", 0, "item", nil}, + {"TestAlreadyExists", common.PT_STATUS_DUPLICATE, "item", errors.New("item already exists. You must remove it manually before continuing")}, + {"TestInvalidItem", common.PT_STATUS_INVALID_CERT, "item", fmt.Errorf("%s invalid cert", "item")}, + {"TestNonZeroReturnCode", 9999, "item", fmt.Errorf("non-zero return code: %d", 9999)}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, gotErr := checkReturnValue(tt.in, tt.item) - - if got != tt.want { - t.Errorf("got %v, want %v", got, tt.want) - } + gotErr := checkReturnValue(tt.in, tt.item) if (gotErr != nil && tt.wantErr == nil) || (gotErr == nil && tt.wantErr != nil) || (gotErr != nil && tt.wantErr != nil && gotErr.Error() != tt.wantErr.Error()) { t.Errorf("gotErr %v, wantErr %v", gotErr, tt.wantErr) From dfff4be48280fb33b33fd659c3f333e056c1badf Mon Sep 17 00:00:00 2001 From: Tim Shockley Date: Fri, 11 Aug 2023 10:00:17 -0700 Subject: [PATCH 08/29] feat: adjusted flags for password and config file --- internal/flags/configure.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/internal/flags/configure.go b/internal/flags/configure.go index cc853d02..2100a7b9 100644 --- a/internal/flags/configure.go +++ b/internal/flags/configure.go @@ -9,11 +9,16 @@ import ( ) func (f *Flags) handleConfigureCommand() int { + f.amtConfigureCommand.StringVar(&f.Password, "password", f.lookupEnvOrString("AMT_PASSWORD", ""), "AMT password") f.amtConfigureCommand.StringVar(&f.configContent, "config", "", "specify a config file ") - if err := f.amtConfigureAddWiFiSettingsCommand.Parse(f.commandLineArgs[2:]); err != nil { + if err := f.amtConfigureCommand.Parse(f.commandLineArgs[3:]); err != nil { f.amtConfigureCommand.Usage() return utils.IncorrectCommandLineParameters } + //if err := f.amtConfigureAddWiFiSettingsCommand.Parse(f.commandLineArgs[2:]); err != nil { + // f.amtConfigureCommand.Usage() + // return utils.IncorrectCommandLineParameters + //} // runs locally f.Local = true From 8670e277b38de207f7f72cfd678fe81f03193523 Mon Sep 17 00:00:00 2001 From: Tim Shockley Date: Fri, 11 Aug 2023 13:34:30 -0700 Subject: [PATCH 09/29] fix: added check in local/configure for profile name alphanum only --- internal/local/configure.go | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/internal/local/configure.go b/internal/local/configure.go index 5a4bf5d5..1e793e1d 100644 --- a/internal/local/configure.go +++ b/internal/local/configure.go @@ -10,6 +10,7 @@ import ( "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim/wifi" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/common" log "github.com/sirupsen/logrus" + "regexp" "rpc/internal/config" "rpc/pkg/utils" ) @@ -39,12 +40,14 @@ func (service *ProvisioningService) ConfigureWiFi() int { var successes []string var failures []string for _, cfg := range lc.WifiConfigs { + log.Info("configuring wifi profile: ", cfg.ProfileName) err = service.ProcessWifiConfig(&cfg) if err != nil { - log.Error("failed configuring: ", cfg.ProfileName, " ", err) + log.Error("failed configuring: ", cfg.ProfileName) + log.Error(err) failures = append(failures, cfg.ProfileName) } else { - log.Info("successfully configured ", cfg.ProfileName) + log.Info("successfully configured: ", cfg.ProfileName) successes = append(successes, cfg.ProfileName) } } @@ -57,6 +60,12 @@ func (service *ProvisioningService) ConfigureWiFi() int { func (service *ProvisioningService) ProcessWifiConfig(wifiCfg *config.WifiConfig) error { + // profile names can only be alphanumeric (not even dashes) + var reAlphaNum = regexp.MustCompile("[^a-zA-Z0-9]+") + if reAlphaNum.MatchString(wifiCfg.ProfileName) { + return fmt.Errorf("invalid wifi profile name: %s (only alphanumeric allowed)", wifiCfg.ProfileName) + } + wiFiEndpointSettings := models.WiFiEndpointSettings{ ElementName: wifiCfg.ProfileName, InstanceID: fmt.Sprintf("Intel(r) AMT:WiFi Endpoint Settings %s", wifiCfg.ProfileName), @@ -78,6 +87,8 @@ func (service *ProvisioningService) ProcessWifiConfig(wifiCfg *config.WifiConfig return err } + } else { + wiFiEndpointSettings.PSKPassPhrase = wifiCfg.PskPassphrase } xmlMsg := service.amtMessages.WiFiPortConfigurationService.AddWiFiSettings( wiFiEndpointSettings, @@ -297,11 +308,11 @@ func (service *ProvisioningService) AddPrivateKey(privateKey string) (string, er func checkReturnValue(returnValue int, item string) error { if returnValue != 0 { if returnValue == common.PT_STATUS_DUPLICATE { - return errors.New("item already exists. You must remove it manually before continuing") + return fmt.Errorf("%s already exists and must be removed before continuing", item) } else if returnValue == common.PT_STATUS_INVALID_CERT { - return fmt.Errorf("%s invalid cert", item) + return fmt.Errorf("%s is invalid", item) } else { - return fmt.Errorf("non-zero return code: %d", returnValue) + return fmt.Errorf("%s non-zero return code: %d", item, returnValue) } } return nil From 125ecf2c05e45267b05c311ce9064f40cb6285df Mon Sep 17 00:00:00 2001 From: Tim Shockley Date: Mon, 14 Aug 2023 12:44:37 -0700 Subject: [PATCH 10/29] feat: local/configure unit test completed --- internal/local/configure.go | 5 +- internal/local/configure_test.go | 747 ++++++++++++++++++------------- 2 files changed, 437 insertions(+), 315 deletions(-) diff --git a/internal/local/configure.go b/internal/local/configure.go index 1e793e1d..ddf77f2a 100644 --- a/internal/local/configure.go +++ b/internal/local/configure.go @@ -109,6 +109,7 @@ func (service *ProvisioningService) ProcessWifiConfig(wifiCfg *config.WifiConfig } returnValue := addWifiSettingsRsp.Body.AddWiFiSettings_OUTPUT.ReturnValue if returnValue != 0 { + service.RollbackAddedItems(&handles) return fmt.Errorf("AddWiFiSettings_OUTPUT.ReturnValue: %d", returnValue) } return nil @@ -166,8 +167,6 @@ func (service *ProvisioningService) EnableWifi() error { return err } - // pcs := wifiPortConfigResponse.Body.WiFiPortConfigurationService - // if local sync not enable, enable it if wifiPortConfigResponse.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled == wifiportconfiguration.LocalSyncDisabled { wifiPortConfigResponse.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled = wifiportconfiguration.UnrestrictedSync @@ -182,7 +181,7 @@ func (service *ProvisioningService) EnableWifi() error { if err != nil { return err } - //pcs = wifiPortConfigResponse.Body.WiFiPortConfigurationService + if wifiPortConfigResponse.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled == 0 { return errors.New("failed to enable wifi local profile synchronization") } diff --git a/internal/local/configure_test.go b/internal/local/configure_test.go index 65fdcd20..75a6f298 100644 --- a/internal/local/configure_test.go +++ b/internal/local/configure_test.go @@ -2,14 +2,15 @@ package local import ( "encoding/xml" - "errors" "fmt" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/amt/wifiportconfiguration" + "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim/models" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim/wifi" "net/http" "rpc/internal/config" "rpc/internal/flags" "rpc/pkg/utils" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -23,53 +24,119 @@ const addKeyXMLResponse = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous0http://intel.com/wbem/wscim/1/amt-schema/1/AMT_PublicKeyManagementlps/AddKeyResponseuuid:00000000-8086-8086-8086-00000003A89Bhttp://intel.com/wbem/wscim/1/amt-schema/1/AMT_PublicKeyManagementlpshttp://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymoushttp://intel.com/wbem/wscim/1/amt-schema/1/AMT_PublicPrivateKeyPairIntel(r) AMT Key: Handle: 0a" var wifiCfgWPA = config.WifiConfig{ - ProfileName: "WPA Wifi Config", - SSID: "testssid", + ProfileName: "wifiWPA", + SSID: "ssid", Priority: 1, - AuthenticationMethod: 4, - EncryptionMethod: 4, - PskPassphrase: "testPassPhrase", + AuthenticationMethod: int(models.AuthenticationMethod_WPA_PSK), + EncryptionMethod: int(models.EncryptionMethod_CCMP), + PskPassphrase: "wifiWPAPassPhrase", Ieee8021xProfileName: "", } -// TODO: remove these when local-acm-activation branch is available in main -func respondServerError(w http.ResponseWriter) { - w.WriteHeader(http.StatusInternalServerError) +var wifiCfgWPA2 = config.WifiConfig{ + ProfileName: "wifiWPA2", + SSID: "ssid", + Priority: 2, + AuthenticationMethod: int(models.AuthenticationMethod_WPA2_PSK), + EncryptionMethod: int(models.EncryptionMethod_CCMP), + PskPassphrase: "wifiWPAPassPhrase", + Ieee8021xProfileName: "", } -func respondBadXml(t *testing.T, w http.ResponseWriter) { - _, err := w.Write([]byte(`not really xml is it?`)) - assert.Nil(t, err) +var wifiCfgWPA8021xEAPTLS = config.WifiConfig{ + ProfileName: "wifiWPA28021x", + SSID: "ssid", + Priority: 2, + AuthenticationMethod: int(models.AuthenticationMethod_WPA_IEEE8021x), + EncryptionMethod: int(models.EncryptionMethod_CCMP), + PskPassphrase: "", + Ieee8021xProfileName: "ieee8021xCfgEAPTLS", } -func respondMsg(t *testing.T, w http.ResponseWriter, msg any) { - bytes, err := xml.Marshal(msg) - assert.Nil(t, err) - _, err = w.Write(bytes) - assert.Nil(t, err) +var ieee8021xCfgEAPTLS = config.Ieee8021xConfig{ + ProfileName: "ieee8021xCfgEAPTLS", + Username: "username", + Password: "", + AuthenticationProtocol: int(models.AuthenticationProtocolEAPTLS), + ClientCert: "clientCert", + CACert: "caCert", + PrivateKey: "privateKey", +} +var wifiCfgWPA28021xPEAPv0_EAPMSCHAPv2 = config.WifiConfig{ + ProfileName: "wifiWPA28021x", + SSID: "ssid", + Priority: 2, + AuthenticationMethod: int(models.AuthenticationMethod_WPA2_IEEE8021x), + EncryptionMethod: int(models.EncryptionMethod_CCMP), + PskPassphrase: "", + Ieee8021xProfileName: "ieee8021xCfgPEAPv0_EAPMSCHAPv2", } -func TestConfigure(t *testing.T) { - f := &flags.Flags{} +var ieee8021xCfgPEAPv0_EAPMSCHAPv2 = config.Ieee8021xConfig{ + ProfileName: "ieee8021xCfgPEAPv0_EAPMSCHAPv2", + Username: "username", + Password: "password", + AuthenticationProtocol: int(models.AuthenticationProtocolPEAPv0_EAPMSCHAPv2), + ClientCert: "clientCert", + CACert: "caCert", + PrivateKey: "privateKey", +} + +// TODO: remove these when local-acm-activation branch is available in main +type ResponseFuncArray []func(w http.ResponseWriter, r *http.Request) + +func setupWsmanResponses(t *testing.T, f *flags.Flags, responses ResponseFuncArray) ProvisioningService { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, "POST", r.Method) - respondServerError(w) + responses[0](w, r) + responses = responses[1:] }) + return setupWithWsmanClient(f, handler) +} + +func respondServerErrFunc() func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + } +} + +func respondBadXmlFunc(t *testing.T) func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + _, err := w.Write([]byte(`not really xml is it?`)) + assert.Nil(t, err) + } +} + +func respondMsgFunc(t *testing.T, msg any) func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + bytes, err := xml.Marshal(msg) + assert.Nil(t, err) + _, err = w.Write(bytes) + assert.Nil(t, err) + } +} + +func respondStringFunc(t *testing.T, msg string) func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + _, err := w.Write([]byte(msg)) + assert.Nil(t, err) + } +} + +func TestConfigure(t *testing.T) { + f := &flags.Flags{} + t.Run("returns InvalidParameters with no sub command and not wifi configs", func(t *testing.T) { - lps := setupWithWsmanClient(f, handler) + lps := setupWsmanResponses(t, f, ResponseFuncArray{}) resultCode := lps.Configure() assert.Equal(t, utils.InvalidParameters, resultCode) }) - //t.Run("returns WiFiConfigurationFailed from err in Configure8021xWiFi", func(t *testing.T) { - // f.SubCommand = utils.SubCommandAddWifiSettings - // lps := setupWithWsmanClient(f, handler) - // resultCode := lps.Configure() - // assert.Equal(t, utils.WiFiConfigurationFailed, resultCode) - //}) t.Run("returns WiFiConfigurationFailed handling WifiConfigs from LocalConfig", func(t *testing.T) { f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfgWPA) - lps := setupWithWsmanClient(f, handler) + responsers := ResponseFuncArray{} + responsers = append(responsers, respondServerErrFunc()) + lps := setupWsmanResponses(t, f, responsers) resultCode := lps.Configure() assert.Equal(t, utils.WiFiConfigurationFailed, resultCode) }) @@ -77,297 +144,353 @@ func TestConfigure(t *testing.T) { func TestConfigureWiFi(t *testing.T) { f := &flags.Flags{} - - pcsResponse := wifiportconfiguration.PortConfigurationResponse{} - - t.Run("returns success on happy path", func(t *testing.T) { - count := 0 - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "POST", r.Method) - count++ - switch count { - case 1: - respondMsg(t, w, pcsResponse) - break - case 2: - pcsResponse.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled = 1 - respondMsg(t, w, pcsResponse) - break - case 3: - respondMsg(t, w, wifi.RequestStateChangeResponse{}) - break - } - }) - lps := setupWithWsmanClient(f, handler) + f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfgWPA) + t.Run("expect Success on happy path", func(t *testing.T) { + pcsRsp := wifiportconfiguration.PortConfigurationResponse{} + pcsRsp.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled = 1 + responsers := ResponseFuncArray{} + responsers = append(responsers, respondMsgFunc(t, pcsRsp)) + responsers = append(responsers, respondMsgFunc(t, wifi.RequestStateChangeResponse{})) + responsers = append(responsers, respondMsgFunc(t, wifiportconfiguration.AddWiFiSettingsResponse{})) + lps := setupWsmanResponses(t, f, responsers) resultCode := lps.ConfigureWiFi() assert.Equal(t, utils.Success, resultCode) }) + t.Run("expect WiFiConfigurationFailed on error with configuration", func(t *testing.T) { + orig := f.LocalConfig.WifiConfigs[0].ProfileName + f.LocalConfig.WifiConfigs[0].ProfileName = "bad-name" + responsers := ResponseFuncArray{} + responsers = append(responsers, respondMsgFunc(t, wifiportconfiguration.PortConfigurationResponse{})) + responsers = append(responsers, respondMsgFunc(t, wifi.RequestStateChangeResponse{})) + responsers = append(responsers, respondMsgFunc(t, wifiportconfiguration.AddWiFiSettingsResponse{})) + lps := setupWsmanResponses(t, f, responsers) + resultCode := lps.ConfigureWiFi() + assert.Equal(t, utils.WiFiConfigurationFailed, resultCode) + f.LocalConfig.WifiConfigs[0].ProfileName = orig + }) } -func TestEnableWifi(t *testing.T) { +func TestProcessWifiConfig(t *testing.T) { f := &flags.Flags{} - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Check the request method and URL path. - assert.Equal(t, "POST", r.Method) - // Return an error response - w.WriteHeader(http.StatusInternalServerError) + + // bad name error already tested + t.Run("expect error ProcessIeee8012xConfig", func(t *testing.T) { + orig := wifiCfgWPA8021xEAPTLS.AuthenticationMethod + wifiCfgWPA8021xEAPTLS.AuthenticationMethod = int(models.AuthenticationMethod_WPA_IEEE8021x) + f.LocalConfig.Ieee8021xConfigs = config.Ieee8021xConfigs{} + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, ieee8021xCfgEAPTLS) + responsers := ResponseFuncArray{} + responsers = append(responsers, respondServerErrFunc()) + lps := setupWsmanResponses(t, f, responsers) + err := lps.ProcessWifiConfig(&wifiCfgWPA8021xEAPTLS) + assert.NotNil(t, err) + wifiCfgWPA8021xEAPTLS.AuthenticationMethod = orig + }) + t.Run("expect server error for AddWiFiSettings()", func(t *testing.T) { + responsers := ResponseFuncArray{} + responsers = append(responsers, respondServerErrFunc()) + lps := setupWsmanResponses(t, f, responsers) + err := lps.ProcessWifiConfig(&wifiCfgWPA2) + assert.NotNil(t, err) + }) + t.Run("expect xml parse error for AddWiFiSettings()", func(t *testing.T) { + responsers := ResponseFuncArray{} + responsers = append(responsers, respondBadXmlFunc(t)) + lps := setupWsmanResponses(t, f, responsers) + err := lps.ProcessWifiConfig(&wifiCfgWPA2) + assert.NotNil(t, err) + }) + t.Run("expect unsuccessful return value error for AddWiFiSettings()", func(t *testing.T) { + msgRsp := wifiportconfiguration.AddWiFiSettingsResponse{} + msgRsp.Body.AddWiFiSettings_OUTPUT.ReturnValue = 1 + responsers := ResponseFuncArray{} + responsers = append(responsers, respondMsgFunc(t, msgRsp)) + lps := setupWsmanResponses(t, f, responsers) + err := lps.ProcessWifiConfig(&wifiCfgWPA2) + assert.NotNil(t, err) + }) +} + +func TestProcessIeee8012xConfig(t *testing.T) { + f := &flags.Flags{} + + t.Run("expect error on missing ieee8021x profile", func(t *testing.T) { + ieee8021xSettings := &models.IEEE8021xSettings{} + handles := Handles{} + f.LocalConfig.Ieee8021xConfigs = config.Ieee8021xConfigs{} + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, ieee8021xCfgEAPTLS) + lps := setupWsmanResponses(t, f, ResponseFuncArray{}) + err := lps.ProcessIeee8012xConfig("someothername", ieee8021xSettings, &handles) + assert.NotNil(t, err) + assert.Empty(t, ieee8021xSettings.ElementName) + assert.Empty(t, handles.privateKeyHandle) + assert.Empty(t, handles.clientCertHandle) + assert.Empty(t, handles.rootCertHandle) + }) + t.Run("expect error on AddPrivateKey error", func(t *testing.T) { + ieee8021xSettings := &models.IEEE8021xSettings{} + handles := Handles{} + f.LocalConfig.Ieee8021xConfigs = config.Ieee8021xConfigs{} + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, ieee8021xCfgPEAPv0_EAPMSCHAPv2) + responsers := ResponseFuncArray{} + responsers = append(responsers, respondServerErrFunc()) + lps := setupWsmanResponses(t, f, responsers) + err := lps.ProcessIeee8012xConfig(ieee8021xCfgPEAPv0_EAPMSCHAPv2.ProfileName, ieee8021xSettings, &handles) + assert.NotNil(t, err) + assert.Equal(t, ieee8021xCfgPEAPv0_EAPMSCHAPv2.ProfileName, ieee8021xSettings.ElementName) + assert.Empty(t, handles.privateKeyHandle) + assert.Empty(t, handles.clientCertHandle) + assert.Empty(t, handles.rootCertHandle) + }) + t.Run("expect error on AddClientCert error", func(t *testing.T) { + ieee8021xSettings := &models.IEEE8021xSettings{} + handles := Handles{} + f.LocalConfig.Ieee8021xConfigs = config.Ieee8021xConfigs{} + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, ieee8021xCfgEAPTLS) + responsers := ResponseFuncArray{} + responsers = append(responsers, respondStringFunc(t, addKeyXMLResponse)) + responsers = append(responsers, respondServerErrFunc()) + lps := setupWsmanResponses(t, f, responsers) + err := lps.ProcessIeee8012xConfig(ieee8021xCfgEAPTLS.ProfileName, ieee8021xSettings, &handles) + assert.NotNil(t, err) + assert.Equal(t, ieee8021xCfgEAPTLS.ProfileName, ieee8021xSettings.ElementName) + assert.NotEmpty(t, handles.privateKeyHandle) + assert.Empty(t, handles.clientCertHandle) + assert.Empty(t, handles.rootCertHandle) + }) + t.Run("expect error on AddTrustedRootCert error", func(t *testing.T) { + ieee8021xSettings := &models.IEEE8021xSettings{} + handles := Handles{} + f.LocalConfig.Ieee8021xConfigs = config.Ieee8021xConfigs{} + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, ieee8021xCfgEAPTLS) + responsers := ResponseFuncArray{} + responsers = append(responsers, respondStringFunc(t, addKeyXMLResponse)) + responsers = append(responsers, respondStringFunc(t, clientCertXMLResponse)) + responsers = append(responsers, respondServerErrFunc()) + lps := setupWsmanResponses(t, f, responsers) + err := lps.ProcessIeee8012xConfig(ieee8021xCfgEAPTLS.ProfileName, ieee8021xSettings, &handles) + assert.NotNil(t, err) + assert.Equal(t, ieee8021xCfgEAPTLS.ProfileName, ieee8021xSettings.ElementName) + assert.NotEmpty(t, handles.privateKeyHandle) + assert.NotEmpty(t, handles.clientCertHandle) + assert.Empty(t, handles.rootCertHandle) + }) + t.Run("expect success on happy path", func(t *testing.T) { + ieee8021xSettings := &models.IEEE8021xSettings{} + handles := Handles{} + f.LocalConfig.Ieee8021xConfigs = config.Ieee8021xConfigs{} + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, ieee8021xCfgEAPTLS) + responsers := ResponseFuncArray{} + responsers = append(responsers, respondStringFunc(t, addKeyXMLResponse)) + responsers = append(responsers, respondStringFunc(t, clientCertXMLResponse)) + responsers = append(responsers, respondStringFunc(t, trustedRootXMLResponse)) + lps := setupWsmanResponses(t, f, responsers) + err := lps.ProcessIeee8012xConfig(ieee8021xCfgEAPTLS.ProfileName, ieee8021xSettings, &handles) + assert.Nil(t, err) + assert.Equal(t, ieee8021xCfgEAPTLS.ProfileName, ieee8021xSettings.ElementName) + assert.NotEmpty(t, handles.privateKeyHandle) + assert.NotEmpty(t, handles.clientCertHandle) + assert.NotEmpty(t, handles.rootCertHandle) + }) +} + +func TestEnableWifiErrors(t *testing.T) { + f := &flags.Flags{} + t.Run("expect server error for WiFiPortConfigurationService.Get()", func(t *testing.T) { + responsers := ResponseFuncArray{} + responsers = append(responsers, respondServerErrFunc()) + lps := setupWsmanResponses(t, f, responsers) + err := lps.EnableWifi() + assert.NotNil(t, err) + }) + t.Run("expect unmarshall error for WiFiPortConfigurationService.Get()", func(t *testing.T) { + responsers := ResponseFuncArray{} + responsers = append(responsers, respondBadXmlFunc(t)) + lps := setupWsmanResponses(t, f, responsers) + err := lps.EnableWifi() + assert.NotNil(t, err) + }) + t.Run("expect server error for WiFiPortConfigurationService.Put()", func(t *testing.T) { + pcsResponse := wifiportconfiguration.PortConfigurationResponse{} + responsers := ResponseFuncArray{} + responsers = append(responsers, respondMsgFunc(t, pcsResponse)) + responsers = append(responsers, respondServerErrFunc()) + lps := setupWsmanResponses(t, f, responsers) + err := lps.EnableWifi() + assert.NotNil(t, err) + }) + t.Run("expect unmarshall error for WiFiPortConfigurationService.Put()", func(t *testing.T) { + pcsResponse := wifiportconfiguration.PortConfigurationResponse{} + responsers := ResponseFuncArray{} + responsers = append(responsers, respondMsgFunc(t, pcsResponse)) + responsers = append(responsers, respondBadXmlFunc(t)) + lps := setupWsmanResponses(t, f, responsers) + err := lps.EnableWifi() + assert.NotNil(t, err) + }) + t.Run("expect non-zero error for WiFiPortConfigurationService.Put()", func(t *testing.T) { + pcsResponse := wifiportconfiguration.PortConfigurationResponse{} + pcsResponseFailed := wifiportconfiguration.PortConfigurationResponse{} + responsers := ResponseFuncArray{} + responsers = append(responsers, respondMsgFunc(t, pcsResponse)) + responsers = append(responsers, respondMsgFunc(t, pcsResponseFailed)) + lps := setupWsmanResponses(t, f, responsers) + err := lps.EnableWifi() + assert.NotNil(t, err) + }) + t.Run("expect server error for RequestStateChange()", func(t *testing.T) { + pcsResponse := wifiportconfiguration.PortConfigurationResponse{} + pcsResponseEnabled := wifiportconfiguration.PortConfigurationResponse{} + pcsResponseEnabled.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled = 1 + responsers := ResponseFuncArray{} + responsers = append(responsers, respondMsgFunc(t, pcsResponse)) + responsers = append(responsers, respondMsgFunc(t, pcsResponseEnabled)) + responsers = append(responsers, respondServerErrFunc()) + lps := setupWsmanResponses(t, f, responsers) + err := lps.EnableWifi() + assert.NotNil(t, err) + }) + t.Run("expect xml unmarshall error for RequestStateChange()", func(t *testing.T) { + pcsResponse := wifiportconfiguration.PortConfigurationResponse{} + pcsResponseEnabled := wifiportconfiguration.PortConfigurationResponse{} + pcsResponseEnabled.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled = 1 + responsers := ResponseFuncArray{} + responsers = append(responsers, respondMsgFunc(t, pcsResponse)) + responsers = append(responsers, respondMsgFunc(t, pcsResponseEnabled)) + responsers = append(responsers, respondBadXmlFunc(t)) + lps := setupWsmanResponses(t, f, responsers) + err := lps.EnableWifi() + assert.NotNil(t, err) + }) + t.Run("expect non-zero error for RequestStateChange()", func(t *testing.T) { + pcsResponse := wifiportconfiguration.PortConfigurationResponse{} + pcsResponseEnabled := wifiportconfiguration.PortConfigurationResponse{} + pcsResponseEnabled.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled = 1 + stateChangeResponse := wifi.RequestStateChangeResponse{} + stateChangeResponse.Body.RequestStateChange_OUTPUT.ReturnValue = 1 + responsers := ResponseFuncArray{} + responsers = append(responsers, respondMsgFunc(t, pcsResponse)) + responsers = append(responsers, respondMsgFunc(t, pcsResponseEnabled)) + responsers = append(responsers, respondMsgFunc(t, stateChangeResponse)) + lps := setupWsmanResponses(t, f, responsers) + err := lps.EnableWifi() + assert.NotNil(t, err) + }) +} + +func TestRollbackAddedItems(t *testing.T) { + f := &flags.Flags{} + handles := Handles{ + privateKeyHandle: "privateKeyHandle", + clientCertHandle: "clientCertHandle", + rootCertHandle: "rootCertHandle", + } + + t.Run("expect all error paths traversed for coverage", func(t *testing.T) { + responsers := ResponseFuncArray{} + responsers = append(responsers, respondServerErrFunc()) + responsers = append(responsers, respondServerErrFunc()) + responsers = append(responsers, respondServerErrFunc()) + lps := setupWsmanResponses(t, f, responsers) + lps.RollbackAddedItems(&handles) }) + t.Run("expect all happy paths traversed for coverage", func(t *testing.T) { + responsers := ResponseFuncArray{} + responsers = append(responsers, respondStringFunc(t, "any message works?")) + responsers = append(responsers, respondStringFunc(t, "any message works?")) + responsers = append(responsers, respondStringFunc(t, "any message works?")) + lps := setupWsmanResponses(t, f, responsers) + lps.RollbackAddedItems(&handles) + }) +} + +func TestAddTrustedRootCert(t *testing.T) { + f := &flags.Flags{} + t.Run("expect server error", func(t *testing.T) { + responsers := ResponseFuncArray{} + responsers = append(responsers, respondServerErrFunc()) + lps := setupWsmanResponses(t, f, responsers) + handle, err := lps.AddTrustedRootCert("AABBCCDD") + assert.NotNil(t, err) + assert.Empty(t, handle) + }) + t.Run("expect xml parse error", func(t *testing.T) { + responsers := ResponseFuncArray{} + responsers = append(responsers, respondBadXmlFunc(t)) + lps := setupWsmanResponses(t, f, responsers) + handle, err := lps.AddTrustedRootCert("AABBCCDD") + assert.NotNil(t, err) + assert.Empty(t, handle) + }) + t.Run("expect non-zero error ", func(t *testing.T) { + dup := strings.Replace(trustedRootXMLResponse, `0`, `1`, 1) + responsers := ResponseFuncArray{} + responsers = append(responsers, respondStringFunc(t, dup)) + lps := setupWsmanResponses(t, f, responsers) + handle, err := lps.AddTrustedRootCert("AABBCCDD") + assert.NotNil(t, err) + assert.Empty(t, handle) + }) +} - lps := setupWithWsmanClient(f, handler) - err := lps.EnableWifi() - assert.NotNil(t, err) +func TestAddClientCert(t *testing.T) { + f := &flags.Flags{} + t.Run("expect server error", func(t *testing.T) { + responsers := ResponseFuncArray{} + responsers = append(responsers, respondServerErrFunc()) + lps := setupWsmanResponses(t, f, responsers) + handle, err := lps.AddClientCert("AABBCCDD") + assert.NotNil(t, err) + assert.Empty(t, handle) + }) + t.Run("expect xml parse error", func(t *testing.T) { + responsers := ResponseFuncArray{} + responsers = append(responsers, respondBadXmlFunc(t)) + lps := setupWsmanResponses(t, f, responsers) + handle, err := lps.AddClientCert("AABBCCDD") + assert.NotNil(t, err) + assert.Empty(t, handle) + }) + t.Run("expect non-zero error ", func(t *testing.T) { + dup := strings.Replace(clientCertXMLResponse, `0`, `1`, 1) + responsers := ResponseFuncArray{} + responsers = append(responsers, respondStringFunc(t, dup)) + lps := setupWsmanResponses(t, f, responsers) + handle, err := lps.AddClientCert("AABBCCDD") + assert.NotNil(t, err) + assert.Empty(t, handle) + }) +} + +func TestAddPrivateKey(t *testing.T) { + f := &flags.Flags{} + t.Run("expect server error", func(t *testing.T) { + responsers := ResponseFuncArray{} + responsers = append(responsers, respondServerErrFunc()) + lps := setupWsmanResponses(t, f, responsers) + handle, err := lps.AddPrivateKey("AABBCCDD") + assert.NotNil(t, err) + assert.Empty(t, handle) + }) + t.Run("expect xml parse error", func(t *testing.T) { + responsers := ResponseFuncArray{} + responsers = append(responsers, respondBadXmlFunc(t)) + lps := setupWsmanResponses(t, f, responsers) + handle, err := lps.AddPrivateKey("AABBCCDD") + assert.NotNil(t, err) + assert.Empty(t, handle) + }) + t.Run("expect non-zero error ", func(t *testing.T) { + dup := strings.Replace(addKeyXMLResponse, `0`, `1`, 1) + responsers := ResponseFuncArray{} + responsers = append(responsers, respondStringFunc(t, dup)) + lps := setupWsmanResponses(t, f, responsers) + handle, err := lps.AddPrivateKey("AABBCCDD") + assert.NotNil(t, err) + assert.Empty(t, handle) + }) } -//func TestConfigure8021xWiFi(t *testing.T) { -// f := &flags.Flags{} -// t.Run("returns error when AddPrivateKey fails", func(t *testing.T) { -// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, "POST", r.Method) -// w.WriteHeader(http.StatusInternalServerError) -// }) -// lps := setupWithWsmanClient(f, handler) -// err := lps.Configure8021xWiFi() -// assert.NotNil(t, err) -// }) -// -// t.Run("returns error when AddClientCert fails", func(t *testing.T) { -// calls := 0 -// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// // Simulate AddPrivateKey success and AddClientCert failure -// if calls == 0 { -// calls++ -// assert.Equal(t, "POST", r.Method) -// _, err := w.Write([]byte(addKeyXMLResponse)) -// assert.Nil(t, err) -// -// } else { -// assert.Equal(t, "POST", r.Method) -// w.WriteHeader(http.StatusInternalServerError) -// } -// }) -// -// lps := setupWithWsmanClient(f, handler) -// err := lps.Configure8021xWiFi() -// assert.NotNil(t, err) -// }) -// -// t.Run("returns error when AddTrustedRootCert fails", func(t *testing.T) { -// calls := 0 -// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// // Simulate AddPrivateKey and AddClientCert success and AddTrustedRootCert failure -// if calls == 0 { -// calls++ -// assert.Equal(t, "POST", r.Method) -// _, err := w.Write([]byte(addKeyXMLResponse)) -// assert.Nil(t, err) -// } else if calls == 1 { -// calls++ -// assert.Equal(t, "POST", r.Method) -// _, err := w.Write([]byte(clientCertXMLResponse)) -// assert.Nil(t, err) -// } else { -// assert.Equal(t, "POST", r.Method) -// w.WriteHeader(http.StatusInternalServerError) -// } -// }) -// -// lps := setupWithWsmanClient(f, handler) -// err := lps.Configure8021xWiFi() -// assert.NotNil(t, err) -// }) -// -// t.Run("returns error when AddWifiSettings fails", func(t *testing.T) { -// calls := 0 -// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// // Simulate AddPrivateKey and AddClientCert success and AddTrustedRootCert failure -// if calls == 0 { -// calls++ -// assert.Equal(t, "POST", r.Method) -// _, err := w.Write([]byte(addKeyXMLResponse)) -// assert.Nil(t, err) -// } else if calls == 1 { -// calls++ -// assert.Equal(t, "POST", r.Method) -// _, err := w.Write([]byte(clientCertXMLResponse)) -// assert.Nil(t, err) -// } else if calls == 2 { -// calls++ -// assert.Equal(t, "POST", r.Method) -// _, err := w.Write([]byte(trustedRootXMLResponse)) -// assert.Nil(t, err) -// } else { -// assert.Equal(t, "POST", r.Method) -// w.WriteHeader(http.StatusInternalServerError) -// } -// }) -// -// lps := setupWithWsmanClient(f, handler) -// err := lps.Configure8021xWiFi() -// assert.NotNil(t, err) -// }) -// -// t.Run("returns error when RollbackAddedItems fails", func(t *testing.T) { -// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// // Simulate all steps before RollbackAddedItems success and RollbackAddedItems failure -// if strings.Contains(r.URL.Path, "RollbackAddedItems") { -// assert.Equal(t, "POST", r.Method) -// w.WriteHeader(http.StatusInternalServerError) -// } else if strings.Contains(r.URL.Path, "WifiSettings") { -// w.WriteHeader(http.StatusInternalServerError) -// } else { -// w.WriteHeader(http.StatusOK) -// } -// }) -// -// lps := setupWithWsmanClient(f, handler) -// err := lps.Configure8021xWiFi() -// assert.NotNil(t, err) -// }) -// -// t.Run("returns nil on happy path", func(t *testing.T) { -// calls := 0 -// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, "POST", r.Method) -// var err error -// // Simulate AddPrivateKey and AddClientCert success and AddTrustedRootCert failure -// if calls == 0 { -// _, err = w.Write([]byte(addKeyXMLResponse)) -// } else if calls == 1 { -// _, err = w.Write([]byte(clientCertXMLResponse)) -// } else if calls == 2 { -// _, err = w.Write([]byte(trustedRootXMLResponse)) -// } else { -// _, err = w.Write([]byte(addWifiSettingsResponse)) -// } -// assert.Nil(t, err) -// calls++ -// }) -// -// lps := setupWithWsmanClient(f, handler) -// err := lps.Configure8021xWiFi() -// assert.Nil(t, err) -// }) -//} -// -//func TestAddWifiSettings(t *testing.T) { -// f := &flags.Flags{} -// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// // Check the request method and URL path. -// assert.Equal(t, "POST", r.Method) -// // Return an error response -// w.WriteHeader(http.StatusInternalServerError) -// }) -// -// lps := setupWithWsmanClient(f, handler) -// err := lps.AddWifiSettings("certHandle", "rootHandle") -// assert.NotNil(t, err) -//} - -//func TestRollbackAddedItems(t *testing.T) { -// f := &flags.Flags{} -// t.Run("returns no error when rollback is successful", func(t *testing.T) { -// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, "POST", r.Method) -// w.WriteHeader(http.StatusOK) -// }) -// -// lps := setupWithWsmanClient(f, handler) -// err := lps.RollbackAddedItems("certHandle", "rootHandle", "privateKeyHandle") -// assert.Nil(t, err) -// }) -// -// t.Run("returns error when server returns non-200 status code", func(t *testing.T) { -// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, "POST", r.Method) -// w.WriteHeader(http.StatusInternalServerError) -// }) -// -// lps := setupWithWsmanClient(f, handler) -// err := lps.RollbackAddedItems("certHandle", "rootHandle", "privateKeyHandle") -// assert.NotNil(t, err) -// }) -//} - -// func TestAddTrustedRootCert(t *testing.T) { -// f := &flags.Flags{} -// t.Run("returns handle when adding cert is successful", func(t *testing.T) { -// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, "POST", r.Method) -// _, err := w.Write([]byte(trustedRootXMLResponse)) -// assert.Nil(t, err) -// }) -// -// lps := setupWithWsmanClient(f, handler) -// handle, err := lps.AddTrustedRootCert() -// assert.Nil(t, err) -// assert.NotEmpty(t, handle) -// }) -// -// t.Run("returns error when server returns non-200 status code", func(t *testing.T) { -// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, "POST", r.Method) -// w.WriteHeader(http.StatusInternalServerError) -// }) -// -// lps := setupWithWsmanClient(f, handler) -// _, err := lps.AddTrustedRootCert() -// assert.NotNil(t, err) -// }) -// } -// -// func TestAddClientCert(t *testing.T) { -// f := &flags.Flags{} -// t.Run("returns handle when adding cert is successful", func(t *testing.T) { -// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, "POST", r.Method) -// _, err := w.Write([]byte(clientCertXMLResponse)) -// assert.Nil(t, err) -// }) -// -// lps := setupWithWsmanClient(f, handler) -// handle, err := lps.AddClientCert() -// assert.Nil(t, err) -// assert.NotEmpty(t, handle) -// }) -// -// t.Run("returns error when server returns non-200 status code", func(t *testing.T) { -// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, "POST", r.Method) -// w.WriteHeader(http.StatusInternalServerError) -// }) -// -// lps := setupWithWsmanClient(f, handler) -// _, err := lps.AddClientCert() -// assert.NotNil(t, err) -// }) -// } -// -// func TestAddPrivateKey(t *testing.T) { -// f := &flags.Flags{} -// t.Run("returns handle when adding cert is successful", func(t *testing.T) { -// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, "POST", r.Method) -// _, err := w.Write([]byte(addKeyXMLResponse)) -// assert.Nil(t, err) -// }) -// -// lps := setupWithWsmanClient(f, handler) -// handle, err := lps.AddPrivateKey() -// assert.Nil(t, err) -// assert.NotEmpty(t, handle) -// }) -// -// t.Run("returns error when server returns non-200 status code", func(t *testing.T) { -// handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// assert.Equal(t, "POST", r.Method) -// w.WriteHeader(http.StatusInternalServerError) -// }) -// -// lps := setupWithWsmanClient(f, handler) -// _, err := lps.AddPrivateKey() -// assert.NotNil(t, err) -// }) -// } func TestCheckReturnValue(t *testing.T) { tests := []struct { name string @@ -376,9 +499,9 @@ func TestCheckReturnValue(t *testing.T) { wantErr error }{ {"TestNoError", 0, "item", nil}, - {"TestAlreadyExists", common.PT_STATUS_DUPLICATE, "item", errors.New("item already exists. You must remove it manually before continuing")}, - {"TestInvalidItem", common.PT_STATUS_INVALID_CERT, "item", fmt.Errorf("%s invalid cert", "item")}, - {"TestNonZeroReturnCode", 9999, "item", fmt.Errorf("non-zero return code: %d", 9999)}, + {"TestAlreadyExists", common.PT_STATUS_DUPLICATE, "item", fmt.Errorf("%s already exists and must be removed before continuing", "item")}, + {"TestInvalidItem", common.PT_STATUS_INVALID_CERT, "item", fmt.Errorf("%s is invalid", "item")}, + {"TestNonZeroReturnCode", 9999, "item", fmt.Errorf("%s non-zero return code: %d", "item", 9999)}, } for _, tt := range tests { From c49f715223d54450e011d6864dbc9e3645925c39 Mon Sep 17 00:00:00 2001 From: Tim Shockley Date: Tue, 15 Aug 2023 00:12:37 -0700 Subject: [PATCH 11/29] fix: flags configure addwifisettings subcommand --- internal/flags/configure.go | 101 ++++++++++++++++++++++++------- internal/flags/configure_test.go | 3 +- internal/flags/flags.go | 11 ++-- internal/flags/flags_test.go | 4 +- internal/flags/maintenance.go | 6 +- 5 files changed, 90 insertions(+), 35 deletions(-) diff --git a/internal/flags/configure.go b/internal/flags/configure.go index 2100a7b9..d403ea61 100644 --- a/internal/flags/configure.go +++ b/internal/flags/configure.go @@ -2,44 +2,99 @@ package flags import ( "fmt" + "os" + "path/filepath" "rpc/pkg/utils" "github.com/ilyakaznacheev/cleanenv" log "github.com/sirupsen/logrus" ) +func (f *Flags) printConfigurationUsage() string { + executable := filepath.Base(os.Args[0]) + usage := "\nRemote Provisioning Client (RPC) - used for activation, deactivation, maintenance and status of AMT\n\n" + usage = usage + "Usage: " + executable + " configure COMMAND [OPTIONS]\n\n" + usage = usage + "Supported Configuration Commands:\n" + usage = usage + " addwifisettings Add or modify WiFi settings in AMT. AMT password is required. A config.yml or command line flags must be provided for all settings. This command runs without cloud interaction.\n" + usage = usage + " Example: " + executable + " configure addwifisettings -password YourAMTPassword -config wificonfig.yaml\n" + usage = usage + "\nRun '" + executable + " configure COMMAND -h' for more information on a command.\n" + fmt.Println(usage) + return usage +} + func (f *Flags) handleConfigureCommand() int { - f.amtConfigureCommand.StringVar(&f.Password, "password", f.lookupEnvOrString("AMT_PASSWORD", ""), "AMT password") - f.amtConfigureCommand.StringVar(&f.configContent, "config", "", "specify a config file ") - if err := f.amtConfigureCommand.Parse(f.commandLineArgs[3:]); err != nil { - f.amtConfigureCommand.Usage() + if len(f.commandLineArgs) == 2 { + f.printConfigurationUsage() return utils.IncorrectCommandLineParameters } - //if err := f.amtConfigureAddWiFiSettingsCommand.Parse(f.commandLineArgs[2:]); err != nil { - // f.amtConfigureCommand.Usage() - // return utils.IncorrectCommandLineParameters - //} - // runs locally - f.Local = true + + var errCode = utils.Success f.SubCommand = f.commandLineArgs[2] switch f.SubCommand { case "addwifisettings": - if f.configContent == "" { - fmt.Println("-config flag is required and cannot be empty") - return utils.IncorrectCommandLineParameters - } - err := cleanenv.ReadConfig(f.configContent, &f.LocalConfig) - if err != nil { - log.Error("config error: ", err) - return utils.IncorrectCommandLineParameters - } - configFileStatus := f.verifyWifiConfigurationFile() - if configFileStatus != 0 { - log.Error("config error: ", err) - return utils.IncorrectCommandLineParameters + errCode = f.handleAddWifiSettings() + break + default: + f.printConfigurationUsage() + errCode = utils.IncorrectCommandLineParameters + break + } + if errCode != utils.Success { + return errCode + } + + f.Local = true + if f.Password == "" { + if _, errCode := f.ReadPasswordFromUser(); errCode != 0 { + return utils.MissingOrIncorrectPassword } } + f.LocalConfig.Password = f.Password + return utils.Success +} + +func (f *Flags) handleAddWifiSettings() int { + + f.flagSetAddWifiSettings.BoolVar(&f.Verbose, "v", false, "Verbose output") + f.flagSetAddWifiSettings.StringVar(&f.LogLevel, "l", "info", "Log level (panic,fatal,error,warn,info,debug,trace)") + f.flagSetAddWifiSettings.BoolVar(&f.JsonOutput, "json", false, "JSON output") + f.flagSetAddWifiSettings.StringVar(&f.Password, "password", f.lookupEnvOrString("AMT_PASSWORD", ""), "AMT password") + f.flagSetAddWifiSettings.StringVar(&f.configContent, "config", "", "specify a config file ") + // TODO: these are the params for entering a single wifi config from command line + //wifiCfg := config.WifiConfig{} + //ieee8021xCfg := config.Ieee8021xConfig{} + //f.flagSetAddWifiSettings.StringVar(&wifiCfg.ProfileName, "profileName", "", "specify wifi profile name name") + //f.flagSetAddWifiSettings.IntVar(&wifiCfg.AuthenticationMethod, "authenticationMethod", 0, "specify authentication method") + //f.flagSetAddWifiSettings.IntVar(&wifiCfg.EncryptionMethod, "encryptionMethod", 0, "specify encryption method") + //f.flagSetAddWifiSettings.StringVar(&wifiCfg.SSID, "ssid", "", "specify ssid") + //f.flagSetAddWifiSettings.StringVar(&wifiCfg.PskPassphrase, "pskPassphrase", "", "specify psk passphrase") + //f.flagSetAddWifiSettings.IntVar(&wifiCfg.Priority, "priority", 0, "specify priority") + //f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.Username, "username", "", "specify username") + //f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.Password, "ieee8021xPassword", "", "specify ieee8021x password") + //f.flagSetAddWifiSettings.IntVar(&ieee8021xCfg.AuthenticationProtocol, "authenticationProtocol", 0, "specify authentication protocol") + //f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.ClientCert, "clientCert", "", "specify client certificate") + //f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.CACert, "caCert", "", "specify CA certificate") + //f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.PrivateKey, "privateKey", "", "specify private key") + + if err := f.flagSetAddWifiSettings.Parse(f.commandLineArgs[3:]); err != nil { + f.printConfigurationUsage() + return utils.IncorrectCommandLineParameters + } + if f.configContent == "" { + fmt.Println("-config flag is required and cannot be empty") + return utils.IncorrectCommandLineParameters + } + err := cleanenv.ReadConfig(f.configContent, &f.LocalConfig) + if err != nil { + log.Error("config error: ", err) + return utils.IncorrectCommandLineParameters + } + configFileStatus := f.verifyWifiConfigurationFile() + if configFileStatus != 0 { + log.Error("config error: ", err) + return utils.IncorrectCommandLineParameters + } return utils.Success } diff --git a/internal/flags/configure_test.go b/internal/flags/configure_test.go index d822e6c7..c514828b 100644 --- a/internal/flags/configure_test.go +++ b/internal/flags/configure_test.go @@ -10,13 +10,14 @@ import ( ) func TestHandleConfigureCommand(t *testing.T) { - cmdLine := "rpc configure addwifisettings --config ../../config-wifi.yaml " + cmdLine := "rpc configure addwifisettings -password Passw0rd! -config ../../config-wifi.yaml " args := strings.Fields(cmdLine) flags := NewFlags(args) gotResult := flags.ParseFlags() assert.Equal(t, flags.Local, true) assert.Equal(t, utils.Success, gotResult) assert.Equal(t, utils.CommandConfigure, flags.Command) + assert.Equal(t, utils.SubCommandAddWifiSettings, flags.SubCommand) } func TestVerifyWifiConfigurationFile(t *testing.T) { diff --git a/internal/flags/flags.go b/internal/flags/flags.go index 8e6a09c6..9ab46210 100644 --- a/internal/flags/flags.go +++ b/internal/flags/flags.go @@ -68,15 +68,13 @@ type Flags struct { amtInfoCommand *flag.FlagSet amtActivateCommand *flag.FlagSet amtDeactivateCommand *flag.FlagSet - amtMaintenanceCommand *flag.FlagSet amtMaintenanceAddWiFiSettingsCommand *flag.FlagSet amtMaintenanceSyncIPCommand *flag.FlagSet amtMaintenanceSyncClockCommand *flag.FlagSet amtMaintenanceSyncHostnameCommand *flag.FlagSet amtMaintenanceChangePasswordCommand *flag.FlagSet versionCommand *flag.FlagSet - amtConfigureCommand *flag.FlagSet - amtConfigureAddWiFiSettingsCommand *flag.FlagSet + flagSetAddWifiSettings *flag.FlagSet amtCommand amt.AMTCommand netEnumerator NetEnumerator IpConfiguration IPConfiguration @@ -94,7 +92,6 @@ func NewFlags(args []string) *Flags { flags.amtActivateCommand = flag.NewFlagSet(utils.CommandActivate, flag.ContinueOnError) flags.amtDeactivateCommand = flag.NewFlagSet(utils.CommandDeactivate, flag.ContinueOnError) - flags.amtMaintenanceCommand = flag.NewFlagSet(utils.CommandMaintenance, flag.ContinueOnError) flags.amtMaintenanceSyncIPCommand = flag.NewFlagSet("syncip", flag.ContinueOnError) flags.amtMaintenanceSyncClockCommand = flag.NewFlagSet("syncclock", flag.ContinueOnError) @@ -105,9 +102,7 @@ func NewFlags(args []string) *Flags { flags.versionCommand = flag.NewFlagSet(utils.CommandVersion, flag.ContinueOnError) flags.versionCommand.BoolVar(&flags.JsonOutput, "json", false, "json output") - flags.amtConfigureCommand = flag.NewFlagSet(utils.CommandConfigure, flag.ContinueOnError) - flags.amtConfigureCommand.BoolVar(&flags.JsonOutput, "json", false, "json output") - flags.amtConfigureAddWiFiSettingsCommand = flag.NewFlagSet("addwifisettings", flag.ContinueOnError) + flags.flagSetAddWifiSettings = flag.NewFlagSet(utils.SubCommandAddWifiSettings, flag.ContinueOnError) flags.amtCommand = amt.NewAMTCommand() flags.netEnumerator = NetEnumerator{} @@ -153,6 +148,8 @@ func (f *Flags) printUsage() string { usage = usage + " Example: " + executable + " activate -u wss://server/activate --profile acmprofile\n" usage = usage + " amtinfo Displays information about AMT status and configuration\n" usage = usage + " Example: " + executable + " amtinfo\n" + usage = usage + " configure Local configuration of a feature on this device. AMT password is required\n" + usage = usage + " Example: " + executable + " configure addwifisettings ...\n" usage = usage + " deactivate Deactivates this device. AMT password is required\n" usage = usage + " Example: " + executable + " deactivate -u wss://server/activate\n" usage = usage + " maintenance Execute a maintenance task for the device. AMT password is required\n" diff --git a/internal/flags/flags_test.go b/internal/flags/flags_test.go index c13fc829..0c4c52e3 100644 --- a/internal/flags/flags_test.go +++ b/internal/flags/flags_test.go @@ -161,6 +161,8 @@ func TestPrintUsage(t *testing.T) { usage = usage + " Example: " + executable + " activate -u wss://server/activate --profile acmprofile\n" usage = usage + " amtinfo Displays information about AMT status and configuration\n" usage = usage + " Example: " + executable + " amtinfo\n" + usage = usage + " configure Local configuration of a feature on this device. AMT password is required\n" + usage = usage + " Example: " + executable + " configure addwifisettings ...\n" usage = usage + " deactivate Deactivates this device. AMT password is required\n" usage = usage + " Example: " + executable + " deactivate -u wss://server/activate\n" usage = usage + " maintenance Execute a maintenance task for the device. AMT password is required\n" @@ -220,7 +222,7 @@ func TestParseFlagsVersion(t *testing.T) { assert.Equal(t, false, flags.JsonOutput) } func TestParseFlagsConfigure(t *testing.T) { - args := []string{"./rpc", "configure", "-config", "../../config-wifi.yaml"} + args := []string{"./rpc", "configure", "addwifisettings", "-config", "../../config-wifi.yaml", "-password", "Passw0rd!"} flags := NewFlags(args) result := flags.ParseFlags() assert.EqualValues(t, result, utils.Success) diff --git a/internal/flags/maintenance.go b/internal/flags/maintenance.go index 9eb5b919..595e2dab 100644 --- a/internal/flags/maintenance.go +++ b/internal/flags/maintenance.go @@ -48,7 +48,7 @@ func (f *Flags) handleMaintenanceCommand() int { f.SubCommand = f.commandLineArgs[2] switch f.SubCommand { case "addwifisettings": - errCode = f.handleAddWifiSettings() + errCode = f.handleMaintenanceAddWifiSettings() break case "syncclock": errCode = f.handleMaintenanceSyncClock() @@ -82,7 +82,7 @@ func (f *Flags) handleMaintenanceCommand() int { if !f.Local { if f.URL == "" { fmt.Print("\n-u flag is required and cannot be empty\n\n") - f.amtMaintenanceCommand.Usage() + f.printMaintenanceUsage() return utils.MissingOrIncorrectURL } } @@ -90,7 +90,7 @@ func (f *Flags) handleMaintenanceCommand() int { return utils.Success } -func (f *Flags) handleAddWifiSettings() int { +func (f *Flags) handleMaintenanceAddWifiSettings() int { // this is an implied local command f.Local = true From a997ec18198531e69454d0eb7bbd5018bde85025 Mon Sep 17 00:00:00 2001 From: Tim Shockley Date: Tue, 15 Aug 2023 10:03:10 -0700 Subject: [PATCH 12/29] fix: added command line params from maintenance --- internal/flags/configure.go | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/internal/flags/configure.go b/internal/flags/configure.go index d403ea61..2bbb1ad2 100644 --- a/internal/flags/configure.go +++ b/internal/flags/configure.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "path/filepath" + "rpc/internal/config" "rpc/pkg/utils" "github.com/ilyakaznacheev/cleanenv" @@ -62,29 +63,28 @@ func (f *Flags) handleAddWifiSettings() int { f.flagSetAddWifiSettings.StringVar(&f.Password, "password", f.lookupEnvOrString("AMT_PASSWORD", ""), "AMT password") f.flagSetAddWifiSettings.StringVar(&f.configContent, "config", "", "specify a config file ") // TODO: these are the params for entering a single wifi config from command line - //wifiCfg := config.WifiConfig{} - //ieee8021xCfg := config.Ieee8021xConfig{} - //f.flagSetAddWifiSettings.StringVar(&wifiCfg.ProfileName, "profileName", "", "specify wifi profile name name") - //f.flagSetAddWifiSettings.IntVar(&wifiCfg.AuthenticationMethod, "authenticationMethod", 0, "specify authentication method") - //f.flagSetAddWifiSettings.IntVar(&wifiCfg.EncryptionMethod, "encryptionMethod", 0, "specify encryption method") - //f.flagSetAddWifiSettings.StringVar(&wifiCfg.SSID, "ssid", "", "specify ssid") - //f.flagSetAddWifiSettings.StringVar(&wifiCfg.PskPassphrase, "pskPassphrase", "", "specify psk passphrase") - //f.flagSetAddWifiSettings.IntVar(&wifiCfg.Priority, "priority", 0, "specify priority") - //f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.Username, "username", "", "specify username") - //f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.Password, "ieee8021xPassword", "", "specify ieee8021x password") - //f.flagSetAddWifiSettings.IntVar(&ieee8021xCfg.AuthenticationProtocol, "authenticationProtocol", 0, "specify authentication protocol") - //f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.ClientCert, "clientCert", "", "specify client certificate") - //f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.CACert, "caCert", "", "specify CA certificate") - //f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.PrivateKey, "privateKey", "", "specify private key") + wifiCfg := config.WifiConfig{} + ieee8021xCfg := config.Ieee8021xConfig{} + f.flagSetAddWifiSettings.StringVar(&wifiCfg.ProfileName, "profileName", "", "specify wifi profile name name") + f.flagSetAddWifiSettings.IntVar(&wifiCfg.AuthenticationMethod, "authenticationMethod", 0, "specify authentication method") + f.flagSetAddWifiSettings.IntVar(&wifiCfg.EncryptionMethod, "encryptionMethod", 0, "specify encryption method") + f.flagSetAddWifiSettings.StringVar(&wifiCfg.SSID, "ssid", "", "specify ssid") + f.flagSetAddWifiSettings.StringVar(&wifiCfg.PskPassphrase, "pskPassphrase", "", "specify psk passphrase") + f.flagSetAddWifiSettings.IntVar(&wifiCfg.Priority, "priority", 0, "specify priority") + f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.Username, "username", "", "specify username") + f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.Password, "ieee8021xPassword", "", "specify ieee8021x password") + f.flagSetAddWifiSettings.IntVar(&ieee8021xCfg.AuthenticationProtocol, "authenticationProtocol", 0, "specify authentication protocol") + f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.ClientCert, "clientCert", "", "specify client certificate") + f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.CACert, "caCert", "", "specify CA certificate") + f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.PrivateKey, "privateKey", "", "specify private key") + + f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfg) + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, ieee8021xCfg) if err := f.flagSetAddWifiSettings.Parse(f.commandLineArgs[3:]); err != nil { f.printConfigurationUsage() return utils.IncorrectCommandLineParameters } - if f.configContent == "" { - fmt.Println("-config flag is required and cannot be empty") - return utils.IncorrectCommandLineParameters - } err := cleanenv.ReadConfig(f.configContent, &f.LocalConfig) if err != nil { log.Error("config error: ", err) From 13d9303ef9643903a38e172d0fa547d19848b2d4 Mon Sep 17 00:00:00 2001 From: Craig-Spencer-12 Date: Tue, 15 Aug 2023 15:04:41 -0700 Subject: [PATCH 13/29] feat: Prunes wifi configs when new ones are added --- internal/local/configure.go | 49 ++++++++++++++++++++++++++++++++++--- pkg/utils/constants.go | 2 ++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/internal/local/configure.go b/internal/local/configure.go index ddf77f2a..e9149868 100644 --- a/internal/local/configure.go +++ b/internal/local/configure.go @@ -4,15 +4,16 @@ import ( "encoding/xml" "errors" "fmt" + "regexp" + "rpc/internal/config" + "rpc/pkg/utils" + "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/amt/publickey" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/amt/wifiportconfiguration" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim/models" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim/wifi" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/common" log "github.com/sirupsen/logrus" - "regexp" - "rpc/internal/config" - "rpc/pkg/utils" ) func (service *ProvisioningService) Configure() int { @@ -31,6 +32,7 @@ func (service *ProvisioningService) Configure() int { } func (service *ProvisioningService) ConfigureWiFi() int { + service.pruneWifiConfigs() err := service.EnableWifi() if err != nil { log.Error(err) @@ -58,6 +60,47 @@ func (service *ProvisioningService) ConfigureWiFi() int { return utils.Success } +func (service *ProvisioningService) pruneWifiConfigs() { + // Removes existing wifi configs + enumerateMessage := service.cimMessages.WiFiEndpointSettings.Enumerate() + enumerateResponse, err := service.client.Post(enumerateMessage) + if err != nil { + log.Error(err) + return utils.WSMANMessageError + } + + var enumerationEnvelope wifi.EnumerationEnvelope + if err := xml.Unmarshal(enumerateResponse, &enumerationEnvelope); err != nil { + log.Error(err) + return utils.UnmarshalMessageFailed + } + + pullMessage := service.cimMessages.WiFiEndpointSettings.Pull(enumerationEnvelope.Body.EnumerateResponse.EnumerationContext) + pullResponse, err := service.client.Post(pullMessage) + if err != nil { + log.Error(err) + return utils.WSMANMessageError + } + + var pullEnvelope wifi.PullEnvelope + if err := xml.Unmarshal(pullResponse, &pullEnvelope); err != nil { + log.Error(err) + return utils.UnmarshalMessageFailed + } + + for _, config := range pullEnvelope.Body.PullResponse.Items.WifiSettings { + deleteMessage := service.cimMessages.WiFiEndpointSettings.Delete(config.InstanceID) + deleteMessageResponse, err := service.client.Post(deleteMessage) + if err != nil { + log.Error(err) + return utils.DeleteWifiConfigFailed + } + fmt.Println(deleteMessageResponse) + } + + err = service.EnableWifi() +} + func (service *ProvisioningService) ProcessWifiConfig(wifiCfg *config.WifiConfig) error { // profile names can only be alphanumeric (not even dashes) diff --git a/pkg/utils/constants.go b/pkg/utils/constants.go index 7c11212c..5b627453 100644 --- a/pkg/utils/constants.go +++ b/pkg/utils/constants.go @@ -79,6 +79,8 @@ const ( UnableToDeactivate = 109 // Device is not in CCM mode DeactivationFailed = 110 // Deactivation Failed UnableToActivate = 111 // Device is not in pre-provisioning mode + UnmarshalMessageFailed = 112 // Unmarshal wsman response failed + DeleteWifiConfigFailed = 113 // Delete wifi configuration failed // (150-199) Maintenance Errors ClockSyncFailed = 150 // Clock sync failed From 3edc3726f86ddc358ddd907adc217a12384b7e5c Mon Sep 17 00:00:00 2001 From: Craig-Spencer-12 Date: Tue, 15 Aug 2023 15:18:03 -0700 Subject: [PATCH 14/29] wip --- internal/local/configure.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/internal/local/configure.go b/internal/local/configure.go index e9149868..a79447b3 100644 --- a/internal/local/configure.go +++ b/internal/local/configure.go @@ -32,7 +32,9 @@ func (service *ProvisioningService) Configure() int { } func (service *ProvisioningService) ConfigureWiFi() int { - service.pruneWifiConfigs() + if errCode := service.pruneWifiConfigs(); errCode != 0 { + return errCode + } err := service.EnableWifi() if err != nil { log.Error(err) @@ -60,7 +62,7 @@ func (service *ProvisioningService) ConfigureWiFi() int { return utils.Success } -func (service *ProvisioningService) pruneWifiConfigs() { +func (service *ProvisioningService) pruneWifiConfigs() int { // Removes existing wifi configs enumerateMessage := service.cimMessages.WiFiEndpointSettings.Enumerate() enumerateResponse, err := service.client.Post(enumerateMessage) @@ -98,7 +100,7 @@ func (service *ProvisioningService) pruneWifiConfigs() { fmt.Println(deleteMessageResponse) } - err = service.EnableWifi() + return 0 } func (service *ProvisioningService) ProcessWifiConfig(wifiCfg *config.WifiConfig) error { From 3d2f77be9af9512fb95f8f4d208e901c0bb80a27 Mon Sep 17 00:00:00 2001 From: Walt Date: Tue, 15 Aug 2023 15:33:58 -0700 Subject: [PATCH 15/29] feat: check if ieee8021x struct is empty --- internal/flags/configure.go | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/internal/flags/configure.go b/internal/flags/configure.go index 2bbb1ad2..20dd9098 100644 --- a/internal/flags/configure.go +++ b/internal/flags/configure.go @@ -78,21 +78,29 @@ func (f *Flags) handleAddWifiSettings() int { f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.CACert, "caCert", "", "specify CA certificate") f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.PrivateKey, "privateKey", "", "specify private key") - f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfg) - f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, ieee8021xCfg) - if err := f.flagSetAddWifiSettings.Parse(f.commandLineArgs[3:]); err != nil { f.printConfigurationUsage() return utils.IncorrectCommandLineParameters } - err := cleanenv.ReadConfig(f.configContent, &f.LocalConfig) - if err != nil { - log.Error("config error: ", err) - return utils.IncorrectCommandLineParameters + + f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfg) + //Check if ieee8021x is empty, if so do not append. + if !ieee8021xCfgIsEmpty(ieee8021xCfg) { + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, ieee8021xCfg) } + + if f.configContent != "" { + err := cleanenv.ReadConfig(f.configContent, &f.LocalConfig) + if err != nil { + log.Error("config error: ", err) + return utils.IncorrectCommandLineParameters + } + } + configFileStatus := f.verifyWifiConfigurationFile() if configFileStatus != 0 { - log.Error("config error: ", err) + log.Error("config error") + // log.Error("config error: ", err) return utils.IncorrectCommandLineParameters } return utils.Success @@ -161,3 +169,12 @@ func (f *Flags) verifyWifiConfigurationFile() int { } return utils.Success } +func ieee8021xCfgIsEmpty(config config.Ieee8021xConfig) bool { + return config.ProfileName == "" && + config.Username == "" && + config.Password == "" && + config.AuthenticationProtocol == 0 && + config.ClientCert == "" && + config.CACert == "" && + config.PrivateKey == "" +} From e819b46b7a610fa03b8ef7fd61a56cbb6acc1848 Mon Sep 17 00:00:00 2001 From: Walt Date: Tue, 15 Aug 2023 16:42:13 -0700 Subject: [PATCH 16/29] feat: adds cli parameter tests WIP --- internal/flags/configure_test.go | 94 +++++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 8 deletions(-) diff --git a/internal/flags/configure_test.go b/internal/flags/configure_test.go index c514828b..71f15440 100644 --- a/internal/flags/configure_test.go +++ b/internal/flags/configure_test.go @@ -10,14 +10,70 @@ import ( ) func TestHandleConfigureCommand(t *testing.T) { - cmdLine := "rpc configure addwifisettings -password Passw0rd! -config ../../config-wifi.yaml " - args := strings.Fields(cmdLine) - flags := NewFlags(args) - gotResult := flags.ParseFlags() - assert.Equal(t, flags.Local, true) - assert.Equal(t, utils.Success, gotResult) - assert.Equal(t, utils.CommandConfigure, flags.Command) - assert.Equal(t, utils.SubCommandAddWifiSettings, flags.SubCommand) + cases := []struct { + description string + cmdLine string + flagsLocal bool + expectedResult int + }{ + // {description: "Basic wifi config command line", + // cmdLine: "rpc configure addwifisettings -password Passw0rd! -profilename cliprofname -authenticationMethod 6 -encryptionMethod 4 -ssid \"myclissid\" -priority 1 -PskPassphrase \"mypassword\" -Ieee8021xProfileName \"\"", + // flagsLocal: true, + // expectedResult: utils.Success, + // }, + {description: "Missing Ieee8021xProfileName value", + cmdLine: "rpc configure addwifisettings -password Passw0rd! -profilename cliprofname -authenticationMethod 6 -encryptionMethod 4 -ssid \"myclissid\" -priority 1 -PskPassphrase \"mypassword\" -Ieee8021xProfileName", + flagsLocal: false, + expectedResult: utils.IncorrectCommandLineParameters, + }, + {description: "Missing PskPassphrase value", + cmdLine: "rpc configure addwifisettings -password Passw0rd! -profilename cliprofname -authenticationMethod 6 -encryptionMethod 4 -ssid \"myclissid\" -priority 1 -PskPassphrase", + flagsLocal: false, + expectedResult: utils.IncorrectCommandLineParameters, + }, + {description: "Missing priority value", + cmdLine: "rpc configure addwifisettings -password Passw0rd! -profilename cliprofname -authenticationMethod 6 -encryptionMethod 4 -ssid \"myclissid\" -priority", + flagsLocal: false, + expectedResult: utils.IncorrectCommandLineParameters, + }, + {description: "Missing ssid value", + cmdLine: "rpc configure addwifisettings -password Passw0rd! -profilename cliprofname -authenticationMethod 6 -encryptionMethod 4 -ssid", + flagsLocal: false, + expectedResult: utils.IncorrectCommandLineParameters, + }, + {description: "Missing authenticationMethod value", + cmdLine: "rpc configure addwifisettings -password Passw0rd! -profilename cliprofname -authenticationMethod", + flagsLocal: false, + expectedResult: utils.IncorrectCommandLineParameters, + }, + {description: "Missing profile name", + cmdLine: "rpc configure addwifisettings -password Passw0rd! -profilename", + flagsLocal: false, + expectedResult: utils.IncorrectCommandLineParameters, + }, + {description: "Missing filename", + cmdLine: "rpc configure addwifisettings -password Passw0rd! -config", + flagsLocal: false, + expectedResult: utils.IncorrectCommandLineParameters, + }, + {description: "Valid with reading from file", + cmdLine: "rpc configure addwifisettings -password Passw0rd! -config ../../config-wifi.yaml", + flagsLocal: true, + expectedResult: utils.Success, + }, + } + for _, tc := range cases { + t.Run(tc.description, func(t *testing.T) { + args := strings.Fields(tc.cmdLine) + flags := NewFlags(args) + gotResult := flags.ParseFlags() + + assert.Equal(t, flags.Local, tc.flagsLocal) + assert.Equal(t, tc.expectedResult, gotResult) + assert.Equal(t, utils.CommandConfigure, flags.Command) + assert.Equal(t, utils.SubCommandAddWifiSettings, flags.SubCommand) + }) + } } func TestVerifyWifiConfigurationFile(t *testing.T) { @@ -273,3 +329,25 @@ func TestVerifyWifiConfigurationFile(t *testing.T) { }) } } +func TestIeee8021xCfgIsEmpty(t *testing.T) { + emptyConfig := config.Ieee8021xConfig{} + notEmptyConfig := config.Ieee8021xConfig{ + ProfileName: "wifi-8021x", + Username: "user", + Password: "pass", + AuthenticationProtocol: 1, + ClientCert: "cert", + CACert: "caCert", + PrivateKey: "key", + } + + empty := ieee8021xCfgIsEmpty(emptyConfig) + if !empty { + t.Errorf("Expected empty config to return true, but got false") + } + + notEmpty := ieee8021xCfgIsEmpty(notEmptyConfig) + if notEmpty { + t.Errorf("Expected non-empty config to return false, but got true") + } +} From a3b1e6e3ff8e194b86a59e8502f8978abc7a7929 Mon Sep 17 00:00:00 2001 From: Craig Spencer Date: Wed, 16 Aug 2023 09:25:48 -0700 Subject: [PATCH 17/29] removes print statement --- internal/local/configure.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/internal/local/configure.go b/internal/local/configure.go index a79447b3..8615bfd0 100644 --- a/internal/local/configure.go +++ b/internal/local/configure.go @@ -32,7 +32,7 @@ func (service *ProvisioningService) Configure() int { } func (service *ProvisioningService) ConfigureWiFi() int { - if errCode := service.pruneWifiConfigs(); errCode != 0 { + if errCode := service.PruneWifiConfigs(); errCode != 0 { return errCode } err := service.EnableWifi() @@ -62,7 +62,7 @@ func (service *ProvisioningService) ConfigureWiFi() int { return utils.Success } -func (service *ProvisioningService) pruneWifiConfigs() int { +func (service *ProvisioningService) PruneWifiConfigs() int { // Removes existing wifi configs enumerateMessage := service.cimMessages.WiFiEndpointSettings.Enumerate() enumerateResponse, err := service.client.Post(enumerateMessage) @@ -97,7 +97,6 @@ func (service *ProvisioningService) pruneWifiConfigs() int { log.Error(err) return utils.DeleteWifiConfigFailed } - fmt.Println(deleteMessageResponse) } return 0 From 6bd300e4d0a9f94675cbb475f9e9f7dfabe50862 Mon Sep 17 00:00:00 2001 From: Craig Spencer Date: Wed, 16 Aug 2023 09:29:12 -0700 Subject: [PATCH 18/29] Adds info statement --- internal/local/configure.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/local/configure.go b/internal/local/configure.go index 8615bfd0..a8e4a9b7 100644 --- a/internal/local/configure.go +++ b/internal/local/configure.go @@ -97,6 +97,7 @@ func (service *ProvisioningService) PruneWifiConfigs() int { log.Error(err) return utils.DeleteWifiConfigFailed } + log.Info(deleteMessageResponse) } return 0 From bb6ccdad7d39f5f7da009d9f9acdc36f09ecf61a Mon Sep 17 00:00:00 2001 From: Craig Spencer Date: Wed, 16 Aug 2023 10:57:06 -0700 Subject: [PATCH 19/29] Unit tests for PruneWifiConfigs --- internal/local/configure.go | 3 +- internal/local/configure_test.go | 49 ++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/internal/local/configure.go b/internal/local/configure.go index a8e4a9b7..2064cbc3 100644 --- a/internal/local/configure.go +++ b/internal/local/configure.go @@ -92,12 +92,11 @@ func (service *ProvisioningService) PruneWifiConfigs() int { for _, config := range pullEnvelope.Body.PullResponse.Items.WifiSettings { deleteMessage := service.cimMessages.WiFiEndpointSettings.Delete(config.InstanceID) - deleteMessageResponse, err := service.client.Post(deleteMessage) + _, err := service.client.Post(deleteMessage) if err != nil { log.Error(err) return utils.DeleteWifiConfigFailed } - log.Info(deleteMessageResponse) } return 0 diff --git a/internal/local/configure_test.go b/internal/local/configure_test.go index 75a6f298..c9902fa7 100644 --- a/internal/local/configure_test.go +++ b/internal/local/configure_test.go @@ -3,9 +3,6 @@ package local import ( "encoding/xml" "fmt" - "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/amt/wifiportconfiguration" - "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim/models" - "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim/wifi" "net/http" "rpc/internal/config" "rpc/internal/flags" @@ -13,6 +10,10 @@ import ( "strings" "testing" + "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/amt/wifiportconfiguration" + "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim/models" + "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim/wifi" + "github.com/stretchr/testify/assert" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/common" @@ -211,6 +212,48 @@ func TestProcessWifiConfig(t *testing.T) { }) } +func TestPruneWifiConfigs(t *testing.T) { + f := &flags.Flags{} + + t.Run("expect success when there are no configs", func(t *testing.T) { + responsers := ResponseFuncArray{} + responsers = append(responsers, respondMsgFunc(t, wifi.EnumerationEnvelope{})) + responsers = append(responsers, respondMsgFunc(t, wifi.PullEnvelope{})) + lps := setupWsmanResponses(t, f, responsers) + errCode := lps.PruneWifiConfigs() + assert.Equal(t, 0, errCode) + }) + t.Run("expect success when there are configs", func(t *testing.T) { + pullEnvelope := wifi.PullEnvelope{} + pullEnvelope.Body.PullResponse.Items.WifiSettings = append(pullEnvelope.Body.PullResponse.Items.WifiSettings, wifi.CIMWiFiEndpointSettings{InstanceID: "Config1"}) + pullEnvelope.Body.PullResponse.Items.WifiSettings = append(pullEnvelope.Body.PullResponse.Items.WifiSettings, wifi.CIMWiFiEndpointSettings{InstanceID: "Config2"}) + + responsers := ResponseFuncArray{} + responsers = append(responsers, respondMsgFunc(t, wifi.EnumerationEnvelope{})) + responsers = append(responsers, respondMsgFunc(t, pullEnvelope)) + responsers = append(responsers, respondMsgFunc(t, "Config1 Deleted")) + responsers = append(responsers, respondMsgFunc(t, "Config2 Deleted")) + lps := setupWsmanResponses(t, f, responsers) + errCode := lps.PruneWifiConfigs() + assert.Equal(t, 0, errCode) + }) + t.Run("expect error when enumeration not returned", func(t *testing.T) { + responsers := ResponseFuncArray{} + responsers = append(responsers, respondMsgFunc(t, "Not an enumeration envelope")) + lps := setupWsmanResponses(t, f, responsers) + errCode := lps.PruneWifiConfigs() + assert.Equal(t, utils.UnmarshalMessageFailed, errCode) + }) + t.Run("expect error when pull not returned", func(t *testing.T) { + responsers := ResponseFuncArray{} + responsers = append(responsers, respondMsgFunc(t, wifi.EnumerationEnvelope{})) + responsers = append(responsers, respondMsgFunc(t, "Not a pull envelope")) + lps := setupWsmanResponses(t, f, responsers) + errCode := lps.PruneWifiConfigs() + assert.Equal(t, utils.UnmarshalMessageFailed, errCode) + }) +} + func TestProcessIeee8012xConfig(t *testing.T) { f := &flags.Flags{} From 7cdee643d200d86e997cb7651ea9ebfa789c17e6 Mon Sep 17 00:00:00 2001 From: Craig Spencer Date: Wed, 16 Aug 2023 11:14:40 -0700 Subject: [PATCH 20/29] fix unit tests --- internal/local/configure_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/local/configure_test.go b/internal/local/configure_test.go index c9902fa7..a7e610a8 100644 --- a/internal/local/configure_test.go +++ b/internal/local/configure_test.go @@ -136,6 +136,8 @@ func TestConfigure(t *testing.T) { t.Run("returns WiFiConfigurationFailed handling WifiConfigs from LocalConfig", func(t *testing.T) { f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfgWPA) responsers := ResponseFuncArray{} + responsers = append(responsers, respondMsgFunc(t, wifi.EnumerationEnvelope{})) // PruneWifiConfigs + responsers = append(responsers, respondMsgFunc(t, wifi.PullEnvelope{})) // PruneWifiConfigs responsers = append(responsers, respondServerErrFunc()) lps := setupWsmanResponses(t, f, responsers) resultCode := lps.Configure() @@ -150,6 +152,8 @@ func TestConfigureWiFi(t *testing.T) { pcsRsp := wifiportconfiguration.PortConfigurationResponse{} pcsRsp.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled = 1 responsers := ResponseFuncArray{} + responsers = append(responsers, respondMsgFunc(t, wifi.EnumerationEnvelope{})) // PruneWifiConfigs + responsers = append(responsers, respondMsgFunc(t, wifi.PullEnvelope{})) // PruneWifiConfigs responsers = append(responsers, respondMsgFunc(t, pcsRsp)) responsers = append(responsers, respondMsgFunc(t, wifi.RequestStateChangeResponse{})) responsers = append(responsers, respondMsgFunc(t, wifiportconfiguration.AddWiFiSettingsResponse{})) @@ -161,6 +165,8 @@ func TestConfigureWiFi(t *testing.T) { orig := f.LocalConfig.WifiConfigs[0].ProfileName f.LocalConfig.WifiConfigs[0].ProfileName = "bad-name" responsers := ResponseFuncArray{} + responsers = append(responsers, respondMsgFunc(t, wifi.EnumerationEnvelope{})) // PruneWifiConfigs + responsers = append(responsers, respondMsgFunc(t, wifi.PullEnvelope{})) // PruneWifiConfigs responsers = append(responsers, respondMsgFunc(t, wifiportconfiguration.PortConfigurationResponse{})) responsers = append(responsers, respondMsgFunc(t, wifi.RequestStateChangeResponse{})) responsers = append(responsers, respondMsgFunc(t, wifiportconfiguration.AddWiFiSettingsResponse{})) From 5bcb79d7f21cb9af8b8456b4e95ff187269d5b0b Mon Sep 17 00:00:00 2001 From: Tim Shockley Date: Wed, 16 Aug 2023 12:24:42 -0700 Subject: [PATCH 21/29] feat: refactored verifiyConfig tests a bit --- internal/flags/configure.go | 6 +- internal/flags/configure_test.go | 408 ++++++++++++------------------- 2 files changed, 163 insertions(+), 251 deletions(-) diff --git a/internal/flags/configure.go b/internal/flags/configure.go index 20dd9098..e4a70b94 100644 --- a/internal/flags/configure.go +++ b/internal/flags/configure.go @@ -78,6 +78,8 @@ func (f *Flags) handleAddWifiSettings() int { f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.CACert, "caCert", "", "specify CA certificate") f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.PrivateKey, "privateKey", "", "specify private key") + // rpc configure addwifisettings -configstring "{ prop: val, prop2: val }" + // rpc configure add -config "filename" -secrets "someotherfile" if err := f.flagSetAddWifiSettings.Parse(f.commandLineArgs[3:]); err != nil { f.printConfigurationUsage() return utils.IncorrectCommandLineParameters @@ -107,8 +109,6 @@ func (f *Flags) handleAddWifiSettings() int { } func (f *Flags) verifyWifiConfigurationFile() int { - var matchedIeeeProfileName int = 0 - for _, wifiConfigs := range f.LocalConfig.WifiConfigs { //Check profile name is not empty if wifiConfigs.ProfileName == "" { @@ -146,6 +146,8 @@ func (f *Flags) verifyWifiConfigurationFile() int { } if wifiConfigs.AuthenticationMethod == 5 || wifiConfigs.AuthenticationMethod == 7 { //Check for ieee8021xProfileName in IEEE8021XSettings + var matchedIeeeProfileName int = 0 + for _, ieee802xSettings := range f.LocalConfig.Ieee8021xConfigs { if wifiConfigs.Ieee8021xProfileName == ieee802xSettings.ProfileName { matchedIeeeProfileName++ diff --git a/internal/flags/configure_test.go b/internal/flags/configure_test.go index 71f15440..1bf81cb5 100644 --- a/internal/flags/configure_test.go +++ b/internal/flags/configure_test.go @@ -1,6 +1,7 @@ package flags import ( + "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim/models" "rpc/internal/config" "rpc/pkg/utils" "strings" @@ -76,259 +77,168 @@ func TestHandleConfigureCommand(t *testing.T) { } } -func TestVerifyWifiConfigurationFile(t *testing.T) { +var wifiCfgWPA = config.WifiConfig{ + ProfileName: "wifiWPA", + SSID: "ssid", + Priority: 1, + AuthenticationMethod: int(models.AuthenticationMethod_WPA_PSK), + EncryptionMethod: int(models.EncryptionMethod_CCMP), +} - cases := []struct { - description string - testConfiguration Flags - expected int - }{ - { - description: "Missing ProfileName", - testConfiguration: Flags{ - LocalConfig: config.Config{ - WifiConfigs: config.WifiConfigs{ - { - ProfileName: "", - }, - }, - }, - }, - expected: utils.MissingOrIncorrectProfile, - }, - { - description: "Missing SSID", - testConfiguration: Flags{ - LocalConfig: config.Config{ - WifiConfigs: config.WifiConfigs{ - { - ProfileName: "Test-Profile-1", - SSID: "", - }, - }, - }, - }, - expected: utils.MissingOrIncorrectProfile, - }, - { - description: "Missing Priority", - testConfiguration: Flags{ - LocalConfig: config.Config{ - WifiConfigs: config.WifiConfigs{ - { - ProfileName: "Test-Profile-1", - SSID: "Test-SSID-1", - }, - }, - }, - }, - expected: utils.MissingOrIncorrectProfile, - }, - { - description: "Missing AuthenticationMethod", - testConfiguration: Flags{ - LocalConfig: config.Config{ - WifiConfigs: config.WifiConfigs{ - { - ProfileName: "Test-Profile-1", - SSID: "Test-SSID-1", - Priority: 1, - }, - }, - }, - }, - expected: utils.MissingOrIncorrectProfile, - }, - { - description: "Missing EncryptionMethod", - testConfiguration: Flags{ - LocalConfig: config.Config{ - WifiConfigs: config.WifiConfigs{ - { - ProfileName: "Test-Profile-1", - SSID: "Test-SSID-1", - Priority: 1, - AuthenticationMethod: 6, - }, - }, - }, - }, - expected: utils.MissingOrIncorrectProfile, - }, - { - description: "Missing Passphrase when AuthenticationMethod is 6", - testConfiguration: Flags{ - LocalConfig: config.Config{ - WifiConfigs: config.WifiConfigs{ - { - ProfileName: "Test-Profile-1", - SSID: "Test-SSID-1", - Priority: 1, - AuthenticationMethod: 6, - EncryptionMethod: 4, - }, - }, - }, - }, - expected: utils.MissingOrIncorrectProfile, - }, - { - description: "Properly formed config", - testConfiguration: Flags{ - LocalConfig: config.Config{ - WifiConfigs: config.WifiConfigs{ - { - ProfileName: "Test-Profile-1", - SSID: "Test-SSID-1", - Priority: 1, - AuthenticationMethod: 6, - EncryptionMethod: 4, - PskPassphrase: "Test-Passphrase-1", - Ieee8021xProfileName: "", - }, - }, - }, - }, - expected: utils.Success, - }, - { - description: "Passphrase present when AuthenticationMethod is 5", - testConfiguration: Flags{ - LocalConfig: config.Config{ - WifiConfigs: config.WifiConfigs{ - { - ProfileName: "Test-Profile-1", - SSID: "Test-SSID-1", - Priority: 1, - AuthenticationMethod: 5, - EncryptionMethod: 4, - PskPassphrase: "Test-Passphrase-1", - }, - }, - }, - }, - expected: utils.MissingOrIncorrectProfile, - }, - { - description: "Passphrase present when AuthenticationMethod is 7", - testConfiguration: Flags{ - LocalConfig: config.Config{ - WifiConfigs: config.WifiConfigs{ - { - ProfileName: "Test-Profile-1", - SSID: "Test-SSID-1", - Priority: 1, - AuthenticationMethod: 7, - EncryptionMethod: 4, - PskPassphrase: "Test-Passphrase-1", - }, - }, - }, - }, - expected: utils.MissingOrIncorrectProfile, - }, - { - description: "Successfully matches IEEE802.1 ProfileName", - testConfiguration: Flags{ - LocalConfig: config.Config{ - WifiConfigs: config.WifiConfigs{ - { - ProfileName: "Test-Profile-1", - SSID: "Test-SSID-1", - Priority: 1, - AuthenticationMethod: 7, - EncryptionMethod: 4, - PskPassphrase: "", - Ieee8021xProfileName: "Test-IEEE-Profile", - }, - }, - Ieee8021xConfigs: config.Ieee8021xConfigs{ - { - ProfileName: "Test-IEEE-Profile", - }, - }, - }, - }, - expected: utils.Success, - }, - { - description: "Found duplicate IEEE802.1 ProfileName when AuthenticationMethod is 5", - testConfiguration: Flags{ - LocalConfig: config.Config{ - WifiConfigs: config.WifiConfigs{ - { - ProfileName: "Test-Profile-1", - SSID: "Test-SSID-1", - Priority: 1, - AuthenticationMethod: 7, - EncryptionMethod: 4, - PskPassphrase: "", - Ieee8021xProfileName: "Test-IEEE-Profile", - }, - }, - Ieee8021xConfigs: config.Ieee8021xConfigs{ - { - ProfileName: "Test-IEEE-Profile", - }, - { - ProfileName: "Test-IEEE-Profile", - }, - }, - }, - }, - expected: utils.MissingOrIncorrectProfile, - }, - { - description: "Found duplicate IEEE802.1 ProfileName when AuthenticationMethod is 7", - testConfiguration: Flags{ - LocalConfig: config.Config{ - WifiConfigs: config.WifiConfigs{ - { - ProfileName: "Test-Profile-1", - SSID: "Test-SSID-1", - Priority: 1, - AuthenticationMethod: 7, - EncryptionMethod: 4, - PskPassphrase: "", - Ieee8021xProfileName: "Test-IEEE-Profile", - }, - }, - Ieee8021xConfigs: config.Ieee8021xConfigs{ - { - ProfileName: "Test-IEEE-Profile", - }, - { - ProfileName: "Test-IEEE-Profile", - }, - }, - }, - }, - expected: utils.MissingOrIncorrectProfile, - }, - { - description: "Missing ProfileName in IEEE802.1x config", - testConfiguration: Flags{ - LocalConfig: config.Config{ - Ieee8021xConfigs: config.Ieee8021xConfigs{ - { - ProfileName: "", - }, - }, - }, - }, - expected: utils.MissingOrIncorrectProfile, - }, - } +var wifiCfgWPA2 = config.WifiConfig{ + ProfileName: "wifiWPA2", + SSID: "ssid", + Priority: 2, + AuthenticationMethod: int(models.AuthenticationMethod_WPA2_PSK), + EncryptionMethod: int(models.EncryptionMethod_CCMP), + PskPassphrase: "wifiWPAPassPhrase", +} - for _, tt := range cases { - t.Run(tt.description, func(t *testing.T) { - gotResult := tt.testConfiguration.verifyWifiConfigurationFile() - if gotResult != tt.expected { - t.Errorf("expected %d but got %d", tt.expected, gotResult) - } - }) +var wifiCfgWPA8021xEAPTLS = config.WifiConfig{ + ProfileName: "wifiWPA28021x", + SSID: "ssid", + Priority: 2, + AuthenticationMethod: int(models.AuthenticationMethod_WPA_IEEE8021x), + EncryptionMethod: int(models.EncryptionMethod_CCMP), + Ieee8021xProfileName: "ieee8021xCfgEAPTLS", +} + +var ieee8021xCfgEAPTLS = config.Ieee8021xConfig{ + ProfileName: "ieee8021xCfgEAPTLS", + Username: "username", + Password: "", + AuthenticationProtocol: int(models.AuthenticationProtocolEAPTLS), + ClientCert: "clientCert", + CACert: "caCert", + PrivateKey: "privateKey", +} + +var wifiCfgWPA28021xPEAPv0_EAPMSCHAPv2 = config.WifiConfig{ + ProfileName: "wifiWPA28021x", + SSID: "ssid", + Priority: 2, + AuthenticationMethod: int(models.AuthenticationMethod_WPA2_IEEE8021x), + EncryptionMethod: int(models.EncryptionMethod_CCMP), + Ieee8021xProfileName: "ieee8021xCfgPEAPv0_EAPMSCHAPv2", +} + +var ieee8021xCfgPEAPv0_EAPMSCHAPv2 = config.Ieee8021xConfig{ + ProfileName: "ieee8021xCfgPEAPv0_EAPMSCHAPv2", + Username: "username", + Password: "password", + AuthenticationProtocol: int(models.AuthenticationProtocolPEAPv0_EAPMSCHAPv2), + ClientCert: "clientCert", + CACert: "caCert", + PrivateKey: "privateKey", +} + +func runVerifyWifiConfiguration(t *testing.T, expectedResult int, wifiCfgs config.WifiConfigs, ieee8021xCfgs config.Ieee8021xConfigs) { + f := Flags{} + for _, cfg := range wifiCfgs { + f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, cfg) + } + for _, cfg := range ieee8021xCfgs { + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) } + gotResult := f.verifyWifiConfigurationFile() + assert.Equal(t, expectedResult, gotResult) +} + +func TestVerifyWifiConfigurationFile(t *testing.T) { + + t.Run("expect Success for correct configs", func(t *testing.T) { + runVerifyWifiConfiguration(t, utils.Success, + config.WifiConfigs{wifiCfgWPA, wifiCfgWPA2, wifiCfgWPA8021xEAPTLS, wifiCfgWPA28021xPEAPv0_EAPMSCHAPv2}, + config.Ieee8021xConfigs{ieee8021xCfgEAPTLS, ieee8021xCfgPEAPv0_EAPMSCHAPv2}) + }) + t.Run("expect MissingOrIncorrectProfile when missing ProfileName", func(t *testing.T) { + orig := wifiCfgWPA.ProfileName + wifiCfgWPA.ProfileName = "" + runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + config.WifiConfigs{wifiCfgWPA}, + config.Ieee8021xConfigs{}) + wifiCfgWPA.ProfileName = orig + }) + t.Run("expect MissingOrIncorrectProfile when missing SSID", func(t *testing.T) { + orig := wifiCfgWPA.SSID + wifiCfgWPA.SSID = "" + runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + config.WifiConfigs{wifiCfgWPA}, + config.Ieee8021xConfigs{}) + wifiCfgWPA.SSID = orig + }) + t.Run("expect MissingOrIncorrectProfile with invalid Priority", func(t *testing.T) { + orig := wifiCfgWPA.Priority + wifiCfgWPA.Priority = 0 + runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + config.WifiConfigs{wifiCfgWPA}, + config.Ieee8021xConfigs{}) + wifiCfgWPA.Priority = orig + }) + t.Run("expect MissingOrIncorrectProfile with invalid AuthenticationMethod", func(t *testing.T) { + orig := wifiCfgWPA.AuthenticationMethod + wifiCfgWPA.AuthenticationMethod = 0 + runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + config.WifiConfigs{wifiCfgWPA}, + config.Ieee8021xConfigs{}) + wifiCfgWPA.AuthenticationMethod = orig + }) + t.Run("expect MissingOrIncorrectProfile with invalid EncryptionMethod", func(t *testing.T) { + orig := wifiCfgWPA.EncryptionMethod + wifiCfgWPA.EncryptionMethod = 0 + runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + config.WifiConfigs{wifiCfgWPA}, + config.Ieee8021xConfigs{}) + wifiCfgWPA.EncryptionMethod = orig + }) + t.Run("expect MissingOrIncorrectProfile with missing passphrase", func(t *testing.T) { + orig := wifiCfgWPA2.PskPassphrase + wifiCfgWPA2.PskPassphrase = "" + runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + config.WifiConfigs{wifiCfgWPA2}, + config.Ieee8021xConfigs{}) + wifiCfgWPA2.PskPassphrase = orig + }) + t.Run("expect MissingOrIncorrectProfile with missing ieee8021x ProfileName", func(t *testing.T) { + orig8021xName := ieee8021xCfgEAPTLS.ProfileName + ieee8021xCfgEAPTLS.ProfileName = "" + runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + config.WifiConfigs{wifiCfgWPA8021xEAPTLS}, + config.Ieee8021xConfigs{ieee8021xCfgEAPTLS}) + ieee8021xCfgEAPTLS.ProfileName = orig8021xName + }) + t.Run("expect MissingOrIncorrectProfile with PskPassphrase is present for ieee8021x profile", func(t *testing.T) { + wifiCfgWPA8021xEAPTLS.PskPassphrase = "shouldn't be here" + runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + config.WifiConfigs{wifiCfgWPA8021xEAPTLS}, + config.Ieee8021xConfigs{ieee8021xCfgEAPTLS}) + wifiCfgWPA8021xEAPTLS.PskPassphrase = "" + }) + t.Run("expect MissingOrIncorrectProfile with PskPassphrase is present for ieee8021x profile", func(t *testing.T) { + wifiCfgWPA28021xPEAPv0_EAPMSCHAPv2.PskPassphrase = "shouldn't be here" + runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + config.WifiConfigs{wifiCfgWPA28021xPEAPv0_EAPMSCHAPv2}, + config.Ieee8021xConfigs{ieee8021xCfgPEAPv0_EAPMSCHAPv2}) + wifiCfgWPA28021xPEAPv0_EAPMSCHAPv2.PskPassphrase = "" + }) + + t.Run("expect MissingOrIncorrectProfile with duplicate ieee8021x ProfileName", func(t *testing.T) { + orig8021xName := ieee8021xCfgEAPTLS.ProfileName + ieee8021xCfgEAPTLS.ProfileName = ieee8021xCfgPEAPv0_EAPMSCHAPv2.ProfileName + wifiCfgWPA8021xEAPTLS.Ieee8021xProfileName = ieee8021xCfgPEAPv0_EAPMSCHAPv2.ProfileName + // authMethod 5 + runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + config.WifiConfigs{wifiCfgWPA8021xEAPTLS}, + config.Ieee8021xConfigs{ieee8021xCfgEAPTLS, ieee8021xCfgPEAPv0_EAPMSCHAPv2}) + // authMethod 7 + runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + config.WifiConfigs{wifiCfgWPA28021xPEAPv0_EAPMSCHAPv2}, + config.Ieee8021xConfigs{ieee8021xCfgEAPTLS, ieee8021xCfgPEAPv0_EAPMSCHAPv2}) + ieee8021xCfgEAPTLS.ProfileName = orig8021xName + wifiCfgWPA8021xEAPTLS.Ieee8021xProfileName = ieee8021xCfgEAPTLS.ProfileName + }) } + func TestIeee8021xCfgIsEmpty(t *testing.T) { emptyConfig := config.Ieee8021xConfig{} notEmptyConfig := config.Ieee8021xConfig{ From 674f8d459bb7d93b0b756e37f1afbfb6b4f5368b Mon Sep 17 00:00:00 2001 From: Walt M Date: Wed, 16 Aug 2023 20:23:46 -0700 Subject: [PATCH 22/29] feat: adds -secret flag on command line, WIP read --- internal/config/local.go | 8 ++++++++ internal/flags/configure.go | 20 +++++++++++++++++++- internal/flags/flags.go | 4 +++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/internal/config/local.go b/internal/config/local.go index 5ee64261..b1b90216 100644 --- a/internal/config/local.go +++ b/internal/config/local.go @@ -6,6 +6,7 @@ type ( IEEE8021XSettings `yaml:"ieee801xConfig"` WifiConfigs `yaml:"wifiConfigs"` Ieee8021xConfigs `yaml:"ieee8021xConfigs"` + SecretConfigs `yaml:"secretConfig"` ACMSettings `yaml:"acmactivate"` } IEEE8021XSettings struct { @@ -30,6 +31,12 @@ type ( PskPassphrase string `yaml:"pskPassphrase"` Ieee8021xProfileName string `yaml:"ieee8021xProfileName"` } + SecretConfigs []SecretConfig + SecretConfig struct { + ClientCert string `yaml:"secretClientCert"` + CACert string `yaml:"secretCaCert"` + PrivateKey string `yaml:"secretPrivateKey"` + } Ieee8021xConfigs []Ieee8021xConfig Ieee8021xConfig struct { ProfileName string `yaml:"profileName"` @@ -40,6 +47,7 @@ type ( CACert string `yaml:"caCert"` PrivateKey string `yaml:"privateKey"` } + ACMSettings struct { AMTPassword string `yaml:"amtPassword"` ProvisioningCert string `yaml:"provisioningCert"` diff --git a/internal/flags/configure.go b/internal/flags/configure.go index e4a70b94..4a1f6425 100644 --- a/internal/flags/configure.go +++ b/internal/flags/configure.go @@ -62,9 +62,11 @@ func (f *Flags) handleAddWifiSettings() int { f.flagSetAddWifiSettings.BoolVar(&f.JsonOutput, "json", false, "JSON output") f.flagSetAddWifiSettings.StringVar(&f.Password, "password", f.lookupEnvOrString("AMT_PASSWORD", ""), "AMT password") f.flagSetAddWifiSettings.StringVar(&f.configContent, "config", "", "specify a config file ") + f.flagSetAddWifiSettings.StringVar(&f.secretContent, "secret", "", "specify a config file ") // TODO: these are the params for entering a single wifi config from command line wifiCfg := config.WifiConfig{} ieee8021xCfg := config.Ieee8021xConfig{} + secretCfg := config.SecretConfig{} f.flagSetAddWifiSettings.StringVar(&wifiCfg.ProfileName, "profileName", "", "specify wifi profile name name") f.flagSetAddWifiSettings.IntVar(&wifiCfg.AuthenticationMethod, "authenticationMethod", 0, "specify authentication method") f.flagSetAddWifiSettings.IntVar(&wifiCfg.EncryptionMethod, "encryptionMethod", 0, "specify encryption method") @@ -77,12 +79,20 @@ func (f *Flags) handleAddWifiSettings() int { f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.ClientCert, "clientCert", "", "specify client certificate") f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.CACert, "caCert", "", "specify CA certificate") f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.PrivateKey, "privateKey", "", "specify private key") + f.flagSetAddWifiSettings.StringVar(&secretCfg.ClientCert, "secretClientCert", "", "specify client certificate") + f.flagSetAddWifiSettings.StringVar(&secretCfg.CACert, "secretCaCert", "", "specify CA certificate") + f.flagSetAddWifiSettings.StringVar(&secretCfg.PrivateKey, "secretPrivateKey", "", "specify private key") // rpc configure addwifisettings -configstring "{ prop: val, prop2: val }" // rpc configure add -config "filename" -secrets "someotherfile" if err := f.flagSetAddWifiSettings.Parse(f.commandLineArgs[3:]); err != nil { f.printConfigurationUsage() - return utils.IncorrectCommandLineParameters + if f.Password == "" { + log.Error("commandline error: missing password") + return utils.MissingOrIncorrectPassword + } else { + return utils.IncorrectCommandLineParameters + } } f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfg) @@ -99,6 +109,14 @@ func (f *Flags) handleAddWifiSettings() int { } } + if f.secretContent != "" { + err := cleanenv.ReadConfig(f.secretContent, &f.LocalConfig) + if err != nil { + log.Error("secrets error: ", err) + return utils.IncorrectCommandLineParameters + } + } + configFileStatus := f.verifyWifiConfigurationFile() if configFileStatus != 0 { log.Error("config error") diff --git a/internal/flags/flags.go b/internal/flags/flags.go index 0e08e0a4..7edd93be 100644 --- a/internal/flags/flags.go +++ b/internal/flags/flags.go @@ -7,7 +7,6 @@ package flags import ( "flag" "fmt" - "github.com/ilyakaznacheev/cleanenv" "net" "os" "path/filepath" @@ -17,6 +16,8 @@ import ( "strconv" "time" + "github.com/ilyakaznacheev/cleanenv" + log "github.com/sirupsen/logrus" ) @@ -65,6 +66,7 @@ type Flags struct { UseCCM bool UseACM bool configContent string + secretContent string LocalConfig config.Config amtInfoCommand *flag.FlagSet amtActivateCommand *flag.FlagSet From 3ce6982203363896b922ce5eef275942c6a8cb8d Mon Sep 17 00:00:00 2001 From: Tim Shockley Date: Wed, 16 Aug 2023 22:15:14 -0700 Subject: [PATCH 23/29] fix: refactored for consistency --- internal/local/configure.go | 224 +++++++++++++------------ internal/local/configure_test.go | 270 ++++++++++++++----------------- internal/local/lps.go | 3 - internal/local/lps_test.go | 51 +++++- pkg/utils/constants.go | 36 +++-- 5 files changed, 314 insertions(+), 270 deletions(-) diff --git a/internal/local/configure.go b/internal/local/configure.go index 3d29e8ce..aa81ee9b 100644 --- a/internal/local/configure.go +++ b/internal/local/configure.go @@ -2,7 +2,6 @@ package local import ( "encoding/xml" - "errors" "fmt" "regexp" "rpc/internal/config" @@ -19,78 +18,54 @@ import ( func (service *ProvisioningService) Configure() int { service.setupWsmanClient("admin", service.flags.Password) - //if service.flags.SubCommand == utils.SubCommandAddWifiSettings { - // err := service.Configure8021xWiFi() - // if err != nil { - // return utils.WiFiConfigurationFailed - // } - //} - if len(service.flags.LocalConfig.WifiConfigs) > 0 { - return service.ConfigureWiFi() + if service.flags.SubCommand == utils.SubCommandAddWifiSettings { + return service.AddWifiSettings() } return utils.IncorrectCommandLineParameters } -func (service *ProvisioningService) ConfigureWiFi() int { - if errCode := service.PruneWifiConfigs(); errCode != 0 { - return errCode +func (service *ProvisioningService) AddWifiSettings() int { + resultCode := service.PruneWifiConfigs() + if resultCode != utils.Success { + return resultCode } - err := service.EnableWifi() - if err != nil { - log.Error(err) - return utils.WiFiConfigurationFailed - } - lc := service.flags.LocalConfig - var successes []string - var failures []string - for _, cfg := range lc.WifiConfigs { - log.Info("configuring wifi profile: ", cfg.ProfileName) - err = service.ProcessWifiConfig(&cfg) - if err != nil { - log.Error("failed configuring: ", cfg.ProfileName) - log.Error(err) - failures = append(failures, cfg.ProfileName) - } else { - log.Info("successfully configured: ", cfg.ProfileName) - successes = append(successes, cfg.ProfileName) - } - } - if len(failures) > 0 { - return utils.WifiConfigurationWithWarnings + resultCode = service.EnableWifi() + if resultCode != utils.Success { + return resultCode } - return utils.Success + return service.ProcessWifiConfigs() } func (service *ProvisioningService) PruneWifiConfigs() int { // Removes existing wifi configs - enumerateMessage := service.cimMessages.WiFiEndpointSettings.Enumerate() - enumerateResponse, err := service.client.Post(enumerateMessage) + xmlMsg := service.cimMessages.WiFiEndpointSettings.Enumerate() + xmlRsp, err := service.client.Post(xmlMsg) if err != nil { log.Error(err) return utils.WSMANMessageError } var enumerationEnvelope wifi.EnumerationEnvelope - if err := xml.Unmarshal(enumerateResponse, &enumerationEnvelope); err != nil { + if err := xml.Unmarshal(xmlRsp, &enumerationEnvelope); err != nil { log.Error(err) return utils.UnmarshalMessageFailed } - pullMessage := service.cimMessages.WiFiEndpointSettings.Pull(enumerationEnvelope.Body.EnumerateResponse.EnumerationContext) - pullResponse, err := service.client.Post(pullMessage) + xmlMsg = service.cimMessages.WiFiEndpointSettings.Pull(enumerationEnvelope.Body.EnumerateResponse.EnumerationContext) + xmlRsp, err = service.client.Post(xmlMsg) if err != nil { log.Error(err) return utils.WSMANMessageError } var pullEnvelope wifi.PullEnvelope - if err := xml.Unmarshal(pullResponse, &pullEnvelope); err != nil { + if err := xml.Unmarshal(xmlRsp, &pullEnvelope); err != nil { log.Error(err) return utils.UnmarshalMessageFailed } - for _, config := range pullEnvelope.Body.PullResponse.Items.WifiSettings { - deleteMessage := service.cimMessages.WiFiEndpointSettings.Delete(config.InstanceID) + for _, wifiSetting := range pullEnvelope.Body.PullResponse.Items.WifiSettings { + deleteMessage := service.cimMessages.WiFiEndpointSettings.Delete(wifiSetting.InstanceID) _, err := service.client.Post(deleteMessage) if err != nil { log.Error(err) @@ -101,12 +76,38 @@ func (service *ProvisioningService) PruneWifiConfigs() int { return 0 } -func (service *ProvisioningService) ProcessWifiConfig(wifiCfg *config.WifiConfig) error { +func (service *ProvisioningService) ProcessWifiConfigs() int { + lc := service.flags.LocalConfig + var successes []string + var failures []string + for _, cfg := range lc.WifiConfigs { + log.Info("configuring wifi profile: ", cfg.ProfileName) + resultCode := service.ProcessWifiConfig(&cfg) + if resultCode != utils.Success { + log.Error("failed configuring: ", cfg.ProfileName) + failures = append(failures, cfg.ProfileName) + } else { + log.Info("successfully configured: ", cfg.ProfileName) + successes = append(successes, cfg.ProfileName) + } + } + if len(failures) > 0 { + if len(successes) > 0 { + return utils.WifiConfigurationWithWarnings + } else { + return utils.WiFiConfigurationFailed + } + } + return utils.Success +} + +func (service *ProvisioningService) ProcessWifiConfig(wifiCfg *config.WifiConfig) int { // profile names can only be alphanumeric (not even dashes) var reAlphaNum = regexp.MustCompile("[^a-zA-Z0-9]+") if reAlphaNum.MatchString(wifiCfg.ProfileName) { - return fmt.Errorf("invalid wifi profile name: %s (only alphanumeric allowed)", wifiCfg.ProfileName) + log.Errorf("invalid wifi profile name: %s (only alphanumeric allowed)", wifiCfg.ProfileName) + return utils.MissingOrIncorrectWifiProfileName } wiFiEndpointSettings := models.WiFiEndpointSettings{ @@ -124,10 +125,10 @@ func (service *ProvisioningService) ProcessWifiConfig(wifiCfg *config.WifiConfig wiFiEndpointSettings.AuthenticationMethod == models.AuthenticationMethod_WPA2_IEEE8021x { ieee8021xSettings = &models.IEEE8021xSettings{} - err := service.ProcessIeee8012xConfig(wifiCfg.Ieee8021xProfileName, ieee8021xSettings, &handles) - if err != nil { + resultCode := service.ProcessIeee8012xConfig(wifiCfg.Ieee8021xProfileName, ieee8021xSettings, &handles) + if resultCode != utils.Success { service.RollbackAddedItems(&handles) - return err + return resultCode } } else { @@ -142,23 +143,24 @@ func (service *ProvisioningService) ProcessWifiConfig(wifiCfg *config.WifiConfig xmlRsp, err := service.client.Post(xmlMsg) if err != nil { service.RollbackAddedItems(&handles) - return err + return utils.WSMANMessageError } var addWifiSettingsRsp wifiportconfiguration.AddWiFiSettingsResponse err = xml.Unmarshal(xmlRsp, &addWifiSettingsRsp) if err != nil { service.RollbackAddedItems(&handles) - return err + return utils.UnmarshalMessageFailed } returnValue := addWifiSettingsRsp.Body.AddWiFiSettings_OUTPUT.ReturnValue if returnValue != 0 { service.RollbackAddedItems(&handles) - return fmt.Errorf("AddWiFiSettings_OUTPUT.ReturnValue: %d", returnValue) + log.Errorf("AddWiFiSettings_OUTPUT.ReturnValue: %d", returnValue) + return utils.AmtPtStatusCodeBase + returnValue } - return nil + return utils.Success } -func (service *ProvisioningService) ProcessIeee8012xConfig(profileName string, settings *models.IEEE8021xSettings, handles *Handles) error { +func (service *ProvisioningService) ProcessIeee8012xConfig(profileName string, settings *models.IEEE8021xSettings, handles *Handles) int { // find the matching configuration var ieee8021xConfig *config.Ieee8021xConfig @@ -168,8 +170,8 @@ func (service *ProvisioningService) ProcessIeee8012xConfig(profileName string, s } } if ieee8021xConfig == nil { - errMsg := fmt.Sprintf("missing Ieee8021xConfig %s", profileName) - return errors.New(errMsg) + log.Errorf("missing Ieee8021xConfig %s", profileName) + return utils.MissingIeee8021xConfiguration } // translate from configuration to settings @@ -182,32 +184,31 @@ func (service *ProvisioningService) ProcessIeee8012xConfig(profileName string, s } // add key and certs - var err error - handles.privateKeyHandle, err = service.AddPrivateKey(ieee8021xConfig.PrivateKey) - if err != nil { - return err + var resultCode int + handles.privateKeyHandle, resultCode = service.AddPrivateKey(ieee8021xConfig.PrivateKey) + if resultCode != utils.Success { + return resultCode } - handles.clientCertHandle, err = service.AddClientCert(ieee8021xConfig.ClientCert) - if err != nil { - return err + handles.clientCertHandle, resultCode = service.AddClientCert(ieee8021xConfig.ClientCert) + if resultCode != utils.Success { + return resultCode } - handles.rootCertHandle, err = service.AddTrustedRootCert(ieee8021xConfig.CACert) - if err != nil { - return err - } - return nil + handles.rootCertHandle, resultCode = service.AddTrustedRootCert(ieee8021xConfig.CACert) + return resultCode } -func (service *ProvisioningService) EnableWifi() error { +func (service *ProvisioningService) EnableWifi() int { xmlMsg := service.amtMessages.WiFiPortConfigurationService.Get() xmlRsp, err := service.client.Post(xmlMsg) if err != nil { - return err + log.Error(err) + return utils.WSMANMessageError } var wifiPortConfigResponse wifiportconfiguration.PortConfigurationResponse err = xml.Unmarshal(xmlRsp, &wifiPortConfigResponse) if err != nil { - return err + log.Error(err) + return utils.UnmarshalMessageFailed } // if local sync not enable, enable it @@ -218,15 +219,18 @@ func (service *ProvisioningService) EnableWifi() error { // no response struct in wsmang messages xmlRsp, err = service.client.Post(xmlMsg) if err != nil { - return err + log.Error(err) + return utils.WSMANMessageError } err = xml.Unmarshal(xmlRsp, &wifiPortConfigResponse) if err != nil { - return err + log.Error(err) + return utils.UnmarshalMessageFailed } if wifiPortConfigResponse.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled == 0 { - return errors.New("failed to enable wifi local profile synchronization") + log.Errorf("failed to enable wifi local profile synchronization") + return utils.WiFiConfigurationFailed } } @@ -235,19 +239,22 @@ func (service *ProvisioningService) EnableWifi() error { xmlMsg = service.cimMessages.WiFiPort.RequestStateChange(32769) xmlRsp, err = service.client.Post(xmlMsg) if err != nil { - return err + log.Error(err) + return utils.WSMANMessageError } var stateChangeRsp wifi.RequestStateChangeResponse err = xml.Unmarshal(xmlRsp, &stateChangeRsp) if err != nil { - return err + log.Error(err) + return utils.UnmarshalMessageFailed } returnValue := stateChangeRsp.Body.RequestStateChange_OUTPUT.ReturnValue if returnValue != 0 { - return fmt.Errorf("AddWiFiSettings_OUTPUT.ReturnValue: %d", returnValue) + log.Errorf("AddWiFiSettings_OUTPUT.ReturnValue: %d", returnValue) + return utils.AmtPtStatusCodeBase + returnValue } - return nil + return utils.Success } type Handles struct { @@ -290,72 +297,81 @@ func (service *ProvisioningService) RollbackAddedItems(handles *Handles) { } } -func (service *ProvisioningService) AddTrustedRootCert(caCert string) (string, error) { +func (service *ProvisioningService) AddTrustedRootCert(caCert string) (string, int) { xmlMsg := service.amtMessages.PublicKeyManagementService.AddTrustedRootCertificate(caCert) xmlRsp, err := service.client.Post(xmlMsg) if err != nil { - return "", err + log.Error(err) + return "", utils.WSMANMessageError } var pkResponse publickey.Response err = xml.Unmarshal(xmlRsp, &pkResponse) if err != nil { - return "", err + log.Error(err) + return "", utils.UnmarshalMessageFailed } - err = checkReturnValue(pkResponse.Body.AddTrustedRootCertificate_OUTPUT.ReturnValue, "root certificate") - if err != nil { - return "", err + resultCode := checkReturnValue(pkResponse.Body.AddTrustedRootCertificate_OUTPUT.ReturnValue, "root certificate") + if resultCode != utils.Success { + return "", resultCode } handle := pkResponse.Body.AddTrustedRootCertificate_OUTPUT.CreatedCertificate.ReferenceParameters.SelectorSet.Selector[0].Value - return handle, nil + return handle, utils.Success } -func (service *ProvisioningService) AddClientCert(clientCert string) (string, error) { +func (service *ProvisioningService) AddClientCert(clientCert string) (string, int) { xmlMsg := service.amtMessages.PublicKeyManagementService.AddCertificate(clientCert) xmlRsp, err := service.client.Post(xmlMsg) if err != nil { - return "", err + log.Error(err) + return "", utils.WSMANMessageError } var pkResponse publickey.Response err = xml.Unmarshal(xmlRsp, &pkResponse) if err != nil { - return "", err + log.Error(err) + return "", utils.UnmarshalMessageFailed } - err = checkReturnValue(pkResponse.Body.AddTrustedCertificate_OUTPUT.ReturnValue, "client certificate") - if err != nil { - return "", err + resultCode := checkReturnValue(pkResponse.Body.AddTrustedCertificate_OUTPUT.ReturnValue, "client certificate") + if resultCode != utils.Success { + return "", resultCode } handle := pkResponse.Body.AddTrustedCertificate_OUTPUT.CreatedCertificate.ReferenceParameters.SelectorSet.Selector[0].Value - return handle, nil + return handle, utils.Success } -func (service *ProvisioningService) AddPrivateKey(privateKey string) (string, error) { +func (service *ProvisioningService) AddPrivateKey(privateKey string) (string, int) { xmlMsg := service.amtMessages.PublicKeyManagementService.AddKey([]byte(privateKey)) xmlRsp, err := service.client.Post(xmlMsg) if err != nil { - return "", err + log.Error(err) + return "", utils.WSMANMessageError } var pkResponse publickey.Response err = xml.Unmarshal(xmlRsp, &pkResponse) if err != nil { - return "", err + log.Error(err) + return "", utils.UnmarshalMessageFailed } - err = checkReturnValue(pkResponse.Body.AddKey_OUTPUT.ReturnValue, "private key") - if err != nil { - return "", err + resultCode := checkReturnValue(pkResponse.Body.AddKey_OUTPUT.ReturnValue, "private key") + if resultCode != utils.Success { + return "", resultCode } handle := pkResponse.Body.AddKey_OUTPUT.CreatedKey.ReferenceParameters.SelectorSet.Selector[0].Value - return handle, nil + return handle, utils.Success } -func checkReturnValue(returnValue int, item string) error { - if returnValue != 0 { +func checkReturnValue(returnValue int, item string) int { + if returnValue != common.PT_STATUS_SUCCESS { if returnValue == common.PT_STATUS_DUPLICATE { - return fmt.Errorf("%s already exists and must be removed before continuing", item) + log.Errorf("%s already exists and must be removed before continuing", item) + return utils.AmtPtStatusCodeBase + returnValue } else if returnValue == common.PT_STATUS_INVALID_CERT { - return fmt.Errorf("%s is invalid", item) + log.Errorf("%s is invalid", item) + return utils.AmtPtStatusCodeBase + returnValue } else { - return fmt.Errorf("%s non-zero return code: %d", item, returnValue) + log.Errorf("%s non-zero return code: %d", item, returnValue) + return utils.AmtPtStatusCodeBase + returnValue } } - return nil + return utils.Success } diff --git a/internal/local/configure_test.go b/internal/local/configure_test.go index 6ed3480e..8652b1a7 100644 --- a/internal/local/configure_test.go +++ b/internal/local/configure_test.go @@ -1,9 +1,6 @@ package local import ( - "encoding/xml" - "fmt" - "net/http" "rpc/internal/config" "rpc/internal/flags" "rpc/pkg/utils" @@ -83,73 +80,30 @@ var ieee8021xCfgPEAPv0_EAPMSCHAPv2 = config.Ieee8021xConfig{ PrivateKey: "privateKey", } -// TODO: remove these when local-acm-activation branch is available in main -type ResponseFuncArray []func(w http.ResponseWriter, r *http.Request) - -func setupWsmanResponses(t *testing.T, f *flags.Flags, responses ResponseFuncArray) ProvisioningService { - handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, "POST", r.Method) - responses[0](w, r) - responses = responses[1:] - }) - return setupWithWsmanClient(f, handler) -} - -func respondServerErrFunc() func(w http.ResponseWriter, r *http.Request) { - return func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusInternalServerError) - } -} - -func respondBadXmlFunc(t *testing.T) func(w http.ResponseWriter, r *http.Request) { - return func(w http.ResponseWriter, r *http.Request) { - _, err := w.Write([]byte(`not really xml is it?`)) - assert.Nil(t, err) - } -} - -func respondMsgFunc(t *testing.T, msg any) func(w http.ResponseWriter, r *http.Request) { - return func(w http.ResponseWriter, r *http.Request) { - bytes, err := xml.Marshal(msg) - assert.Nil(t, err) - _, err = w.Write(bytes) - assert.Nil(t, err) - } -} - -func respondStringFunc(t *testing.T, msg string) func(w http.ResponseWriter, r *http.Request) { - return func(w http.ResponseWriter, r *http.Request) { - _, err := w.Write([]byte(msg)) - assert.Nil(t, err) - } -} - func TestConfigure(t *testing.T) { f := &flags.Flags{} - t.Run("returns InvalidParameters with no sub command and not wifi configs", func(t *testing.T) { + t.Run("expect InvalidParameters for unhandle Subcommand", func(t *testing.T) { lps := setupWsmanResponses(t, f, ResponseFuncArray{}) resultCode := lps.Configure() assert.Equal(t, utils.IncorrectCommandLineParameters, resultCode) }) - t.Run("returns WiFiConfigurationFailed handling WifiConfigs from LocalConfig", func(t *testing.T) { - f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfgWPA) + t.Run("expect MissingWifiConfiguration for SubCommandAddWifiSettings", func(t *testing.T) { + f.SubCommand = utils.SubCommandAddWifiSettings responsers := ResponseFuncArray{} - responsers = append(responsers, respondMsgFunc(t, wifi.EnumerationEnvelope{})) // PruneWifiConfigs - responsers = append(responsers, respondMsgFunc(t, wifi.PullEnvelope{})) // PruneWifiConfigs responsers = append(responsers, respondServerErrFunc()) lps := setupWsmanResponses(t, f, responsers) resultCode := lps.Configure() - assert.Equal(t, utils.WiFiConfigurationFailed, resultCode) + assert.Equal(t, utils.WSMANMessageError, resultCode) }) } -func TestConfigureWiFi(t *testing.T) { +func TestAddWifiSettings(t *testing.T) { f := &flags.Flags{} f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfgWPA) + pcsRsp := wifiportconfiguration.PortConfigurationResponse{} + pcsRsp.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled = 1 t.Run("expect Success on happy path", func(t *testing.T) { - pcsRsp := wifiportconfiguration.PortConfigurationResponse{} - pcsRsp.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled = 1 responsers := ResponseFuncArray{} responsers = append(responsers, respondMsgFunc(t, wifi.EnumerationEnvelope{})) // PruneWifiConfigs responsers = append(responsers, respondMsgFunc(t, wifi.PullEnvelope{})) // PruneWifiConfigs @@ -157,22 +111,46 @@ func TestConfigureWiFi(t *testing.T) { responsers = append(responsers, respondMsgFunc(t, wifi.RequestStateChangeResponse{})) responsers = append(responsers, respondMsgFunc(t, wifiportconfiguration.AddWiFiSettingsResponse{})) lps := setupWsmanResponses(t, f, responsers) - resultCode := lps.ConfigureWiFi() + resultCode := lps.AddWifiSettings() assert.Equal(t, utils.Success, resultCode) }) - t.Run("expect WifiConfigurationWithWarnings on error with configuration", func(t *testing.T) { - orig := f.LocalConfig.WifiConfigs[0].ProfileName - f.LocalConfig.WifiConfigs[0].ProfileName = "bad-name" + t.Run("expect error from PruneWifiConfigs path", func(t *testing.T) { + responsers := ResponseFuncArray{} + responsers = append(responsers, respondServerErrFunc()) + lps := setupWsmanResponses(t, f, responsers) + resultCode := lps.AddWifiSettings() + assert.NotEqual(t, utils.Success, resultCode) + }) + t.Run("expect error from EnableWifi path", func(t *testing.T) { responsers := ResponseFuncArray{} responsers = append(responsers, respondMsgFunc(t, wifi.EnumerationEnvelope{})) // PruneWifiConfigs responsers = append(responsers, respondMsgFunc(t, wifi.PullEnvelope{})) // PruneWifiConfigs - responsers = append(responsers, respondMsgFunc(t, wifiportconfiguration.PortConfigurationResponse{})) - responsers = append(responsers, respondMsgFunc(t, wifi.RequestStateChangeResponse{})) + responsers = append(responsers, respondServerErrFunc()) + lps := setupWsmanResponses(t, f, responsers) + resultCode := lps.AddWifiSettings() + assert.NotEqual(t, utils.Success, resultCode) + }) +} + +func TestProcessWifiConfigs(t *testing.T) { + f := &flags.Flags{} + f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfgWPA) + f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfgWPA2) + t.Run("expect WifiConfigurationWithWarnings if some configs fail", func(t *testing.T) { + f.LocalConfig.WifiConfigs[0].ProfileName = "bad-name" + responsers := ResponseFuncArray{} responsers = append(responsers, respondMsgFunc(t, wifiportconfiguration.AddWiFiSettingsResponse{})) lps := setupWsmanResponses(t, f, responsers) - resultCode := lps.ConfigureWiFi() + resultCode := lps.ProcessWifiConfigs() assert.Equal(t, utils.WifiConfigurationWithWarnings, resultCode) - f.LocalConfig.WifiConfigs[0].ProfileName = orig + }) + t.Run("expect WiFiConfigurationFailed if all configs fail", func(t *testing.T) { + f.LocalConfig.WifiConfigs[1].ProfileName = "bad-name" + responsers := ResponseFuncArray{} + responsers = append(responsers, respondMsgFunc(t, wifiportconfiguration.AddWiFiSettingsResponse{})) + lps := setupWsmanResponses(t, f, responsers) + resultCode := lps.ProcessWifiConfigs() + assert.Equal(t, utils.WiFiConfigurationFailed, resultCode) }) } @@ -180,7 +158,7 @@ func TestProcessWifiConfig(t *testing.T) { f := &flags.Flags{} // bad name error already tested - t.Run("expect error ProcessIeee8012xConfig", func(t *testing.T) { + t.Run("expect WSMANMessageError for ProcessIeee8012xConfig", func(t *testing.T) { orig := wifiCfgWPA8021xEAPTLS.AuthenticationMethod wifiCfgWPA8021xEAPTLS.AuthenticationMethod = int(models.AuthenticationMethod_WPA_IEEE8021x) f.LocalConfig.Ieee8021xConfigs = config.Ieee8021xConfigs{} @@ -188,45 +166,46 @@ func TestProcessWifiConfig(t *testing.T) { responsers := ResponseFuncArray{} responsers = append(responsers, respondServerErrFunc()) lps := setupWsmanResponses(t, f, responsers) - err := lps.ProcessWifiConfig(&wifiCfgWPA8021xEAPTLS) - assert.NotNil(t, err) + resultCode := lps.ProcessWifiConfig(&wifiCfgWPA8021xEAPTLS) + assert.Equal(t, utils.WSMANMessageError, resultCode) wifiCfgWPA8021xEAPTLS.AuthenticationMethod = orig }) - t.Run("expect server error for AddWiFiSettings()", func(t *testing.T) { + t.Run("expect WSMANMessageError for AddWiFiSettings()", func(t *testing.T) { responsers := ResponseFuncArray{} responsers = append(responsers, respondServerErrFunc()) lps := setupWsmanResponses(t, f, responsers) - err := lps.ProcessWifiConfig(&wifiCfgWPA2) - assert.NotNil(t, err) + resultCode := lps.ProcessWifiConfig(&wifiCfgWPA2) + assert.Equal(t, utils.WSMANMessageError, resultCode) }) - t.Run("expect xml parse error for AddWiFiSettings()", func(t *testing.T) { + t.Run("expect UnmarshalMessageFailed for AddWiFiSettings()", func(t *testing.T) { responsers := ResponseFuncArray{} responsers = append(responsers, respondBadXmlFunc(t)) lps := setupWsmanResponses(t, f, responsers) - err := lps.ProcessWifiConfig(&wifiCfgWPA2) - assert.NotNil(t, err) + resultCode := lps.ProcessWifiConfig(&wifiCfgWPA2) + assert.Equal(t, utils.UnmarshalMessageFailed, resultCode) }) t.Run("expect unsuccessful return value error for AddWiFiSettings()", func(t *testing.T) { msgRsp := wifiportconfiguration.AddWiFiSettingsResponse{} msgRsp.Body.AddWiFiSettings_OUTPUT.ReturnValue = 1 + expected := utils.AmtPtStatusCodeBase + msgRsp.Body.AddWiFiSettings_OUTPUT.ReturnValue responsers := ResponseFuncArray{} responsers = append(responsers, respondMsgFunc(t, msgRsp)) lps := setupWsmanResponses(t, f, responsers) - err := lps.ProcessWifiConfig(&wifiCfgWPA2) - assert.NotNil(t, err) + resultCode := lps.ProcessWifiConfig(&wifiCfgWPA2) + assert.Equal(t, expected, resultCode) }) } func TestPruneWifiConfigs(t *testing.T) { f := &flags.Flags{} - t.Run("expect success when there are no configs", func(t *testing.T) { + t.Run("expect Success when there are no configs", func(t *testing.T) { responsers := ResponseFuncArray{} responsers = append(responsers, respondMsgFunc(t, wifi.EnumerationEnvelope{})) responsers = append(responsers, respondMsgFunc(t, wifi.PullEnvelope{})) lps := setupWsmanResponses(t, f, responsers) errCode := lps.PruneWifiConfigs() - assert.Equal(t, 0, errCode) + assert.Equal(t, utils.Success, errCode) }) t.Run("expect success when there are configs", func(t *testing.T) { pullEnvelope := wifi.PullEnvelope{} @@ -240,7 +219,7 @@ func TestPruneWifiConfigs(t *testing.T) { responsers = append(responsers, respondMsgFunc(t, "Config2 Deleted")) lps := setupWsmanResponses(t, f, responsers) errCode := lps.PruneWifiConfigs() - assert.Equal(t, 0, errCode) + assert.Equal(t, utils.Success, errCode) }) t.Run("expect error when enumeration not returned", func(t *testing.T) { responsers := ResponseFuncArray{} @@ -268,8 +247,8 @@ func TestProcessIeee8012xConfig(t *testing.T) { f.LocalConfig.Ieee8021xConfigs = config.Ieee8021xConfigs{} f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, ieee8021xCfgEAPTLS) lps := setupWsmanResponses(t, f, ResponseFuncArray{}) - err := lps.ProcessIeee8012xConfig("someothername", ieee8021xSettings, &handles) - assert.NotNil(t, err) + resultCode := lps.ProcessIeee8012xConfig("someothername", ieee8021xSettings, &handles) + assert.Equal(t, utils.MissingIeee8021xConfiguration, resultCode) assert.Empty(t, ieee8021xSettings.ElementName) assert.Empty(t, handles.privateKeyHandle) assert.Empty(t, handles.clientCertHandle) @@ -283,8 +262,8 @@ func TestProcessIeee8012xConfig(t *testing.T) { responsers := ResponseFuncArray{} responsers = append(responsers, respondServerErrFunc()) lps := setupWsmanResponses(t, f, responsers) - err := lps.ProcessIeee8012xConfig(ieee8021xCfgPEAPv0_EAPMSCHAPv2.ProfileName, ieee8021xSettings, &handles) - assert.NotNil(t, err) + resultCode := lps.ProcessIeee8012xConfig(ieee8021xCfgPEAPv0_EAPMSCHAPv2.ProfileName, ieee8021xSettings, &handles) + assert.Equal(t, utils.WSMANMessageError, resultCode) assert.Equal(t, ieee8021xCfgPEAPv0_EAPMSCHAPv2.ProfileName, ieee8021xSettings.ElementName) assert.Empty(t, handles.privateKeyHandle) assert.Empty(t, handles.clientCertHandle) @@ -299,8 +278,8 @@ func TestProcessIeee8012xConfig(t *testing.T) { responsers = append(responsers, respondStringFunc(t, addKeyXMLResponse)) responsers = append(responsers, respondServerErrFunc()) lps := setupWsmanResponses(t, f, responsers) - err := lps.ProcessIeee8012xConfig(ieee8021xCfgEAPTLS.ProfileName, ieee8021xSettings, &handles) - assert.NotNil(t, err) + resultCode := lps.ProcessIeee8012xConfig(ieee8021xCfgEAPTLS.ProfileName, ieee8021xSettings, &handles) + assert.Equal(t, utils.WSMANMessageError, resultCode) assert.Equal(t, ieee8021xCfgEAPTLS.ProfileName, ieee8021xSettings.ElementName) assert.NotEmpty(t, handles.privateKeyHandle) assert.Empty(t, handles.clientCertHandle) @@ -316,8 +295,8 @@ func TestProcessIeee8012xConfig(t *testing.T) { responsers = append(responsers, respondStringFunc(t, clientCertXMLResponse)) responsers = append(responsers, respondServerErrFunc()) lps := setupWsmanResponses(t, f, responsers) - err := lps.ProcessIeee8012xConfig(ieee8021xCfgEAPTLS.ProfileName, ieee8021xSettings, &handles) - assert.NotNil(t, err) + resultCode := lps.ProcessIeee8012xConfig(ieee8021xCfgEAPTLS.ProfileName, ieee8021xSettings, &handles) + assert.Equal(t, utils.WSMANMessageError, resultCode) assert.Equal(t, ieee8021xCfgEAPTLS.ProfileName, ieee8021xSettings.ElementName) assert.NotEmpty(t, handles.privateKeyHandle) assert.NotEmpty(t, handles.clientCertHandle) @@ -333,8 +312,8 @@ func TestProcessIeee8012xConfig(t *testing.T) { responsers = append(responsers, respondStringFunc(t, clientCertXMLResponse)) responsers = append(responsers, respondStringFunc(t, trustedRootXMLResponse)) lps := setupWsmanResponses(t, f, responsers) - err := lps.ProcessIeee8012xConfig(ieee8021xCfgEAPTLS.ProfileName, ieee8021xSettings, &handles) - assert.Nil(t, err) + resultCode := lps.ProcessIeee8012xConfig(ieee8021xCfgEAPTLS.ProfileName, ieee8021xSettings, &handles) + assert.Equal(t, utils.Success, resultCode) assert.Equal(t, ieee8021xCfgEAPTLS.ProfileName, ieee8021xSettings.ElementName) assert.NotEmpty(t, handles.privateKeyHandle) assert.NotEmpty(t, handles.clientCertHandle) @@ -344,49 +323,49 @@ func TestProcessIeee8012xConfig(t *testing.T) { func TestEnableWifiErrors(t *testing.T) { f := &flags.Flags{} - t.Run("expect server error for WiFiPortConfigurationService.Get()", func(t *testing.T) { + t.Run("expect WSMANMessageError for WiFiPortConfigurationService.Get()", func(t *testing.T) { responsers := ResponseFuncArray{} responsers = append(responsers, respondServerErrFunc()) lps := setupWsmanResponses(t, f, responsers) - err := lps.EnableWifi() - assert.NotNil(t, err) + resultCode := lps.EnableWifi() + assert.Equal(t, utils.WSMANMessageError, resultCode) }) - t.Run("expect unmarshall error for WiFiPortConfigurationService.Get()", func(t *testing.T) { + t.Run("expect UnmarshalMessageFailed for WiFiPortConfigurationService.Get()", func(t *testing.T) { responsers := ResponseFuncArray{} responsers = append(responsers, respondBadXmlFunc(t)) lps := setupWsmanResponses(t, f, responsers) - err := lps.EnableWifi() - assert.NotNil(t, err) + resultCode := lps.EnableWifi() + assert.Equal(t, utils.UnmarshalMessageFailed, resultCode) }) - t.Run("expect server error for WiFiPortConfigurationService.Put()", func(t *testing.T) { + t.Run("expect WSMANMessageError for WiFiPortConfigurationService.Put()", func(t *testing.T) { pcsResponse := wifiportconfiguration.PortConfigurationResponse{} responsers := ResponseFuncArray{} responsers = append(responsers, respondMsgFunc(t, pcsResponse)) responsers = append(responsers, respondServerErrFunc()) lps := setupWsmanResponses(t, f, responsers) - err := lps.EnableWifi() - assert.NotNil(t, err) + resultCode := lps.EnableWifi() + assert.Equal(t, utils.WSMANMessageError, resultCode) }) - t.Run("expect unmarshall error for WiFiPortConfigurationService.Put()", func(t *testing.T) { + t.Run("expect UnmarshalMessageFailed for WiFiPortConfigurationService.Put()", func(t *testing.T) { pcsResponse := wifiportconfiguration.PortConfigurationResponse{} responsers := ResponseFuncArray{} responsers = append(responsers, respondMsgFunc(t, pcsResponse)) responsers = append(responsers, respondBadXmlFunc(t)) lps := setupWsmanResponses(t, f, responsers) - err := lps.EnableWifi() - assert.NotNil(t, err) + resultCode := lps.EnableWifi() + assert.Equal(t, utils.UnmarshalMessageFailed, resultCode) }) - t.Run("expect non-zero error for WiFiPortConfigurationService.Put()", func(t *testing.T) { + t.Run("expect WiFiConfigurationFailed when enable is unsuccessful", func(t *testing.T) { pcsResponse := wifiportconfiguration.PortConfigurationResponse{} pcsResponseFailed := wifiportconfiguration.PortConfigurationResponse{} responsers := ResponseFuncArray{} responsers = append(responsers, respondMsgFunc(t, pcsResponse)) responsers = append(responsers, respondMsgFunc(t, pcsResponseFailed)) lps := setupWsmanResponses(t, f, responsers) - err := lps.EnableWifi() - assert.NotNil(t, err) + resultCode := lps.EnableWifi() + assert.Equal(t, utils.WiFiConfigurationFailed, resultCode) }) - t.Run("expect server error for RequestStateChange()", func(t *testing.T) { + t.Run("expect WSMANMessageError for RequestStateChange()", func(t *testing.T) { pcsResponse := wifiportconfiguration.PortConfigurationResponse{} pcsResponseEnabled := wifiportconfiguration.PortConfigurationResponse{} pcsResponseEnabled.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled = 1 @@ -395,10 +374,10 @@ func TestEnableWifiErrors(t *testing.T) { responsers = append(responsers, respondMsgFunc(t, pcsResponseEnabled)) responsers = append(responsers, respondServerErrFunc()) lps := setupWsmanResponses(t, f, responsers) - err := lps.EnableWifi() - assert.NotNil(t, err) + resultCode := lps.EnableWifi() + assert.Equal(t, utils.WSMANMessageError, resultCode) }) - t.Run("expect xml unmarshall error for RequestStateChange()", func(t *testing.T) { + t.Run("expect UnmarshalMessageFailed for RequestStateChange()", func(t *testing.T) { pcsResponse := wifiportconfiguration.PortConfigurationResponse{} pcsResponseEnabled := wifiportconfiguration.PortConfigurationResponse{} pcsResponseEnabled.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled = 1 @@ -407,8 +386,8 @@ func TestEnableWifiErrors(t *testing.T) { responsers = append(responsers, respondMsgFunc(t, pcsResponseEnabled)) responsers = append(responsers, respondBadXmlFunc(t)) lps := setupWsmanResponses(t, f, responsers) - err := lps.EnableWifi() - assert.NotNil(t, err) + resultCode := lps.EnableWifi() + assert.Equal(t, utils.UnmarshalMessageFailed, resultCode) }) t.Run("expect non-zero error for RequestStateChange()", func(t *testing.T) { pcsResponse := wifiportconfiguration.PortConfigurationResponse{} @@ -416,13 +395,14 @@ func TestEnableWifiErrors(t *testing.T) { pcsResponseEnabled.Body.WiFiPortConfigurationService.LocalProfileSynchronizationEnabled = 1 stateChangeResponse := wifi.RequestStateChangeResponse{} stateChangeResponse.Body.RequestStateChange_OUTPUT.ReturnValue = 1 + expected := utils.AmtPtStatusCodeBase + stateChangeResponse.Body.RequestStateChange_OUTPUT.ReturnValue responsers := ResponseFuncArray{} responsers = append(responsers, respondMsgFunc(t, pcsResponse)) responsers = append(responsers, respondMsgFunc(t, pcsResponseEnabled)) responsers = append(responsers, respondMsgFunc(t, stateChangeResponse)) lps := setupWsmanResponses(t, f, responsers) - err := lps.EnableWifi() - assert.NotNil(t, err) + resultCode := lps.EnableWifi() + assert.Equal(t, expected, resultCode) }) } @@ -454,111 +434,111 @@ func TestRollbackAddedItems(t *testing.T) { func TestAddTrustedRootCert(t *testing.T) { f := &flags.Flags{} - t.Run("expect server error", func(t *testing.T) { + t.Run("expect WSMANMessageError", func(t *testing.T) { responsers := ResponseFuncArray{} responsers = append(responsers, respondServerErrFunc()) lps := setupWsmanResponses(t, f, responsers) - handle, err := lps.AddTrustedRootCert("AABBCCDD") - assert.NotNil(t, err) + handle, resultCode := lps.AddTrustedRootCert("AABBCCDD") + assert.Equal(t, utils.WSMANMessageError, resultCode) assert.Empty(t, handle) }) - t.Run("expect xml parse error", func(t *testing.T) { + t.Run("expect UnmarshalMessageFailed", func(t *testing.T) { responsers := ResponseFuncArray{} responsers = append(responsers, respondBadXmlFunc(t)) lps := setupWsmanResponses(t, f, responsers) - handle, err := lps.AddTrustedRootCert("AABBCCDD") - assert.NotNil(t, err) + handle, resultCode := lps.AddTrustedRootCert("AABBCCDD") + assert.Equal(t, utils.UnmarshalMessageFailed, resultCode) assert.Empty(t, handle) }) t.Run("expect non-zero error ", func(t *testing.T) { dup := strings.Replace(trustedRootXMLResponse, `0`, `1`, 1) + expected := utils.AmtPtStatusCodeBase + 1 responsers := ResponseFuncArray{} responsers = append(responsers, respondStringFunc(t, dup)) lps := setupWsmanResponses(t, f, responsers) - handle, err := lps.AddTrustedRootCert("AABBCCDD") - assert.NotNil(t, err) + handle, resultCode := lps.AddTrustedRootCert("AABBCCDD") + assert.Equal(t, expected, resultCode) assert.Empty(t, handle) }) } func TestAddClientCert(t *testing.T) { f := &flags.Flags{} - t.Run("expect server error", func(t *testing.T) { + t.Run("expect WSMANMessageError", func(t *testing.T) { responsers := ResponseFuncArray{} responsers = append(responsers, respondServerErrFunc()) lps := setupWsmanResponses(t, f, responsers) - handle, err := lps.AddClientCert("AABBCCDD") - assert.NotNil(t, err) + handle, resultCode := lps.AddClientCert("AABBCCDD") + assert.Equal(t, utils.WSMANMessageError, resultCode) assert.Empty(t, handle) }) - t.Run("expect xml parse error", func(t *testing.T) { + t.Run("expect UnmarshalMessageFailed", func(t *testing.T) { responsers := ResponseFuncArray{} responsers = append(responsers, respondBadXmlFunc(t)) lps := setupWsmanResponses(t, f, responsers) - handle, err := lps.AddClientCert("AABBCCDD") - assert.NotNil(t, err) + handle, resultCode := lps.AddClientCert("AABBCCDD") + assert.Equal(t, utils.UnmarshalMessageFailed, resultCode) assert.Empty(t, handle) }) t.Run("expect non-zero error ", func(t *testing.T) { dup := strings.Replace(clientCertXMLResponse, `0`, `1`, 1) + expected := utils.AmtPtStatusCodeBase + 1 responsers := ResponseFuncArray{} responsers = append(responsers, respondStringFunc(t, dup)) lps := setupWsmanResponses(t, f, responsers) - handle, err := lps.AddClientCert("AABBCCDD") - assert.NotNil(t, err) + handle, resultCode := lps.AddClientCert("AABBCCDD") + assert.Equal(t, expected, resultCode) assert.Empty(t, handle) }) } func TestAddPrivateKey(t *testing.T) { f := &flags.Flags{} - t.Run("expect server error", func(t *testing.T) { + t.Run("expect WSMANMessageError", func(t *testing.T) { responsers := ResponseFuncArray{} responsers = append(responsers, respondServerErrFunc()) lps := setupWsmanResponses(t, f, responsers) - handle, err := lps.AddPrivateKey("AABBCCDD") - assert.NotNil(t, err) + handle, resultCode := lps.AddPrivateKey("AABBCCDD") + assert.Equal(t, utils.WSMANMessageError, resultCode) assert.Empty(t, handle) }) - t.Run("expect xml parse error", func(t *testing.T) { + t.Run("expect UnmarshalMessageFailed", func(t *testing.T) { responsers := ResponseFuncArray{} responsers = append(responsers, respondBadXmlFunc(t)) lps := setupWsmanResponses(t, f, responsers) - handle, err := lps.AddPrivateKey("AABBCCDD") - assert.NotNil(t, err) + handle, resultCode := lps.AddPrivateKey("AABBCCDD") + assert.Equal(t, utils.UnmarshalMessageFailed, resultCode) assert.Empty(t, handle) }) t.Run("expect non-zero error ", func(t *testing.T) { dup := strings.Replace(addKeyXMLResponse, `0`, `1`, 1) + expected := utils.AmtPtStatusCodeBase + 1 responsers := ResponseFuncArray{} responsers = append(responsers, respondStringFunc(t, dup)) lps := setupWsmanResponses(t, f, responsers) - handle, err := lps.AddPrivateKey("AABBCCDD") - assert.NotNil(t, err) + handle, resultCode := lps.AddPrivateKey("AABBCCDD") + assert.Equal(t, expected, resultCode) assert.Empty(t, handle) }) } func TestCheckReturnValue(t *testing.T) { tests := []struct { - name string - in int - item string - wantErr error + name string + in int + item string + want int }{ - {"TestNoError", 0, "item", nil}, - {"TestAlreadyExists", common.PT_STATUS_DUPLICATE, "item", fmt.Errorf("%s already exists and must be removed before continuing", "item")}, - {"TestInvalidItem", common.PT_STATUS_INVALID_CERT, "item", fmt.Errorf("%s is invalid", "item")}, - {"TestNonZeroReturnCode", 9999, "item", fmt.Errorf("%s non-zero return code: %d", "item", 9999)}, + {"TestNoError", 0, "item", utils.Success}, + {"TestAlreadyExists", common.PT_STATUS_DUPLICATE, "item", utils.AmtPtStatusCodeBase + common.PT_STATUS_DUPLICATE}, + {"TestInvalidItem", common.PT_STATUS_INVALID_CERT, "item", utils.AmtPtStatusCodeBase + common.PT_STATUS_INVALID_CERT}, + {"TestNonZeroReturnCode", 2082, "item", utils.AmtPtStatusCodeBase + 2082}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - gotErr := checkReturnValue(tt.in, tt.item) - - if (gotErr != nil && tt.wantErr == nil) || (gotErr == nil && tt.wantErr != nil) || (gotErr != nil && tt.wantErr != nil && gotErr.Error() != tt.wantErr.Error()) { - t.Errorf("gotErr %v, wantErr %v", gotErr, tt.wantErr) - } + got := checkReturnValue(tt.in, tt.item) + assert.Equal(t, tt.want, got) }) } } diff --git a/internal/local/lps.go b/internal/local/lps.go index 02867be1..bf395186 100644 --- a/internal/local/lps.go +++ b/internal/local/lps.go @@ -53,9 +53,6 @@ func ExecuteCommand(flags *flags.Flags) int { case utils.CommandConfigure: resultCode = service.Configure() break - case utils.CommandMaintenance: - resultCode = service.Configure() - break case utils.CommandVersion: resultCode = service.DisplayVersion() break diff --git a/internal/local/lps_test.go b/internal/local/lps_test.go index 27e319e4..505d5090 100644 --- a/internal/local/lps_test.go +++ b/internal/local/lps_test.go @@ -83,6 +83,51 @@ var mockUnprovisionErr error = nil func (c MockAMT) Unprovision() (int, error) { return mockUnprovisionCode, mockUnprovisionErr } +// TODO: remove these when local-acm-activation branch is available in main +type ResponseFuncArray []func(w http.ResponseWriter, r *http.Request) + +func setupWsmanResponses(t *testing.T, f *flags.Flags, responses ResponseFuncArray) ProvisioningService { + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, "POST", r.Method) + if len(responses) > 0 { + responses[0](w, r) + responses = responses[1:] + } else { + w.WriteHeader(http.StatusServiceUnavailable) + } + }) + return setupWithWsmanClient(f, handler) +} + +func respondServerErrFunc() func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + } +} + +func respondBadXmlFunc(t *testing.T) func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + _, resultCode := w.Write([]byte(`not really xml is it?`)) + assert.Nil(t, resultCode) + } +} + +func respondMsgFunc(t *testing.T, msg any) func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + bytes, err := xml.Marshal(msg) + assert.Nil(t, err) + _, err = w.Write(bytes) + assert.Nil(t, err) + } +} + +func respondStringFunc(t *testing.T, msg string) func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + _, err := w.Write([]byte(msg)) + assert.Nil(t, err) + } +} + func setupService(f *flags.Flags) ProvisioningService { service := NewProvisioningService(f) service.amtCommand = MockAMT{} @@ -117,10 +162,10 @@ func TestExecute(t *testing.T) { assert.Equal(t, utils.Success, resultCode) }) - t.Run("execute CommandMaintenance with no SubCommand fails", func(t *testing.T) { - f.Command = utils.CommandMaintenance + t.Run("execute CommandConfigure with no SubCommand fails", func(t *testing.T) { + f.Command = utils.CommandConfigure resultCode := ExecuteCommand(f) - assert.Equal(t, utils.InvalidParameterCombination, resultCode) + assert.Equal(t, utils.IncorrectCommandLineParameters, resultCode) }) } diff --git a/pkg/utils/constants.go b/pkg/utils/constants.go index f3b2138a..3970c2a9 100644 --- a/pkg/utils/constants.go +++ b/pkg/utils/constants.go @@ -67,21 +67,24 @@ const ( OSNetworkInterfacesLookupFailed = 72 // (100-149) Activation, and configuration errors - AMTAuthenticationFailed = 100 - WSMANMessageError = 101 - ActivationFailed = 102 - NetworkConfigurationFailed = 103 - CIRAConfigurationFailed = 104 - TLSConfigurationFailed = 105 - WiFiConfigurationFailed = 106 - AMTFeaturesConfigurationFailed = 107 - Ieee8021xConfigurationFailed = 108 - UnableToDeactivate = 109 - DeactivationFailed = 110 - UnableToActivate = 111 - WifiConfigurationWithWarnings = 112 - UnmarshalMessageFailed = 113 // Unmarshal wsman response failed - DeleteWifiConfigFailed = 114 // Delete wifi configuration failed + AMTAuthenticationFailed = 100 + WSMANMessageError = 101 + ActivationFailed = 102 + NetworkConfigurationFailed = 103 + CIRAConfigurationFailed = 104 + TLSConfigurationFailed = 105 + WiFiConfigurationFailed = 106 + AMTFeaturesConfigurationFailed = 107 + Ieee8021xConfigurationFailed = 108 + UnableToDeactivate = 109 + DeactivationFailed = 110 + UnableToActivate = 111 + WifiConfigurationWithWarnings = 112 + UnmarshalMessageFailed = 113 + DeleteWifiConfigFailed = 114 + MissingWifiConfiguration = 115 + MissingOrIncorrectWifiProfileName = 116 + MissingIeee8021xConfiguration = 117 // (150-199) Maintenance Errors SyncClockFailed = 150 @@ -92,4 +95,7 @@ const ( // (200-299) KPMU // (300-399) Redfish + + // (1000 - 3000) Amt PT Status Code Block + AmtPtStatusCodeBase = 1000 ) From 935c5a167a3a70041530a2aa5528bce269a7f331 Mon Sep 17 00:00:00 2001 From: Tim Shockley Date: Thu, 17 Aug 2023 14:12:00 -0700 Subject: [PATCH 24/29] fix: configFile param, secrets merged and prompted --- config-wifi.yaml | 23 +++-- internal/config/local.go | 37 +++----- internal/flags/activate.go | 2 +- internal/flags/configure.go | 144 +++++++++++++++++++++++-------- internal/flags/configure_test.go | 15 +++- internal/flags/flags.go | 113 ++++++++++++------------ internal/flags/maintenance.go | 46 ---------- pkg/utils/constants.go | 2 + secrets-wifi.yaml | 6 ++ 9 files changed, 215 insertions(+), 173 deletions(-) create mode 100644 secrets-wifi.yaml diff --git a/config-wifi.yaml b/config-wifi.yaml index 9fd6b517..75c795d8 100644 --- a/config-wifi.yaml +++ b/config-wifi.yaml @@ -1,23 +1,30 @@ wifiConfigs: - - profileName: 'wifi-8021x' # friendly name (ex. Profile name) + - profileName: 'wifiWPA2' ssid: 'ssid' priority: 1 authenticationMethod: 6 encryptionMethod: 4 - pskPassphrase: 'Passw0rd!@#' + pskPassphrase: '' ieee8021xProfileName: '' - - profileName: 'wifi-8021x' # friendly name (ex. Profile name) + - profileName: 'wifi8021x' # friendly name (ex. Profile name) ssid: 'ssid' priority: 2 - authenticationMethod: 7 # WPA IEEE 802.1x + authenticationMethod: 7 encryptionMethod: 4 pskPassphrase: '' - ieee8021xProfileName: 'profile-01' + ieee8021xProfileName: 'ieee8021xEAP-TLS' ieee8021xConfigs: - - profileName: 'profile-01' - username: "test" # 8021x username + - profileName: 'ieee8021xEAP-TLS' + username: "test" password: "" # 8021x password if authenticationProtocol is PEAPv0/EAP-MSCHAPv2(2) authenticationProtocol: 0 #8021x profile (ex. EAP-TLS(0)) clientCert: 'test' caCert: 'test' - privateKey: 'test' + privateKey: '' + - profileName: 'ieee8021xPEAPv0' + username: "test" + password: "" # 8021x password if authenticationProtocol is PEAPv0/EAP-MSCHAPv2(2) + authenticationProtocol: 2 #8021x profile (ex. EAP-TLS(0)) + clientCert: 'testClientCert' + caCert: 'testCaCert' + privateKey: 'testPrivateKey' diff --git a/internal/config/local.go b/internal/config/local.go index b1b90216..4f04bc9f 100644 --- a/internal/config/local.go +++ b/internal/config/local.go @@ -2,24 +2,11 @@ package config type ( Config struct { - Password string - IEEE8021XSettings `yaml:"ieee801xConfig"` - WifiConfigs `yaml:"wifiConfigs"` - Ieee8021xConfigs `yaml:"ieee8021xConfigs"` - SecretConfigs `yaml:"secretConfig"` - ACMSettings `yaml:"acmactivate"` - } - IEEE8021XSettings struct { - Name string `yaml:"name"` - AuthenticationMethod int `yaml:"authenticationMethod"` - EncryptionMethod int `yaml:"encryptionMethod"` - SSID string `yaml:"ssid"` - Username string `yaml:"username"` - AuthenticationProtocol int `yaml:"authenticationProtocol"` - Priority int `yaml:"priority"` - ClientCert string `yaml:"clientCert"` - CACert string `yaml:"caCert"` - PrivateKey string `yaml:"privateKey"` + Password string + FilePath string + WifiConfigs `yaml:"wifiConfigs"` + Ieee8021xConfigs `yaml:"ieee8021xConfigs"` + ACMSettings `yaml:"acmactivate"` } WifiConfigs []WifiConfig WifiConfig struct { @@ -31,11 +18,15 @@ type ( PskPassphrase string `yaml:"pskPassphrase"` Ieee8021xProfileName string `yaml:"ieee8021xProfileName"` } - SecretConfigs []SecretConfig - SecretConfig struct { - ClientCert string `yaml:"secretClientCert"` - CACert string `yaml:"secretCaCert"` - PrivateKey string `yaml:"secretPrivateKey"` + SecretConfig struct { + FilePath string + Secrets []Secret `yaml:"secrets"` + } + Secret struct { + ProfileName string `yaml:"profileName"` + PskPassphrase string `yaml:"pskPassphrase"` + PrivateKey string `yaml:"privateKey"` + Password string `yaml:"password"` } Ieee8021xConfigs []Ieee8021xConfig Ieee8021xConfig struct { diff --git a/internal/flags/activate.go b/internal/flags/activate.go index 84f200d3..1e81eb95 100644 --- a/internal/flags/activate.go +++ b/internal/flags/activate.go @@ -21,7 +21,7 @@ func (f *Flags) handleActivateCommand() int { return nil }) // for local activation in ACM mode need a few more items - f.amtActivateCommand.StringVar(&f.configContent, "config", "", "specify a config file ") + f.amtActivateCommand.StringVar(&f.LocalConfig.FilePath, "configFile", "", "specify a config file ") f.amtActivateCommand.StringVar(&f.LocalConfig.ACMSettings.AMTPassword, "amtPassword", "", "amt password") f.amtActivateCommand.StringVar(&f.LocalConfig.ACMSettings.ProvisioningCert, "provisioningCert", "", "provisioning certificate") f.amtActivateCommand.StringVar(&f.LocalConfig.ACMSettings.ProvisioningCertPwd, "provisioningCertPwd", "", "provisioning certificate password") diff --git a/internal/flags/configure.go b/internal/flags/configure.go index 4a1f6425..9cb1480c 100644 --- a/internal/flags/configure.go +++ b/internal/flags/configure.go @@ -2,6 +2,7 @@ package flags import ( "fmt" + "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim/models" "os" "path/filepath" "rpc/internal/config" @@ -29,20 +30,20 @@ func (f *Flags) handleConfigureCommand() int { return utils.IncorrectCommandLineParameters } - var errCode = utils.Success + var resultCode = utils.Success f.SubCommand = f.commandLineArgs[2] switch f.SubCommand { case "addwifisettings": - errCode = f.handleAddWifiSettings() + resultCode = f.handleAddWifiSettings() break default: f.printConfigurationUsage() - errCode = utils.IncorrectCommandLineParameters + resultCode = utils.IncorrectCommandLineParameters break } - if errCode != utils.Success { - return errCode + if resultCode != utils.Success { + return resultCode } f.Local = true @@ -56,17 +57,18 @@ func (f *Flags) handleConfigureCommand() int { } func (f *Flags) handleAddWifiSettings() int { - + var err error + var resultCode int + var wifiSecretConfig config.SecretConfig f.flagSetAddWifiSettings.BoolVar(&f.Verbose, "v", false, "Verbose output") f.flagSetAddWifiSettings.StringVar(&f.LogLevel, "l", "info", "Log level (panic,fatal,error,warn,info,debug,trace)") f.flagSetAddWifiSettings.BoolVar(&f.JsonOutput, "json", false, "JSON output") f.flagSetAddWifiSettings.StringVar(&f.Password, "password", f.lookupEnvOrString("AMT_PASSWORD", ""), "AMT password") - f.flagSetAddWifiSettings.StringVar(&f.configContent, "config", "", "specify a config file ") - f.flagSetAddWifiSettings.StringVar(&f.secretContent, "secret", "", "specify a config file ") - // TODO: these are the params for entering a single wifi config from command line + f.flagSetAddWifiSettings.StringVar(&f.LocalConfig.FilePath, "configFile", "", "specify a config file ") + f.flagSetAddWifiSettings.StringVar(&wifiSecretConfig.FilePath, "secretFile", "", "specify a secret file ") + // Params for entering a single wifi config from command line wifiCfg := config.WifiConfig{} ieee8021xCfg := config.Ieee8021xConfig{} - secretCfg := config.SecretConfig{} f.flagSetAddWifiSettings.StringVar(&wifiCfg.ProfileName, "profileName", "", "specify wifi profile name name") f.flagSetAddWifiSettings.IntVar(&wifiCfg.AuthenticationMethod, "authenticationMethod", 0, "specify authentication method") f.flagSetAddWifiSettings.IntVar(&wifiCfg.EncryptionMethod, "encryptionMethod", 0, "specify encryption method") @@ -79,54 +81,120 @@ func (f *Flags) handleAddWifiSettings() int { f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.ClientCert, "clientCert", "", "specify client certificate") f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.CACert, "caCert", "", "specify CA certificate") f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.PrivateKey, "privateKey", "", "specify private key") - f.flagSetAddWifiSettings.StringVar(&secretCfg.ClientCert, "secretClientCert", "", "specify client certificate") - f.flagSetAddWifiSettings.StringVar(&secretCfg.CACert, "secretCaCert", "", "specify CA certificate") - f.flagSetAddWifiSettings.StringVar(&secretCfg.PrivateKey, "secretPrivateKey", "", "specify private key") // rpc configure addwifisettings -configstring "{ prop: val, prop2: val }" // rpc configure add -config "filename" -secrets "someotherfile" - if err := f.flagSetAddWifiSettings.Parse(f.commandLineArgs[3:]); err != nil { + if err = f.flagSetAddWifiSettings.Parse(f.commandLineArgs[3:]); err != nil { f.printConfigurationUsage() - if f.Password == "" { - log.Error("commandline error: missing password") - return utils.MissingOrIncorrectPassword - } else { - return utils.IncorrectCommandLineParameters - } + return utils.IncorrectCommandLineParameters + } + + // port the profile name as it is understood a 8021x config will 'match' this wificfg + if wifiCfg.ProfileName != "" { + wifiCfg.Ieee8021xProfileName = wifiCfg.ProfileName + // don't worry if wifiCfg is not using 8021x, it will be ignored or verified later + ieee8021xCfg.ProfileName = wifiCfg.ProfileName } f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfg) - //Check if ieee8021x is empty, if so do not append. - if !ieee8021xCfgIsEmpty(ieee8021xCfg) { - f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, ieee8021xCfg) + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, ieee8021xCfg) + resultCode = f.handleLocalConfig() + if resultCode != utils.Success { + return resultCode } - if f.configContent != "" { - err := cleanenv.ReadConfig(f.configContent, &f.LocalConfig) + if wifiSecretConfig.FilePath != "" { + err = cleanenv.ReadConfig(wifiSecretConfig.FilePath, &wifiSecretConfig) if err != nil { - log.Error("config error: ", err) - return utils.IncorrectCommandLineParameters + log.Error("error reading secrets file: ", err) + return utils.FailedReadingConfiguration } } - if f.secretContent != "" { - err := cleanenv.ReadConfig(f.secretContent, &f.LocalConfig) - if err != nil { - log.Error("secrets error: ", err) - return utils.IncorrectCommandLineParameters + // merge secrets with configs + resultCode = f.mergeWifiSecrets(wifiSecretConfig) + if resultCode != utils.Success { + return resultCode + } + // prompt for missing secrets + resultCode = f.promptForSecrets() + if resultCode != utils.Success { + return resultCode + } + // verify configs + resultCode = f.verifyWifiConfigurations() + if resultCode != utils.Success { + return resultCode + } + return utils.Success +} + +func (f *Flags) mergeWifiSecrets(wifiSecretConfig config.SecretConfig) int { + for _, secret := range wifiSecretConfig.Secrets { + if secret.ProfileName == "" { + continue + } + if secret.PskPassphrase != "" { + for i, _ := range f.LocalConfig.WifiConfigs { + item := &f.LocalConfig.WifiConfigs[i] + if item.ProfileName == secret.ProfileName { + item.PskPassphrase = secret.PskPassphrase + } + } + } + if secret.Password != "" { + for i, _ := range f.LocalConfig.Ieee8021xConfigs { + item := &f.LocalConfig.Ieee8021xConfigs[i] + if item.ProfileName == secret.ProfileName { + item.Password = secret.Password + } + } + } + if secret.PrivateKey != "" { + for i, _ := range f.LocalConfig.Ieee8021xConfigs { + item := &f.LocalConfig.Ieee8021xConfigs[i] + if item.ProfileName == secret.ProfileName { + item.PrivateKey = secret.PrivateKey + } + } } } + return utils.Success +} - configFileStatus := f.verifyWifiConfigurationFile() - if configFileStatus != 0 { - log.Error("config error") - // log.Error("config error: ", err) - return utils.IncorrectCommandLineParameters +func (f *Flags) promptForSecrets() int { + for i, _ := range f.LocalConfig.WifiConfigs { + item := &f.LocalConfig.WifiConfigs[i] + authMethod := models.AuthenticationMethod(item.AuthenticationMethod) + if authMethod == models.AuthenticationMethod_WPA2_PSK && + item.PskPassphrase == "" { + resultCode := f.PromptUserInput("Please enter PskPassphrase for "+item.ProfileName+": ", &item.PskPassphrase) + if resultCode != utils.Success { + return resultCode + } + } + } + for i, _ := range f.LocalConfig.Ieee8021xConfigs { + item := &f.LocalConfig.Ieee8021xConfigs[i] + authProtocol := models.AuthenticationProtocol(item.AuthenticationProtocol) + if authProtocol == models.AuthenticationProtocolPEAPv0_EAPMSCHAPv2 && + item.Password == "" { + resultCode := f.PromptUserInput("Please enter password for "+item.ProfileName+": ", &item.Password) + if resultCode != utils.Success { + return resultCode + } + } + if item.PrivateKey == "" { + resultCode := f.PromptUserInput("Please enter private key for "+item.ProfileName+": ", &item.PrivateKey) + if resultCode != utils.Success { + return resultCode + } + } } return utils.Success } -func (f *Flags) verifyWifiConfigurationFile() int { +func (f *Flags) verifyWifiConfigurations() int { for _, wifiConfigs := range f.LocalConfig.WifiConfigs { //Check profile name is not empty if wifiConfigs.ProfileName == "" { diff --git a/internal/flags/configure_test.go b/internal/flags/configure_test.go index 1bf81cb5..563de7fe 100644 --- a/internal/flags/configure_test.go +++ b/internal/flags/configure_test.go @@ -10,7 +10,18 @@ import ( "github.com/stretchr/testify/assert" ) +func TestConfigFiles(t *testing.T) { + cmdLine := "rpc configure addwifisettings -configFile ../../config-wifi.yaml -password test" + defer userInput(t, "userInput\nuserInput\nuserInput")() + //cmdLine := "rpc configure addwifisettings -configFile ../../config-wifi.yaml -secretFile ../../secrets-wifi.yaml -password test" + args := strings.Fields(cmdLine) + flags := NewFlags(args) + gotResult := flags.ParseFlags() + assert.Equal(t, utils.Success, gotResult) +} + func TestHandleConfigureCommand(t *testing.T) { + t.TempDir() cases := []struct { description string cmdLine string @@ -58,7 +69,7 @@ func TestHandleConfigureCommand(t *testing.T) { expectedResult: utils.IncorrectCommandLineParameters, }, {description: "Valid with reading from file", - cmdLine: "rpc configure addwifisettings -password Passw0rd! -config ../../config-wifi.yaml", + cmdLine: "rpc configure addwifisettings -password Passw0rd! -configFile ../../config-wifi.yaml", flagsLocal: true, expectedResult: utils.Success, }, @@ -140,7 +151,7 @@ func runVerifyWifiConfiguration(t *testing.T, expectedResult int, wifiCfgs confi for _, cfg := range ieee8021xCfgs { f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) } - gotResult := f.verifyWifiConfigurationFile() + gotResult := f.verifyWifiConfigurations() assert.Equal(t, expectedResult, gotResult) } diff --git a/internal/flags/flags.go b/internal/flags/flags.go index 7edd93be..e7b67f71 100644 --- a/internal/flags/flags.go +++ b/internal/flags/flags.go @@ -42,49 +42,46 @@ type HostnameInfo struct { // Flags holds data received from the command line type Flags struct { - commandLineArgs []string - URL string - DNS string - Hostname string - Proxy string - Command string - SubCommand string - Profile string - LMSAddress string - LMSPort string - SkipCertCheck bool - Verbose bool - Force bool - JsonOutput bool - RandomPassword bool - Local bool - StaticPassword string - Password string - LogLevel string - Token string - TenantID string - UseCCM bool - UseACM bool - configContent string - secretContent string - LocalConfig config.Config - amtInfoCommand *flag.FlagSet - amtActivateCommand *flag.FlagSet - amtDeactivateCommand *flag.FlagSet - amtMaintenanceAddWiFiSettingsCommand *flag.FlagSet - amtMaintenanceSyncIPCommand *flag.FlagSet - amtMaintenanceSyncClockCommand *flag.FlagSet - amtMaintenanceSyncHostnameCommand *flag.FlagSet - amtMaintenanceChangePasswordCommand *flag.FlagSet - versionCommand *flag.FlagSet - flagSetAddWifiSettings *flag.FlagSet - amtCommand amt.AMTCommand - netEnumerator NetEnumerator - IpConfiguration IPConfiguration - HostnameInfo HostnameInfo - AMTTimeoutDuration time.Duration - FriendlyName string - AmtInfo AmtInfoFlags + commandLineArgs []string + URL string + DNS string + Hostname string + Proxy string + Command string + SubCommand string + Profile string + LMSAddress string + LMSPort string + SkipCertCheck bool + Verbose bool + Force bool + JsonOutput bool + RandomPassword bool + Local bool + StaticPassword string + Password string + LogLevel string + Token string + TenantID string + UseCCM bool + UseACM bool + LocalConfig config.Config + amtInfoCommand *flag.FlagSet + amtActivateCommand *flag.FlagSet + amtDeactivateCommand *flag.FlagSet + amtMaintenanceSyncIPCommand *flag.FlagSet + amtMaintenanceSyncClockCommand *flag.FlagSet + amtMaintenanceSyncHostnameCommand *flag.FlagSet + amtMaintenanceChangePasswordCommand *flag.FlagSet + versionCommand *flag.FlagSet + flagSetAddWifiSettings *flag.FlagSet + amtCommand amt.AMTCommand + netEnumerator NetEnumerator + IpConfiguration IPConfiguration + HostnameInfo HostnameInfo + AMTTimeoutDuration time.Duration + FriendlyName string + AmtInfo AmtInfoFlags } func NewFlags(args []string) *Flags { @@ -100,7 +97,6 @@ func NewFlags(args []string) *Flags { flags.amtMaintenanceSyncClockCommand = flag.NewFlagSet("syncclock", flag.ContinueOnError) flags.amtMaintenanceSyncHostnameCommand = flag.NewFlagSet("synchostname", flag.ContinueOnError) flags.amtMaintenanceChangePasswordCommand = flag.NewFlagSet("changepassword", flag.ContinueOnError) - flags.amtMaintenanceAddWiFiSettingsCommand = flag.NewFlagSet("addwifisettings", flag.ContinueOnError) flags.versionCommand = flag.NewFlagSet(utils.CommandVersion, flag.ContinueOnError) flags.versionCommand.BoolVar(&flags.JsonOutput, "json", false, "json output") @@ -168,18 +164,15 @@ func (f *Flags) setupCommonFlags() { for _, fs := range []*flag.FlagSet{ f.amtActivateCommand, f.amtDeactivateCommand, - f.amtMaintenanceAddWiFiSettingsCommand, f.amtMaintenanceChangePasswordCommand, f.amtMaintenanceSyncClockCommand, f.amtMaintenanceSyncHostnameCommand, f.amtMaintenanceSyncIPCommand} { - if fs.Name() != "addiwfisettings" { // addwifisettings does not require remote settings since it is local - fs.StringVar(&f.URL, "u", "", "Websocket address of server to activate against") //required - fs.BoolVar(&f.SkipCertCheck, "n", false, "Skip Websocket server certificate verification") - fs.StringVar(&f.Proxy, "p", "", "Proxy address and port") - fs.StringVar(&f.Token, "token", "", "JWT Token for Authorization") - fs.StringVar(&f.TenantID, "tenant", "", "TenantID") - } + fs.StringVar(&f.URL, "u", "", "Websocket address of server to activate against") //required + fs.BoolVar(&f.SkipCertCheck, "n", false, "Skip Websocket server certificate verification") + fs.StringVar(&f.Proxy, "p", "", "Proxy address and port") + fs.StringVar(&f.Token, "token", "", "JWT Token for Authorization") + fs.StringVar(&f.TenantID, "tenant", "", "TenantID") fs.StringVar(&f.LMSAddress, "lmsaddress", utils.LMSAddress, "LMS address. Can be used to change location of LMS for debugging.") fs.StringVar(&f.LMSPort, "lmsport", utils.LMSPort, "LMS port") fs.BoolVar(&f.Verbose, "v", false, "Verbose output") @@ -211,6 +204,16 @@ func (f *Flags) lookupEnvOrBool(key string, defaultVal bool) bool { return defaultVal } +func (f *Flags) PromptUserInput(prompt string, value *string) int { + fmt.Println(prompt) + _, err := fmt.Scanln(value) + if err != nil { + log.Error(err) + return utils.InvalidUserInput + } + return utils.Success +} + func (f *Flags) ReadPasswordFromUser() (bool, int) { fmt.Println("Please enter AMT Password: ") var password string @@ -223,11 +226,11 @@ func (f *Flags) ReadPasswordFromUser() (bool, int) { } func (f *Flags) handleLocalConfig() int { - if f.configContent != "" { - err := cleanenv.ReadConfig(f.configContent, &f.LocalConfig) + if f.LocalConfig.FilePath != "" { + err := cleanenv.ReadConfig(f.LocalConfig.FilePath, &f.LocalConfig) if err != nil { log.Error("config error: ", err) - return utils.IncorrectCommandLineParameters + return utils.FailedReadingConfiguration } } return utils.Success diff --git a/internal/flags/maintenance.go b/internal/flags/maintenance.go index 4a5c579b..e74048a5 100644 --- a/internal/flags/maintenance.go +++ b/internal/flags/maintenance.go @@ -6,7 +6,6 @@ import ( "net" "os" "path/filepath" - "reflect" "regexp" "rpc/internal/amt" "rpc/pkg/utils" @@ -28,8 +27,6 @@ func (f *Flags) printMaintenanceUsage() string { usage = usage + " syncip Sync the IP configuration of the host OS to AMT Network Settings. AMT password is required\n" usage = usage + " Example: " + executable + " maintenance syncip -staticip 192.168.1.7 -netmask 255.255.255.0 -gateway 192.168.1.1 -primarydns 8.8.8.8 -secondarydns 4.4.4.4 -u wss://server/activate\n" usage = usage + " If a static ip is not specified, the ip address and netmask of the host OS is used\n" - usage = usage + " addwifisettings Add or modify WiFi settings in AMT. AMT password is required. A config.yml or command line flags must be provided for all settings. This command runs without cloud interaction.\n" - usage = usage + " Example: " + executable + " maintenance addwifisettings -password YourAMTPassword -config wificonfig.yaml\n" usage = usage + "\nRun '" + executable + " maintenance COMMAND -h' for more information on a command.\n" fmt.Println(usage) return usage @@ -46,9 +43,6 @@ func (f *Flags) handleMaintenanceCommand() int { f.SubCommand = f.commandLineArgs[2] switch f.SubCommand { - case "addwifisettings": - errCode = f.handleMaintenanceAddWifiSettings() - break case "syncclock": errCode = f.handleMaintenanceSyncClock() break @@ -89,46 +83,6 @@ func (f *Flags) handleMaintenanceCommand() int { return utils.Success } -func (f *Flags) handleMaintenanceAddWifiSettings() int { - // this is an implied local command - f.Local = true - - f.amtMaintenanceAddWiFiSettingsCommand.StringVar(&f.configContent, "config", "", "specify a config file ") - - f.amtMaintenanceAddWiFiSettingsCommand.StringVar(&f.LocalConfig.IEEE8021XSettings.Name, "name", "", "specify name") - f.amtMaintenanceAddWiFiSettingsCommand.IntVar(&f.LocalConfig.IEEE8021XSettings.AuthenticationMethod, "authenticationMethod", 0, "specify authentication method") - f.amtMaintenanceAddWiFiSettingsCommand.IntVar(&f.LocalConfig.IEEE8021XSettings.EncryptionMethod, "encryptionMethod", 0, "specify encryption method") - f.amtMaintenanceAddWiFiSettingsCommand.StringVar(&f.LocalConfig.IEEE8021XSettings.SSID, "ssid", "", "specify ssid") - f.amtMaintenanceAddWiFiSettingsCommand.StringVar(&f.LocalConfig.IEEE8021XSettings.Username, "username", "", "specify username") - f.amtMaintenanceAddWiFiSettingsCommand.IntVar(&f.LocalConfig.IEEE8021XSettings.AuthenticationProtocol, "authenticationProtocol", 0, "specify authentication protocol") - f.amtMaintenanceAddWiFiSettingsCommand.IntVar(&f.LocalConfig.IEEE8021XSettings.Priority, "priority", 0, "specify priority") - f.amtMaintenanceAddWiFiSettingsCommand.StringVar(&f.LocalConfig.IEEE8021XSettings.ClientCert, "clientCert", "", "specify client certificate") - f.amtMaintenanceAddWiFiSettingsCommand.StringVar(&f.LocalConfig.IEEE8021XSettings.CACert, "caCert", "", "specify CA certificate") - f.amtMaintenanceAddWiFiSettingsCommand.StringVar(&f.LocalConfig.IEEE8021XSettings.PrivateKey, "privateKey", "", "specify private key") - - if err := f.amtMaintenanceAddWiFiSettingsCommand.Parse(f.commandLineArgs[3:]); err != nil { - f.amtMaintenanceAddWiFiSettingsCommand.Usage() - return utils.IncorrectCommandLineParameters - } - - if f.JsonOutput { - log.SetFormatter(&log.JSONFormatter{}) - } - resultCode := f.handleLocalConfig() - if resultCode != utils.Success { - return resultCode - } - // Check if all fields are filled - v := reflect.ValueOf(f.LocalConfig.IEEE8021XSettings) - for i := 0; i < v.NumField(); i++ { - if v.Field(i).Interface() == "" { // not checking 0 since authenticantProtocol can and needs to be 0 for EAP-TLS - log.Error("Missing value for field: ", v.Type().Field(i).Name) - return utils.IncorrectCommandLineParameters - } - } - - return utils.Success -} func (f *Flags) handleMaintenanceSyncClock() int { if err := f.amtMaintenanceSyncClockCommand.Parse(f.commandLineArgs[3:]); err != nil { return utils.IncorrectCommandLineParameters diff --git a/pkg/utils/constants.go b/pkg/utils/constants.go index 3970c2a9..23a49318 100644 --- a/pkg/utils/constants.go +++ b/pkg/utils/constants.go @@ -60,6 +60,8 @@ const ( MissingOrIncorrectPrimaryDNS = 31 MissingOrIncorrectSecondaryDNS = 32 InvalidParameterCombination = 33 + FailedReadingConfiguration = 34 + InvalidUserInput = 35 // (70-99) Connection Errors RPSAuthenticationFailed = 70 diff --git a/secrets-wifi.yaml b/secrets-wifi.yaml new file mode 100644 index 00000000..b3b2dfbf --- /dev/null +++ b/secrets-wifi.yaml @@ -0,0 +1,6 @@ +secrets: + - profileName: 'wifiWPA2' + pskPassphrase: 'secrectPASSWORD' + - profileName: 'ieee8021xPEAPv0' + password: 'secrectPASSWORD' + privateKey: 'secretPrivateKey' From 892899c204241f9232ad2698a6b908e13aff1cf3 Mon Sep 17 00:00:00 2001 From: Tim Shockley Date: Thu, 17 Aug 2023 15:28:01 -0700 Subject: [PATCH 25/29] fix: unit tests and configJson capability --- internal/flags/activate_test.go | 6 ++--- internal/flags/configure.go | 16 +++++++++++++ internal/flags/configure_test.go | 10 ++++++++- internal/flags/flags_test.go | 4 ++-- internal/flags/maintenance_test.go | 36 ------------------------------ secrets-wifi.yaml | 3 ++- 6 files changed, 32 insertions(+), 43 deletions(-) diff --git a/internal/flags/activate_test.go b/internal/flags/activate_test.go index b892869b..4a957cdb 100644 --- a/internal/flags/activate_test.go +++ b/internal/flags/activate_test.go @@ -180,15 +180,15 @@ func TestHandleActivateCommandLocal(t *testing.T) { wantResult: utils.MissingOrIncorrectPassword, }, "should fail if acm and local config file error": { - cmdLine: "./rpc activate -local -acm -config ./nofilehere.txt", - wantResult: utils.IncorrectCommandLineParameters, + cmdLine: "./rpc activate -local -acm -configFile ./nofilehere.txt", + wantResult: utils.FailedReadingConfiguration, }, "should fail if acm and ACM Settings not specified": { cmdLine: "./rpc activate -local -acm", wantResult: utils.IncorrectCommandLineParameters, }, "should pass if acm with example config file": { - cmdLine: "./rpc activate -local -acm -config ../../config.yaml", + cmdLine: "./rpc activate -local -acm -configFile ../../config.yaml", wantResult: utils.Success, }, "should pass wif acm and ACM Settings specified": { diff --git a/internal/flags/configure.go b/internal/flags/configure.go index 9cb1480c..30fdcde3 100644 --- a/internal/flags/configure.go +++ b/internal/flags/configure.go @@ -1,6 +1,7 @@ package flags import ( + "encoding/json" "fmt" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim/models" "os" @@ -60,11 +61,13 @@ func (f *Flags) handleAddWifiSettings() int { var err error var resultCode int var wifiSecretConfig config.SecretConfig + var configJson string f.flagSetAddWifiSettings.BoolVar(&f.Verbose, "v", false, "Verbose output") f.flagSetAddWifiSettings.StringVar(&f.LogLevel, "l", "info", "Log level (panic,fatal,error,warn,info,debug,trace)") f.flagSetAddWifiSettings.BoolVar(&f.JsonOutput, "json", false, "JSON output") f.flagSetAddWifiSettings.StringVar(&f.Password, "password", f.lookupEnvOrString("AMT_PASSWORD", ""), "AMT password") f.flagSetAddWifiSettings.StringVar(&f.LocalConfig.FilePath, "configFile", "", "specify a config file ") + f.flagSetAddWifiSettings.StringVar(&configJson, "configJson", "", "configuration as a JSON string") f.flagSetAddWifiSettings.StringVar(&wifiSecretConfig.FilePath, "secretFile", "", "specify a secret file ") // Params for entering a single wifi config from command line wifiCfg := config.WifiConfig{} @@ -96,12 +99,25 @@ func (f *Flags) handleAddWifiSettings() int { ieee8021xCfg.ProfileName = wifiCfg.ProfileName } + if configJson != "" { + err := json.Unmarshal([]byte(configJson), &f.LocalConfig) + if err != nil { + log.Error(err) + return utils.IncorrectCommandLineParameters + } + } f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfg) f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, ieee8021xCfg) resultCode = f.handleLocalConfig() if resultCode != utils.Success { return resultCode } + cfgs, err := json.Marshal(f.LocalConfig) + if err != nil { + log.Error("unable to marshal activationResponse to JSON") + return 0 + } + fmt.Println(string(cfgs)) if wifiSecretConfig.FilePath != "" { err = cleanenv.ReadConfig(wifiSecretConfig.FilePath, &wifiSecretConfig) diff --git a/internal/flags/configure_test.go b/internal/flags/configure_test.go index 563de7fe..4658c443 100644 --- a/internal/flags/configure_test.go +++ b/internal/flags/configure_test.go @@ -20,6 +20,14 @@ func TestConfigFiles(t *testing.T) { assert.Equal(t, utils.Success, gotResult) } +func TestConfigJson(t *testing.T) { + cmdLine := `rpc configure addwifisettings -secretFile ../../secrets-wifi.yaml -password test -configJson {"Password":"","FilePath":"../../config-wifi.yaml","WifiConfigs":[{"ProfileName":"wifiWPA2","SSID":"ssid","Priority":1,"AuthenticationMethod":6,"EncryptionMethod":4,"PskPassphrase":"","Ieee8021xProfileName":""},{"ProfileName":"wifi8021x","SSID":"ssid","Priority":2,"AuthenticationMethod":7,"EncryptionMethod":4,"PskPassphrase":"","Ieee8021xProfileName":"ieee8021xEAP-TLS"}],"Ieee8021xConfigs":[{"ProfileName":"ieee8021xEAP-TLS","Username":"test","Password":"","AuthenticationProtocol":0,"ClientCert":"test","CACert":"test","PrivateKey":""},{"ProfileName":"ieee8021xPEAPv0","Username":"test","Password":"","AuthenticationProtocol":2,"ClientCert":"testClientCert","CACert":"testCaCert","PrivateKey":"testPrivateKey"}],"AMTPassword":"","ProvisioningCert":"","ProvisioningCertPwd":""}` + defer userInput(t, "userInput\nuserInput\nuserInput")() + args := strings.Fields(cmdLine) + flags := NewFlags(args) + gotResult := flags.ParseFlags() + assert.Equal(t, utils.Success, gotResult) +} func TestHandleConfigureCommand(t *testing.T) { t.TempDir() cases := []struct { @@ -69,7 +77,7 @@ func TestHandleConfigureCommand(t *testing.T) { expectedResult: utils.IncorrectCommandLineParameters, }, {description: "Valid with reading from file", - cmdLine: "rpc configure addwifisettings -password Passw0rd! -configFile ../../config-wifi.yaml", + cmdLine: "rpc configure addwifisettings -password Passw0rd! -configFile ../../config-wifi.yaml -secretFile ../../secrets-wifi.yaml", flagsLocal: true, expectedResult: utils.Success, }, diff --git a/internal/flags/flags_test.go b/internal/flags/flags_test.go index 639d8ae3..8c7f87bb 100644 --- a/internal/flags/flags_test.go +++ b/internal/flags/flags_test.go @@ -231,10 +231,10 @@ func TestParseFlagsVersion(t *testing.T) { assert.Equal(t, false, flags.JsonOutput) } func TestParseFlagsConfigure(t *testing.T) { - args := []string{"./rpc", "configure", "addwifisettings", "-config", "../../config-wifi.yaml", "-password", "Passw0rd!"} + args := []string{"./rpc", "configure"} flags := NewFlags(args) result := flags.ParseFlags() - assert.EqualValues(t, result, utils.Success) + assert.EqualValues(t, utils.IncorrectCommandLineParameters, result) assert.Equal(t, flags.Command, utils.CommandConfigure) assert.Equal(t, false, flags.JsonOutput) } diff --git a/internal/flags/maintenance_test.go b/internal/flags/maintenance_test.go index e35808e3..c4341b9d 100644 --- a/internal/flags/maintenance_test.go +++ b/internal/flags/maintenance_test.go @@ -27,8 +27,6 @@ func TestPrintMaintenanceUsage(t *testing.T) { usage = usage + " syncip Sync the IP configuration of the host OS to AMT Network Settings. AMT password is required\n" usage = usage + " Example: " + executable + " maintenance syncip -staticip 192.168.1.7 -netmask 255.255.255.0 -gateway 192.168.1.1 -primarydns 8.8.8.8 -secondarydns 4.4.4.4 -u wss://server/activate\n" usage = usage + " If a static ip is not specified, the ip address and netmask of the host OS is used\n" - usage = usage + " addwifisettings Add or modify WiFi settings in AMT. AMT password is required. A config.yml or command line flags must be provided for all settings. This command runs without cloud interaction.\n" - usage = usage + " Example: " + executable + " maintenance addwifisettings -password YourAMTPassword -config wificonfig.yaml\n" usage = usage + "\nRun '" + executable + " maintenance COMMAND -h' for more information on a command.\n" assert.Equal(t, usage, output) } @@ -180,24 +178,6 @@ func TestParseFlagsMaintenance(t *testing.T) { wantResult: utils.Success, userInput: trickyPassword, }, - "should fail - addwifisettings cannot find file": { - cmdLine: cmdBase + " " + argAddWiFiSettings + " ", - wantResult: utils.IncorrectCommandLineParameters, - }, - "should fail - addwifisettings fail empty password user input": { - cmdLine: cmdBase + " " + argAddWiFiSettings + " --config ../../config.yaml", - wantResult: utils.MissingOrIncorrectPassword, - userInput: "", - }, - "should pass - addwifisettings password user input": { - cmdLine: cmdBase + " " + argAddWiFiSettings + " --config ../../config.yaml", - wantResult: utils.Success, - userInput: trickyPassword, - }, - "should pass - addwifisettings": { - cmdLine: cmdBase + " " + argAddWiFiSettings + " --config ../../config.yaml " + argCurPw, - wantResult: utils.Success, - }, } for name, tc := range tests { @@ -221,19 +201,3 @@ func TestParseFlagsMaintenance(t *testing.T) { }) } } - -// TestHandleLocalCommand is a test function for handleAddWifiSettings method of Flags struct. -func TestHandleLocalCommand(t *testing.T) { - // Setup environment - os.Setenv("AMT_PASSWORD", "test_password") - defer os.Unsetenv("AMT_PASSWORD") - args := []string{"./rpc", "maintenance", "addwifisetting", ""} - // Setup flags - flags := NewFlags(args) - flags.amtCommand.PTHI = MockPTHICommands{} - expectedErrorCode := utils.IncorrectCommandLineParameters - errorCode := flags.handleAddWifiSettings() - if errorCode != expectedErrorCode { - t.Errorf("handleAddWifiSettings() error code = %v; want %v", errorCode, expectedErrorCode) - } -} diff --git a/secrets-wifi.yaml b/secrets-wifi.yaml index b3b2dfbf..b50852ab 100644 --- a/secrets-wifi.yaml +++ b/secrets-wifi.yaml @@ -1,6 +1,7 @@ secrets: - profileName: 'wifiWPA2' pskPassphrase: 'secrectPASSWORD' + - profileName: 'ieee8021xEAP-TLS' + privateKey: 'secretPrivateKey' - profileName: 'ieee8021xPEAPv0' password: 'secrectPASSWORD' - privateKey: 'secretPrivateKey' From f46cf43810eac6ba4cbc3e36697412157edf844a Mon Sep 17 00:00:00 2001 From: Tim Shockley Date: Fri, 18 Aug 2023 01:30:51 -0700 Subject: [PATCH 26/29] feat: split up verification for 8021x and unit tests --- internal/flags/configure.go | 192 +++++++++++++++++-------- internal/flags/configure_test.go | 236 ++++++++++++++++++++++++------- 2 files changed, 314 insertions(+), 114 deletions(-) diff --git a/internal/flags/configure.go b/internal/flags/configure.go index 30fdcde3..206e2ed6 100644 --- a/internal/flags/configure.go +++ b/internal/flags/configure.go @@ -49,11 +49,22 @@ func (f *Flags) handleConfigureCommand() int { f.Local = true if f.Password == "" { - if _, errCode := f.ReadPasswordFromUser(); errCode != 0 { + if f.LocalConfig.Password != "" { + f.Password = f.LocalConfig.Password + } else { + if _, errCode := f.ReadPasswordFromUser(); errCode != 0 { + return utils.MissingOrIncorrectPassword + } + f.LocalConfig.Password = f.Password + } + } else { + if f.LocalConfig.Password == "" { + f.LocalConfig.Password = f.Password + } else if f.LocalConfig.Password != f.Password { + log.Error("password does not match config file password") return utils.MissingOrIncorrectPassword } } - f.LocalConfig.Password = f.Password return utils.Success } @@ -99,25 +110,19 @@ func (f *Flags) handleAddWifiSettings() int { ieee8021xCfg.ProfileName = wifiCfg.ProfileName } - if configJson != "" { - err := json.Unmarshal([]byte(configJson), &f.LocalConfig) - if err != nil { - log.Error(err) - return utils.IncorrectCommandLineParameters - } - } f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfg) f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, ieee8021xCfg) resultCode = f.handleLocalConfig() if resultCode != utils.Success { return resultCode } - cfgs, err := json.Marshal(f.LocalConfig) - if err != nil { - log.Error("unable to marshal activationResponse to JSON") - return 0 + if configJson != "" { + err := json.Unmarshal([]byte(configJson), &f.LocalConfig) + if err != nil { + log.Error(err) + return utils.IncorrectCommandLineParameters + } } - fmt.Println(string(cfgs)) if wifiSecretConfig.FilePath != "" { err = cleanenv.ReadConfig(wifiSecretConfig.FilePath, &wifiSecretConfig) @@ -181,6 +186,9 @@ func (f *Flags) mergeWifiSecrets(wifiSecretConfig config.SecretConfig) int { func (f *Flags) promptForSecrets() int { for i, _ := range f.LocalConfig.WifiConfigs { item := &f.LocalConfig.WifiConfigs[i] + if item.ProfileName == "" { + continue + } authMethod := models.AuthenticationMethod(item.AuthenticationMethod) if authMethod == models.AuthenticationMethod_WPA2_PSK && item.PskPassphrase == "" { @@ -192,6 +200,9 @@ func (f *Flags) promptForSecrets() int { } for i, _ := range f.LocalConfig.Ieee8021xConfigs { item := &f.LocalConfig.Ieee8021xConfigs[i] + if item.ProfileName == "" { + continue + } authProtocol := models.AuthenticationProtocol(item.AuthenticationProtocol) if authProtocol == models.AuthenticationProtocolPEAPv0_EAPMSCHAPv2 && item.Password == "" { @@ -211,74 +222,131 @@ func (f *Flags) promptForSecrets() int { } func (f *Flags) verifyWifiConfigurations() int { - for _, wifiConfigs := range f.LocalConfig.WifiConfigs { + for _, cfg := range f.LocalConfig.WifiConfigs { //Check profile name is not empty - if wifiConfigs.ProfileName == "" { + if cfg.ProfileName == "" { log.Error("missing profile name") return utils.MissingOrIncorrectProfile } //Check ssid is not empty - if wifiConfigs.SSID == "" { - log.Error("missing ssid for profile: ", wifiConfigs.ProfileName) + if cfg.SSID == "" { + log.Error("missing ssid for config: ", cfg.ProfileName) return utils.MissingOrIncorrectProfile } //Check priority is not empty - if wifiConfigs.Priority == 0 { - log.Error("missing priority for profile: ", wifiConfigs.ProfileName) + if cfg.Priority <= 0 { + log.Error("invalid priority for config: ", cfg.ProfileName) return utils.MissingOrIncorrectProfile } - //Check authenticationMethod is not empty - if wifiConfigs.AuthenticationMethod == 0 { - log.Error("missing authenticationMethod for profile: ", wifiConfigs.ProfileName) + + authenticationMethod := models.AuthenticationMethod(cfg.AuthenticationMethod) + switch authenticationMethod { + case models.AuthenticationMethod_WPA_PSK: + break + case models.AuthenticationMethod_WPA2_PSK: + if cfg.PskPassphrase == "" { + log.Error("missing PskPassphrase for config: ", cfg.ProfileName) + return utils.MissingOrIncorrectProfile + } + break + case models.AuthenticationMethod_WPA_IEEE8021x: + fallthrough + case models.AuthenticationMethod_WPA2_IEEE8021x: + if cfg.PskPassphrase != "" { + log.Error("wifi configuration contains passphrase: ", cfg.ProfileName) + return utils.MissingOrIncorrectProfile + } + resultCode := f.verifyMatchingIeee8021xConfig(cfg.Ieee8021xProfileName) + if resultCode != utils.Success { + return resultCode + } + break + default: + log.Error("invalid AuthenticationMethod for config: ", cfg.ProfileName) return utils.MissingOrIncorrectProfile } - //Check encryptionMethod is not empty - if wifiConfigs.EncryptionMethod == 0 { - log.Error("missing encryptionMethod for profile: ", wifiConfigs.ProfileName) + + encryptionMethod := models.EncryptionMethod(cfg.EncryptionMethod) + // NOTE: this is only + switch encryptionMethod { + case models.EncryptionMethod_TKIP: + fallthrough + case models.EncryptionMethod_CCMP: + break + default: + log.Error("invalid EncryptionMethod for config: ", cfg.ProfileName) return utils.MissingOrIncorrectProfile } - //Check authentication method - if wifiConfigs.AuthenticationMethod == 6 && wifiConfigs.PskPassphrase == "" { - log.Error("wifi configuration missing passphrase: ", wifiConfigs.ProfileName) - return utils.MissingOrIncorrectProfile + } + return utils.Success +} + +func (f *Flags) verifyMatchingIeee8021xConfig(profileName string) int { + if profileName == "" { + log.Error("empty ieee802xCfg profile name") + return utils.MissingOrIncorrectProfile + } + foundOne := false + for _, ieee802xCfg := range f.LocalConfig.Ieee8021xConfigs { + if profileName != ieee802xCfg.ProfileName { + continue } - if (wifiConfigs.AuthenticationMethod == 5 || wifiConfigs.AuthenticationMethod == 7) && wifiConfigs.PskPassphrase != "" { - log.Error("wifi configuration contains passphrase: ", wifiConfigs.ProfileName) + if foundOne { + log.Error("duplicate IEEE802x Profile names: ", ieee802xCfg.ProfileName) return utils.MissingOrIncorrectProfile } - if wifiConfigs.AuthenticationMethod == 5 || wifiConfigs.AuthenticationMethod == 7 { - //Check for ieee8021xProfileName in IEEE8021XSettings - var matchedIeeeProfileName int = 0 - - for _, ieee802xSettings := range f.LocalConfig.Ieee8021xConfigs { - if wifiConfigs.Ieee8021xProfileName == ieee802xSettings.ProfileName { - matchedIeeeProfileName++ - } - // fmt.Println("ieee:", ieee802xSettings) - } - //Check if more than on ieee profile name matched. - if matchedIeeeProfileName > 1 { - log.Error("duplicate IEEE802x Profile names") - return utils.MissingOrIncorrectProfile - } + foundOne = true + resultCode := f.verifyIeee8021xConfig(ieee802xCfg) + if resultCode != utils.Success { + return resultCode } - // fmt.Println("wifi: ", wifiConfigs) } - for _, ieee8021xConfigs := range f.LocalConfig.Ieee8021xConfigs { - //Check profile name is not empty in IEEE802.1x config - if ieee8021xConfigs.ProfileName == "" { - log.Error("missing profile name in IEEE802.1x config") - return utils.MissingOrIncorrectProfile - } + if !foundOne { + log.Error("missing IEEE802x Profile: ", profileName) + return utils.MissingOrIncorrectProfile } return utils.Success } -func ieee8021xCfgIsEmpty(config config.Ieee8021xConfig) bool { - return config.ProfileName == "" && - config.Username == "" && - config.Password == "" && - config.AuthenticationProtocol == 0 && - config.ClientCert == "" && - config.CACert == "" && - config.PrivateKey == "" + +func (f *Flags) verifyIeee8021xConfig(cfg config.Ieee8021xConfig) int { + + if cfg.Username == "" { + log.Error("missing Username for Ieee8021xConfig: ", cfg.ProfileName) + return utils.MissingOrIncorrectProfile + } + if cfg.ClientCert == "" { + log.Error("missing ClientCert for Ieee8021xConfig: ", cfg.ProfileName) + return utils.MissingOrIncorrectProfile + } + if cfg.CACert == "" { + log.Error("missing CACert for Ieee8021xConfig: ", cfg.ProfileName) + return utils.MissingOrIncorrectProfile + } + if cfg.PrivateKey == "" { + log.Error("missing PrivateKey for Ieee8021xConfig: ", cfg.ProfileName) + return utils.MissingOrIncorrectProfile + } + authenticationProtocol := models.AuthenticationProtocol(cfg.AuthenticationProtocol) + // not all defined protocols are supported + switch authenticationProtocol { + case models.AuthenticationProtocolEAPTLS: + fallthrough + case models.AuthenticationProtocolPEAPv1_EAPGTC: + fallthrough + case models.AuthenticationProtocolEAPFAST_GTC: + fallthrough + case models.AuthenticationProtocolEAPFAST_TLS: + break + case models.AuthenticationProtocolPEAPv0_EAPMSCHAPv2: + if cfg.Password == "" { + log.Error("missing Password for for PEAPv0_EAPMSCHAPv2 Ieee8021xConfig: ", cfg.ProfileName) + return utils.MissingOrIncorrectPassword + } + break + default: + log.Error("invalid AuthenticationProtocol for Ieee8021xConfig: ", cfg.ProfileName) + return utils.MissingOrIncorrectProfile + } + + return utils.Success } diff --git a/internal/flags/configure_test.go b/internal/flags/configure_test.go index 4658c443..5e0a6d71 100644 --- a/internal/flags/configure_test.go +++ b/internal/flags/configure_test.go @@ -10,14 +10,117 @@ import ( "github.com/stretchr/testify/assert" ) -func TestConfigFiles(t *testing.T) { - cmdLine := "rpc configure addwifisettings -configFile ../../config-wifi.yaml -password test" - defer userInput(t, "userInput\nuserInput\nuserInput")() - //cmdLine := "rpc configure addwifisettings -configFile ../../config-wifi.yaml -secretFile ../../secrets-wifi.yaml -password test" - args := strings.Fields(cmdLine) - flags := NewFlags(args) - gotResult := flags.ParseFlags() - assert.Equal(t, utils.Success, gotResult) +func getPromptForSecretsFlags() Flags { + f := Flags{} + f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfgWPA2) + f.LocalConfig.WifiConfigs[0].PskPassphrase = "" + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, ieee8021xCfgPEAPv0_EAPMSCHAPv2) + f.LocalConfig.Ieee8021xConfigs[0].PrivateKey = "" + f.LocalConfig.Ieee8021xConfigs[0].Password = "" + return f +} + +func TestPromptForSecrets(t *testing.T) { + + t.Run("expect success on valid user input", func(t *testing.T) { + defer userInput(t, "userInput\nuserInput\nuserInput")() + f := getPromptForSecretsFlags() + resultCode := f.promptForSecrets() + assert.Equal(t, utils.Success, resultCode) + assert.Equal(t, "userInput", f.LocalConfig.WifiConfigs[0].PskPassphrase) + assert.Equal(t, "userInput", f.LocalConfig.Ieee8021xConfigs[0].PrivateKey) + assert.Equal(t, "userInput", f.LocalConfig.Ieee8021xConfigs[0].Password) + }) + t.Run("expect InvalidUserInput", func(t *testing.T) { + defer userInput(t, "userInput\nuserInput")() + f := getPromptForSecretsFlags() + resultCode := f.promptForSecrets() + assert.Equal(t, utils.InvalidUserInput, resultCode) + assert.Equal(t, "userInput", f.LocalConfig.WifiConfigs[0].PskPassphrase) + assert.Equal(t, "userInput", f.LocalConfig.Ieee8021xConfigs[0].Password) + assert.Equal(t, "", f.LocalConfig.Ieee8021xConfigs[0].PrivateKey) + }) + t.Run("expect InvalidUserInput", func(t *testing.T) { + defer userInput(t, "userInput")() + f := getPromptForSecretsFlags() + resultCode := f.promptForSecrets() + assert.Equal(t, utils.InvalidUserInput, resultCode) + assert.Equal(t, "userInput", f.LocalConfig.WifiConfigs[0].PskPassphrase) + assert.Equal(t, "", f.LocalConfig.Ieee8021xConfigs[0].Password) + assert.Equal(t, "", f.LocalConfig.Ieee8021xConfigs[0].PrivateKey) + }) + t.Run("expect InvalidUserInput", func(t *testing.T) { + f := getPromptForSecretsFlags() + resultCode := f.promptForSecrets() + assert.Equal(t, utils.InvalidUserInput, resultCode) + assert.Equal(t, "", f.LocalConfig.WifiConfigs[0].PskPassphrase) + assert.Equal(t, "", f.LocalConfig.Ieee8021xConfigs[0].Password) + assert.Equal(t, "", f.LocalConfig.Ieee8021xConfigs[0].PrivateKey) + }) +} + +func TestCmdLine(t *testing.T) { + jsonCfgStr := `{"WifiConfigs":[{"ProfileName":"wifiWPA", "SSID":"ssid", "Priority":1, "AuthenticationMethod":4, "EncryptionMethod":4}]}` + + t.Run("expect IncorrectCommandLineParameters with no subcommand", func(t *testing.T) { + f := NewFlags([]string{`rpc`, `configure`}) + gotResult := f.ParseFlags() + assert.Equal(t, utils.IncorrectCommandLineParameters, gotResult) + }) + t.Run("expect IncorrectCommandLineParameters with unknown subcommand", func(t *testing.T) { + f := NewFlags([]string{`rpc`, `configure`, `what-the-heck?`}) + gotResult := f.ParseFlags() + assert.Equal(t, utils.IncorrectCommandLineParameters, gotResult) + }) + t.Run("expect Success", func(t *testing.T) { + cmdLine := []string{ + `rpc`, `configure`, `addwifisettings`, + `-password`, `cliP@ss0rd!`, + `-configJson`, jsonCfgStr, + } + f := NewFlags(cmdLine) + gotResult := f.ParseFlags() + assert.Equal(t, utils.Success, gotResult) + assert.Equal(t, true, f.Local) + assert.Equal(t, f.Password, f.LocalConfig.Password) + }) + t.Run("expect MissingOrIncorrectPassword", func(t *testing.T) { + f := NewFlags([]string{ + `rpc`, `configure`, `addwifisettings`, + `-configJson`, jsonCfgStr, + }) + gotResult := f.ParseFlags() + assert.Equal(t, utils.MissingOrIncorrectPassword, gotResult) + }) + t.Run("expect Success on password prompt", func(t *testing.T) { + defer userInput(t, "userP@ssw0rd!")() + f := NewFlags([]string{ + `rpc`, `configure`, `addwifisettings`, + `-configJson`, jsonCfgStr, + }) + gotResult := f.ParseFlags() + assert.Equal(t, utils.Success, gotResult) + }) + t.Run("expect Success when password is in config file", func(t *testing.T) { + defer userInput(t, "userP@ssw0rd!")() + f := NewFlags([]string{ + `rpc`, `configure`, `addwifisettings`, + `-configJson`, jsonCfgStr, + }) + f.LocalConfig.Password = "localP@ssw0rd!" + gotResult := f.ParseFlags() + assert.Equal(t, utils.Success, gotResult) + }) + t.Run("expect MissingOrIncorrectPassword when passwords do not match", func(t *testing.T) { + f := NewFlags([]string{ + `rpc`, `configure`, `addwifisettings`, + `-password`, `cliP@ss0rd!`, + `-configJson`, jsonCfgStr, + }) + f.LocalConfig.Password = "localP@ssw0rd!" + gotResult := f.ParseFlags() + assert.Equal(t, utils.MissingOrIncorrectPassword, gotResult) + }) } func TestConfigJson(t *testing.T) { @@ -28,57 +131,46 @@ func TestConfigJson(t *testing.T) { gotResult := flags.ParseFlags() assert.Equal(t, utils.Success, gotResult) } -func TestHandleConfigureCommand(t *testing.T) { - t.TempDir() +func TestHandleAddWifiSettings(t *testing.T) { cases := []struct { description string cmdLine string - flagsLocal bool expectedResult int }{ - // {description: "Basic wifi config command line", - // cmdLine: "rpc configure addwifisettings -password Passw0rd! -profilename cliprofname -authenticationMethod 6 -encryptionMethod 4 -ssid \"myclissid\" -priority 1 -PskPassphrase \"mypassword\" -Ieee8021xProfileName \"\"", - // flagsLocal: true, - // expectedResult: utils.Success, - // }, {description: "Missing Ieee8021xProfileName value", cmdLine: "rpc configure addwifisettings -password Passw0rd! -profilename cliprofname -authenticationMethod 6 -encryptionMethod 4 -ssid \"myclissid\" -priority 1 -PskPassphrase \"mypassword\" -Ieee8021xProfileName", - flagsLocal: false, expectedResult: utils.IncorrectCommandLineParameters, }, {description: "Missing PskPassphrase value", cmdLine: "rpc configure addwifisettings -password Passw0rd! -profilename cliprofname -authenticationMethod 6 -encryptionMethod 4 -ssid \"myclissid\" -priority 1 -PskPassphrase", - flagsLocal: false, expectedResult: utils.IncorrectCommandLineParameters, }, {description: "Missing priority value", cmdLine: "rpc configure addwifisettings -password Passw0rd! -profilename cliprofname -authenticationMethod 6 -encryptionMethod 4 -ssid \"myclissid\" -priority", - flagsLocal: false, expectedResult: utils.IncorrectCommandLineParameters, }, {description: "Missing ssid value", cmdLine: "rpc configure addwifisettings -password Passw0rd! -profilename cliprofname -authenticationMethod 6 -encryptionMethod 4 -ssid", - flagsLocal: false, expectedResult: utils.IncorrectCommandLineParameters, }, {description: "Missing authenticationMethod value", cmdLine: "rpc configure addwifisettings -password Passw0rd! -profilename cliprofname -authenticationMethod", - flagsLocal: false, expectedResult: utils.IncorrectCommandLineParameters, }, {description: "Missing profile name", cmdLine: "rpc configure addwifisettings -password Passw0rd! -profilename", - flagsLocal: false, expectedResult: utils.IncorrectCommandLineParameters, }, {description: "Missing filename", cmdLine: "rpc configure addwifisettings -password Passw0rd! -config", - flagsLocal: false, + expectedResult: utils.IncorrectCommandLineParameters, + }, + {description: "Missing password", + cmdLine: "rpc configure addwifisettings -password Passw0rd! -config", expectedResult: utils.IncorrectCommandLineParameters, }, {description: "Valid with reading from file", cmdLine: "rpc configure addwifisettings -password Passw0rd! -configFile ../../config-wifi.yaml -secretFile ../../secrets-wifi.yaml", - flagsLocal: true, expectedResult: utils.Success, }, } @@ -86,12 +178,8 @@ func TestHandleConfigureCommand(t *testing.T) { t.Run(tc.description, func(t *testing.T) { args := strings.Fields(tc.cmdLine) flags := NewFlags(args) - gotResult := flags.ParseFlags() - - assert.Equal(t, flags.Local, tc.flagsLocal) + gotResult := flags.handleAddWifiSettings() assert.Equal(t, tc.expectedResult, gotResult) - assert.Equal(t, utils.CommandConfigure, flags.Command) - assert.Equal(t, utils.SubCommandAddWifiSettings, flags.SubCommand) }) } } @@ -101,7 +189,7 @@ var wifiCfgWPA = config.WifiConfig{ SSID: "ssid", Priority: 1, AuthenticationMethod: int(models.AuthenticationMethod_WPA_PSK), - EncryptionMethod: int(models.EncryptionMethod_CCMP), + EncryptionMethod: int(models.EncryptionMethod_TKIP), } var wifiCfgWPA2 = config.WifiConfig{ @@ -196,7 +284,7 @@ func TestVerifyWifiConfigurationFile(t *testing.T) { }) t.Run("expect MissingOrIncorrectProfile with invalid AuthenticationMethod", func(t *testing.T) { orig := wifiCfgWPA.AuthenticationMethod - wifiCfgWPA.AuthenticationMethod = 0 + wifiCfgWPA.AuthenticationMethod = int(models.AuthenticationMethod_DMTFReserved) runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, config.WifiConfigs{wifiCfgWPA}, config.Ieee8021xConfigs{}) @@ -204,7 +292,7 @@ func TestVerifyWifiConfigurationFile(t *testing.T) { }) t.Run("expect MissingOrIncorrectProfile with invalid EncryptionMethod", func(t *testing.T) { orig := wifiCfgWPA.EncryptionMethod - wifiCfgWPA.EncryptionMethod = 0 + wifiCfgWPA.EncryptionMethod = int(models.EncryptionMethod_DMTFReserved) runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, config.WifiConfigs{wifiCfgWPA}, config.Ieee8021xConfigs{}) @@ -258,25 +346,69 @@ func TestVerifyWifiConfigurationFile(t *testing.T) { }) } -func TestIeee8021xCfgIsEmpty(t *testing.T) { - emptyConfig := config.Ieee8021xConfig{} - notEmptyConfig := config.Ieee8021xConfig{ - ProfileName: "wifi-8021x", - Username: "user", - Password: "pass", - AuthenticationProtocol: 1, - ClientCert: "cert", - CACert: "caCert", - PrivateKey: "key", - } - - empty := ieee8021xCfgIsEmpty(emptyConfig) - if !empty { - t.Errorf("Expected empty config to return true, but got false") - } +func TestVerifyMatchingIeee8021xConfig(t *testing.T) { + name := "profileName" + cfg := config.Ieee8021xConfig{} + t.Run("expect MissingOrIncorrectProfile with missing name", func(t *testing.T) { + f := Flags{} + resultCode := f.verifyMatchingIeee8021xConfig("") + assert.Equal(t, utils.MissingOrIncorrectProfile, resultCode) + }) + t.Run("expect MissingOrIncorrectProfile if no matching profile", func(t *testing.T) { + f := Flags{} + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) + resultCode := f.verifyMatchingIeee8021xConfig(name) + assert.Equal(t, utils.MissingOrIncorrectProfile, resultCode) + }) + t.Run("expect MissingOrIncorrectProfile if missing username", func(t *testing.T) { + f := Flags{} + cfg.ProfileName = name + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) + resultCode := f.verifyMatchingIeee8021xConfig(name) + assert.Equal(t, utils.MissingOrIncorrectProfile, resultCode) + }) + t.Run("expect MissingOrIncorrectProfile if missing ClientCert", func(t *testing.T) { + f := Flags{} + cfg.Username = "UserName" + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) + resultCode := f.verifyMatchingIeee8021xConfig(name) + assert.Equal(t, utils.MissingOrIncorrectProfile, resultCode) + }) + t.Run("expect MissingOrIncorrectProfile if missing CACert", func(t *testing.T) { + f := Flags{} + cfg.ClientCert = "AABBCCDDEEFF" + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) + resultCode := f.verifyMatchingIeee8021xConfig(name) + assert.Equal(t, utils.MissingOrIncorrectProfile, resultCode) + }) + t.Run("expect MissingOrIncorrectProfile if missing PrivateKey", func(t *testing.T) { + f := Flags{} + cfg.CACert = "AABBCCDDEEFF" + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) + resultCode := f.verifyMatchingIeee8021xConfig(name) + assert.Equal(t, utils.MissingOrIncorrectProfile, resultCode) + }) + t.Run("expect MissingOrIncorrectProfile if unsupported/invalid AuthenticationProtocol", func(t *testing.T) { + f := Flags{} + cfg.PrivateKey = "AABBCCDDEEFF" + cfg.AuthenticationProtocol = int(models.AuthenticationProtocolEAP_AKA) + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) + resultCode := f.verifyMatchingIeee8021xConfig(name) + assert.Equal(t, utils.MissingOrIncorrectProfile, resultCode) + }) + t.Run("expect MissingOrIncorrectProfile if missing PskPassphrase", func(t *testing.T) { + f := Flags{} + cfg.AuthenticationProtocol = int(models.AuthenticationProtocolPEAPv0_EAPMSCHAPv2) + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) + resultCode := f.verifyMatchingIeee8021xConfig(name) + assert.Equal(t, utils.MissingOrIncorrectPassword, resultCode) + }) + t.Run("expect MissingOrIncorrectProfile if missing PskPassphrase", func(t *testing.T) { + f := Flags{} + cfg.AuthenticationProtocol = int(models.AuthenticationProtocolEAPTLS) + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) + resultCode := f.verifyMatchingIeee8021xConfig(name) + assert.Equal(t, utils.Success, resultCode) + }) - notEmpty := ieee8021xCfgIsEmpty(notEmptyConfig) - if notEmpty { - t.Errorf("Expected non-empty config to return false, but got true") - } } From e9e5febacd6026d4d62dc6aeeaed07805bb1407a Mon Sep 17 00:00:00 2001 From: Tim Shockley Date: Fri, 18 Aug 2023 12:35:14 -0700 Subject: [PATCH 27/29] fix: logic hole for 8021x blank configs on command line --- config-wifi.yaml | 27 ++++++---------- internal/flags/configure.go | 54 ++++++++++++++++++++++++-------- internal/flags/configure_test.go | 18 +++++++++-- 3 files changed, 66 insertions(+), 33 deletions(-) diff --git a/config-wifi.yaml b/config-wifi.yaml index 75c795d8..b0095ee7 100644 --- a/config-wifi.yaml +++ b/config-wifi.yaml @@ -1,30 +1,23 @@ wifiConfigs: - - profileName: 'wifiWPA2' - ssid: 'ssid' + - profileName: 'exampleWifiWPA2' # friendly name (ex. Profile name) + ssid: 'exampleSSID' priority: 1 - authenticationMethod: 6 + authenticationMethod: 4 encryptionMethod: 4 pskPassphrase: '' ieee8021xProfileName: '' - - profileName: 'wifi8021x' # friendly name (ex. Profile name) + - profileName: 'exampleWifi8021x' # friendly name (ex. Profile name) ssid: 'ssid' priority: 2 authenticationMethod: 7 encryptionMethod: 4 pskPassphrase: '' - ieee8021xProfileName: 'ieee8021xEAP-TLS' + ieee8021xProfileName: 'exampleIeee8021xEAP-TLS' ieee8021xConfigs: - - profileName: 'ieee8021xEAP-TLS' - username: "test" + - profileName: 'exampleIeee8021xEAP-TLS' + username: "exampleUserName" password: "" # 8021x password if authenticationProtocol is PEAPv0/EAP-MSCHAPv2(2) authenticationProtocol: 0 #8021x profile (ex. EAP-TLS(0)) - clientCert: 'test' - caCert: 'test' - privateKey: '' - - profileName: 'ieee8021xPEAPv0' - username: "test" - password: "" # 8021x password if authenticationProtocol is PEAPv0/EAP-MSCHAPv2(2) - authenticationProtocol: 2 #8021x profile (ex. EAP-TLS(0)) - clientCert: 'testClientCert' - caCert: 'testCaCert' - privateKey: 'testPrivateKey' + clientCert: 'testCert' + caCert: 'testCert' + privateKey: 'testKey' diff --git a/internal/flags/configure.go b/internal/flags/configure.go index 206e2ed6..7f6706c1 100644 --- a/internal/flags/configure.go +++ b/internal/flags/configure.go @@ -71,6 +71,10 @@ func (f *Flags) handleConfigureCommand() int { func (f *Flags) handleAddWifiSettings() int { var err error var resultCode int + if len(f.commandLineArgs) == 3 { + f.printConfigurationUsage() + return utils.IncorrectCommandLineParameters + } var wifiSecretConfig config.SecretConfig var configJson string f.flagSetAddWifiSettings.BoolVar(&f.Verbose, "v", false, "Verbose output") @@ -90,7 +94,7 @@ func (f *Flags) handleAddWifiSettings() int { f.flagSetAddWifiSettings.StringVar(&wifiCfg.PskPassphrase, "pskPassphrase", "", "specify psk passphrase") f.flagSetAddWifiSettings.IntVar(&wifiCfg.Priority, "priority", 0, "specify priority") f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.Username, "username", "", "specify username") - f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.Password, "ieee8021xPassword", "", "specify ieee8021x password") + f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.Password, "ieee8021xPassword", "", "8021x password if authenticationProtocol is PEAPv0/EAP-MSCHAPv2(2)") f.flagSetAddWifiSettings.IntVar(&ieee8021xCfg.AuthenticationProtocol, "authenticationProtocol", 0, "specify authentication protocol") f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.ClientCert, "clientCert", "", "specify client certificate") f.flagSetAddWifiSettings.StringVar(&ieee8021xCfg.CACert, "caCert", "", "specify CA certificate") @@ -103,11 +107,14 @@ func (f *Flags) handleAddWifiSettings() int { return utils.IncorrectCommandLineParameters } - // port the profile name as it is understood a 8021x config will 'match' this wificfg if wifiCfg.ProfileName != "" { - wifiCfg.Ieee8021xProfileName = wifiCfg.ProfileName - // don't worry if wifiCfg is not using 8021x, it will be ignored or verified later - ieee8021xCfg.ProfileName = wifiCfg.ProfileName + authMethod := models.AuthenticationMethod(wifiCfg.AuthenticationMethod) + if authMethod == models.AuthenticationMethod_WPA_IEEE8021x || + authMethod == models.AuthenticationMethod_WPA2_IEEE8021x { + // reuse profilename as configuration reference + wifiCfg.Ieee8021xProfileName = wifiCfg.ProfileName + ieee8021xCfg.ProfileName = wifiCfg.ProfileName + } } f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfg) @@ -330,12 +337,6 @@ func (f *Flags) verifyIeee8021xConfig(cfg config.Ieee8021xConfig) int { // not all defined protocols are supported switch authenticationProtocol { case models.AuthenticationProtocolEAPTLS: - fallthrough - case models.AuthenticationProtocolPEAPv1_EAPGTC: - fallthrough - case models.AuthenticationProtocolEAPFAST_GTC: - fallthrough - case models.AuthenticationProtocolEAPFAST_TLS: break case models.AuthenticationProtocolPEAPv0_EAPMSCHAPv2: if cfg.Password == "" { @@ -343,9 +344,36 @@ func (f *Flags) verifyIeee8021xConfig(cfg config.Ieee8021xConfig) int { return utils.MissingOrIncorrectPassword } break + case models.AuthenticationProtocolEAPTTLS_MSCHAPv2: + log.Errorf("Unsupported AuthenticationProtocolEAPTTLS_MSCHAPv2 (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.Ieee8021xConfigurationFailed + case models.AuthenticationProtocolPEAPv1_EAPGTC: + log.Errorf("Unsupported AuthenticationProtocolPEAPv1_EAPGTC (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.Ieee8021xConfigurationFailed + case models.AuthenticationProtocolEAPFAST_MSCHAPv2: + log.Errorf("Unsupported AuthenticationProtocolEAPFAST_MSCHAPv2 (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.Ieee8021xConfigurationFailed + case models.AuthenticationProtocolEAPFAST_GTC: + log.Errorf("Unsupported AuthenticationProtocolEAPFAST_GTC (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.Ieee8021xConfigurationFailed + case models.AuthenticationProtocolEAP_MD5: + log.Errorf("Unsupported AuthenticationProtocolEAP_MD5 (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.Ieee8021xConfigurationFailed + case models.AuthenticationProtocolEAP_PSK: + log.Errorf("Unsupported AuthenticationProtocolEAP_PSK (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.Ieee8021xConfigurationFailed + case models.AuthenticationProtocolEAP_SIM: + log.Errorf("Unsupported AuthenticationProtocolEAP_SIM (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.Ieee8021xConfigurationFailed + case models.AuthenticationProtocolEAP_AKA: + log.Errorf("Unsupported AuthenticationProtocolEAP_AKA (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.Ieee8021xConfigurationFailed + case models.AuthenticationProtocolEAPFAST_TLS: + log.Errorf("Unsupported AuthenticationProtocolEAPFAST_TLS (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.Ieee8021xConfigurationFailed default: - log.Error("invalid AuthenticationProtocol for Ieee8021xConfig: ", cfg.ProfileName) - return utils.MissingOrIncorrectProfile + log.Errorf("Invalid AuthenticationProtocol (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.Ieee8021xConfigurationFailed } return utils.Success diff --git a/internal/flags/configure_test.go b/internal/flags/configure_test.go index 5e0a6d71..b3e1fc60 100644 --- a/internal/flags/configure_test.go +++ b/internal/flags/configure_test.go @@ -162,13 +162,25 @@ func TestHandleAddWifiSettings(t *testing.T) { expectedResult: utils.IncorrectCommandLineParameters, }, {description: "Missing filename", - cmdLine: "rpc configure addwifisettings -password Passw0rd! -config", + cmdLine: "rpc configure addwifisettings -password Passw0rd! -configFile", expectedResult: utils.IncorrectCommandLineParameters, }, {description: "Missing password", - cmdLine: "rpc configure addwifisettings -password Passw0rd! -config", + cmdLine: "rpc configure addwifisettings -password Passw0rd! -configFile", expectedResult: utils.IncorrectCommandLineParameters, }, + {description: "Missing all params", + cmdLine: "rpc configure addwifisettings", + expectedResult: utils.IncorrectCommandLineParameters, + }, + {description: "Unknown param", + cmdLine: "rpc configure addwifisettings -h", + expectedResult: utils.IncorrectCommandLineParameters, + }, + {description: "Basic wifi config command line", + cmdLine: `rpc configure addwifisettings -password Passw0rd! -profileName cliprofname -authenticationMethod 6 -encryptionMethod 4 -ssid "myclissid" -priority 1 -pskPassphrase "mypassword"`, + expectedResult: utils.Success, + }, {description: "Valid with reading from file", cmdLine: "rpc configure addwifisettings -password Passw0rd! -configFile ../../config-wifi.yaml -secretFile ../../secrets-wifi.yaml", expectedResult: utils.Success, @@ -394,7 +406,7 @@ func TestVerifyMatchingIeee8021xConfig(t *testing.T) { cfg.AuthenticationProtocol = int(models.AuthenticationProtocolEAP_AKA) f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) resultCode := f.verifyMatchingIeee8021xConfig(name) - assert.Equal(t, utils.MissingOrIncorrectProfile, resultCode) + assert.Equal(t, utils.Ieee8021xConfigurationFailed, resultCode) }) t.Run("expect MissingOrIncorrectProfile if missing PskPassphrase", func(t *testing.T) { f := Flags{} From 669db5a6925e18fc86aa88f64b4b45866a3ee0aa Mon Sep 17 00:00:00 2001 From: Tim Shockley Date: Mon, 21 Aug 2023 13:29:26 -0700 Subject: [PATCH 28/29] feat: additional fixes and tests --- config-wifi.yaml | 2 +- internal/config/local.go | 6 +- internal/flags/activate.go | 2 +- internal/flags/configure.go | 157 +++++++++++++++--------- internal/flags/configure_test.go | 199 ++++++++++++++++++++----------- internal/flags/flags.go | 5 +- pkg/utils/constants.go | 4 +- 7 files changed, 239 insertions(+), 136 deletions(-) diff --git a/config-wifi.yaml b/config-wifi.yaml index b0095ee7..217f775c 100644 --- a/config-wifi.yaml +++ b/config-wifi.yaml @@ -4,7 +4,7 @@ wifiConfigs: priority: 1 authenticationMethod: 4 encryptionMethod: 4 - pskPassphrase: '' + pskPassphrase: 'example123!@#' ieee8021xProfileName: '' - profileName: 'exampleWifi8021x' # friendly name (ex. Profile name) ssid: 'ssid' diff --git a/internal/config/local.go b/internal/config/local.go index 4f04bc9f..c187b7cd 100644 --- a/internal/config/local.go +++ b/internal/config/local.go @@ -2,8 +2,7 @@ package config type ( Config struct { - Password string - FilePath string + Password string `yaml:"password"` WifiConfigs `yaml:"wifiConfigs"` Ieee8021xConfigs `yaml:"ieee8021xConfigs"` ACMSettings `yaml:"acmactivate"` @@ -19,8 +18,7 @@ type ( Ieee8021xProfileName string `yaml:"ieee8021xProfileName"` } SecretConfig struct { - FilePath string - Secrets []Secret `yaml:"secrets"` + Secrets []Secret `yaml:"secrets"` } Secret struct { ProfileName string `yaml:"profileName"` diff --git a/internal/flags/activate.go b/internal/flags/activate.go index 1e81eb95..beac2ed3 100644 --- a/internal/flags/activate.go +++ b/internal/flags/activate.go @@ -21,7 +21,7 @@ func (f *Flags) handleActivateCommand() int { return nil }) // for local activation in ACM mode need a few more items - f.amtActivateCommand.StringVar(&f.LocalConfig.FilePath, "configFile", "", "specify a config file ") + f.amtActivateCommand.StringVar(&f.configContent, "configFile", "", "specify a config file ") f.amtActivateCommand.StringVar(&f.LocalConfig.ACMSettings.AMTPassword, "amtPassword", "", "amt password") f.amtActivateCommand.StringVar(&f.LocalConfig.ACMSettings.ProvisioningCert, "provisioningCert", "", "provisioning certificate") f.amtActivateCommand.StringVar(&f.LocalConfig.ACMSettings.ProvisioningCertPwd, "provisioningCertPwd", "", "provisioning certificate password") diff --git a/internal/flags/configure.go b/internal/flags/configure.go index 7f6706c1..8835e28e 100644 --- a/internal/flags/configure.go +++ b/internal/flags/configure.go @@ -71,6 +71,7 @@ func (f *Flags) handleConfigureCommand() int { func (f *Flags) handleAddWifiSettings() int { var err error var resultCode int + var secretsFilePath string if len(f.commandLineArgs) == 3 { f.printConfigurationUsage() return utils.IncorrectCommandLineParameters @@ -81,9 +82,9 @@ func (f *Flags) handleAddWifiSettings() int { f.flagSetAddWifiSettings.StringVar(&f.LogLevel, "l", "info", "Log level (panic,fatal,error,warn,info,debug,trace)") f.flagSetAddWifiSettings.BoolVar(&f.JsonOutput, "json", false, "JSON output") f.flagSetAddWifiSettings.StringVar(&f.Password, "password", f.lookupEnvOrString("AMT_PASSWORD", ""), "AMT password") - f.flagSetAddWifiSettings.StringVar(&f.LocalConfig.FilePath, "configFile", "", "specify a config file ") + f.flagSetAddWifiSettings.StringVar(&f.configContent, "configFile", "", "specify a config file ") f.flagSetAddWifiSettings.StringVar(&configJson, "configJson", "", "configuration as a JSON string") - f.flagSetAddWifiSettings.StringVar(&wifiSecretConfig.FilePath, "secretFile", "", "specify a secret file ") + f.flagSetAddWifiSettings.StringVar(&secretsFilePath, "secretFile", "", "specify a secret file ") // Params for entering a single wifi config from command line wifiCfg := config.WifiConfig{} ieee8021xCfg := config.Ieee8021xConfig{} @@ -131,8 +132,13 @@ func (f *Flags) handleAddWifiSettings() int { } } - if wifiSecretConfig.FilePath != "" { - err = cleanenv.ReadConfig(wifiSecretConfig.FilePath, &wifiSecretConfig) + if len(f.LocalConfig.WifiConfigs) == 0 { + log.Error("missing wifi configuration") + return utils.MissingOrInvalidConfiguration + } + + if secretsFilePath != "" { + err = cleanenv.ReadConfig(secretsFilePath, &wifiSecretConfig) if err != nil { log.Error("error reading secrets file: ", err) return utils.FailedReadingConfiguration @@ -144,6 +150,10 @@ func (f *Flags) handleAddWifiSettings() int { if resultCode != utils.Success { return resultCode } + xmlBytes, _ := json.Marshal(f.LocalConfig) + xmlStr := string(xmlBytes) + fmt.Println(xmlStr) + // prompt for missing secrets resultCode = f.promptForSecrets() if resultCode != utils.Success { @@ -163,7 +173,7 @@ func (f *Flags) mergeWifiSecrets(wifiSecretConfig config.SecretConfig) int { continue } if secret.PskPassphrase != "" { - for i, _ := range f.LocalConfig.WifiConfigs { + for i := range f.LocalConfig.WifiConfigs { item := &f.LocalConfig.WifiConfigs[i] if item.ProfileName == secret.ProfileName { item.PskPassphrase = secret.PskPassphrase @@ -171,7 +181,7 @@ func (f *Flags) mergeWifiSecrets(wifiSecretConfig config.SecretConfig) int { } } if secret.Password != "" { - for i, _ := range f.LocalConfig.Ieee8021xConfigs { + for i := range f.LocalConfig.Ieee8021xConfigs { item := &f.LocalConfig.Ieee8021xConfigs[i] if item.ProfileName == secret.ProfileName { item.Password = secret.Password @@ -179,7 +189,7 @@ func (f *Flags) mergeWifiSecrets(wifiSecretConfig config.SecretConfig) int { } } if secret.PrivateKey != "" { - for i, _ := range f.LocalConfig.Ieee8021xConfigs { + for i := range f.LocalConfig.Ieee8021xConfigs { item := &f.LocalConfig.Ieee8021xConfigs[i] if item.ProfileName == secret.ProfileName { item.PrivateKey = secret.PrivateKey @@ -191,13 +201,13 @@ func (f *Flags) mergeWifiSecrets(wifiSecretConfig config.SecretConfig) int { } func (f *Flags) promptForSecrets() int { - for i, _ := range f.LocalConfig.WifiConfigs { + for i := range f.LocalConfig.WifiConfigs { item := &f.LocalConfig.WifiConfigs[i] if item.ProfileName == "" { continue } authMethod := models.AuthenticationMethod(item.AuthenticationMethod) - if authMethod == models.AuthenticationMethod_WPA2_PSK && + if (authMethod == models.AuthenticationMethod_WPA_PSK || authMethod == models.AuthenticationMethod_WPA2_PSK) && item.PskPassphrase == "" { resultCode := f.PromptUserInput("Please enter PskPassphrase for "+item.ProfileName+": ", &item.PskPassphrase) if resultCode != utils.Success { @@ -205,7 +215,7 @@ func (f *Flags) promptForSecrets() int { } } } - for i, _ := range f.LocalConfig.Ieee8021xConfigs { + for i := range f.LocalConfig.Ieee8021xConfigs { item := &f.LocalConfig.Ieee8021xConfigs[i] if item.ProfileName == "" { continue @@ -233,44 +243,69 @@ func (f *Flags) verifyWifiConfigurations() int { //Check profile name is not empty if cfg.ProfileName == "" { log.Error("missing profile name") - return utils.MissingOrIncorrectProfile + return utils.MissingOrInvalidConfiguration } //Check ssid is not empty if cfg.SSID == "" { log.Error("missing ssid for config: ", cfg.ProfileName) - return utils.MissingOrIncorrectProfile + return utils.MissingOrInvalidConfiguration } //Check priority is not empty if cfg.Priority <= 0 { log.Error("invalid priority for config: ", cfg.ProfileName) - return utils.MissingOrIncorrectProfile + return utils.MissingOrInvalidConfiguration } authenticationMethod := models.AuthenticationMethod(cfg.AuthenticationMethod) switch authenticationMethod { case models.AuthenticationMethod_WPA_PSK: - break + fallthrough case models.AuthenticationMethod_WPA2_PSK: if cfg.PskPassphrase == "" { log.Error("missing PskPassphrase for config: ", cfg.ProfileName) - return utils.MissingOrIncorrectProfile + return utils.MissingOrInvalidConfiguration } break case models.AuthenticationMethod_WPA_IEEE8021x: fallthrough case models.AuthenticationMethod_WPA2_IEEE8021x: + if cfg.ProfileName == "" { + log.Error("missing ieee8021x profile name") + return utils.MissingOrInvalidConfiguration + } if cfg.PskPassphrase != "" { - log.Error("wifi configuration contains passphrase: ", cfg.ProfileName) - return utils.MissingOrIncorrectProfile + log.Errorf("wifi configuration for 8021x contains passphrase: %s", cfg.ProfileName) + return utils.MissingOrInvalidConfiguration } resultCode := f.verifyMatchingIeee8021xConfig(cfg.Ieee8021xProfileName) if resultCode != utils.Success { return resultCode } break + case models.AuthenticationMethod_Other: + log.Errorf("unsupported AuthenticationMethod_Other (%d) for config: %s", cfg.AuthenticationMethod, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration + case models.AuthenticationMethod_OpenSystem: + log.Errorf("unsupported AuthenticationMethod_OpenSystem (%d) for config: %s", cfg.AuthenticationMethod, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration + case models.AuthenticationMethod_SharedKey: + log.Errorf("unsupported AuthenticationMethod_SharedKey (%d) for config: %s", cfg.AuthenticationMethod, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration + case models.AuthenticationMethod_DMTFReserved: + log.Errorf("unsupported AuthenticationMethod_DMTFReserved (%d) for config: %s", cfg.AuthenticationMethod, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration + case models.AuthenticationMethod_WPA3_SAE: + log.Errorf("unsupported AuthenticationMethod_WPA3_SAE (%d) for config: %s", cfg.AuthenticationMethod, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration + case models.AuthenticationMethod_WPA3_OWE: + log.Errorf("unsupported AuthenticationMethod_WPA3_OWE (%d) for config: %s", cfg.AuthenticationMethod, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration + case models.AuthenticationMethod_VendorReserved: + log.Errorf("unsupported AuthenticationMethod_VendorReserved (%d) for config: %s", cfg.AuthenticationMethod, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration default: - log.Error("invalid AuthenticationMethod for config: ", cfg.ProfileName) - return utils.MissingOrIncorrectProfile + log.Errorf("invalid AuthenticationMethod_VendorReserved (%d) for config: %s", cfg.AuthenticationMethod, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration } encryptionMethod := models.EncryptionMethod(cfg.EncryptionMethod) @@ -280,19 +315,27 @@ func (f *Flags) verifyWifiConfigurations() int { fallthrough case models.EncryptionMethod_CCMP: break + case models.EncryptionMethod_Other: + log.Errorf("unsupported EncryptionMethod_Other (%d) for config: %s", cfg.EncryptionMethod, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration + case models.EncryptionMethod_WEP: + log.Errorf("unsupported EncryptionMethod_WEP (%d) for config: %s", cfg.EncryptionMethod, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration + case models.EncryptionMethod_None: + log.Errorf("unsupported EncryptionMethod_None (%d) for config: %s", cfg.EncryptionMethod, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration + case models.EncryptionMethod_DMTFReserved: + log.Errorf("unsupported EncryptionMethod_DMTFReserved (%d) for config: %s", cfg.EncryptionMethod, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration default: - log.Error("invalid EncryptionMethod for config: ", cfg.ProfileName) - return utils.MissingOrIncorrectProfile + log.Errorf("invalid EncryptionMethod (%d) for config: %s", cfg.EncryptionMethod, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration } } return utils.Success } func (f *Flags) verifyMatchingIeee8021xConfig(profileName string) int { - if profileName == "" { - log.Error("empty ieee802xCfg profile name") - return utils.MissingOrIncorrectProfile - } foundOne := false for _, ieee802xCfg := range f.LocalConfig.Ieee8021xConfigs { if profileName != ieee802xCfg.ProfileName { @@ -300,7 +343,7 @@ func (f *Flags) verifyMatchingIeee8021xConfig(profileName string) int { } if foundOne { log.Error("duplicate IEEE802x Profile names: ", ieee802xCfg.ProfileName) - return utils.MissingOrIncorrectProfile + return utils.MissingOrInvalidConfiguration } foundOne = true resultCode := f.verifyIeee8021xConfig(ieee802xCfg) @@ -310,7 +353,7 @@ func (f *Flags) verifyMatchingIeee8021xConfig(profileName string) int { } if !foundOne { log.Error("missing IEEE802x Profile: ", profileName) - return utils.MissingOrIncorrectProfile + return utils.MissingOrInvalidConfiguration } return utils.Success } @@ -318,20 +361,20 @@ func (f *Flags) verifyMatchingIeee8021xConfig(profileName string) int { func (f *Flags) verifyIeee8021xConfig(cfg config.Ieee8021xConfig) int { if cfg.Username == "" { - log.Error("missing Username for Ieee8021xConfig: ", cfg.ProfileName) - return utils.MissingOrIncorrectProfile + log.Error("missing username for config: ", cfg.ProfileName) + return utils.MissingOrInvalidConfiguration } if cfg.ClientCert == "" { - log.Error("missing ClientCert for Ieee8021xConfig: ", cfg.ProfileName) - return utils.MissingOrIncorrectProfile + log.Error("missing clientCert for config: ", cfg.ProfileName) + return utils.MissingOrInvalidConfiguration } if cfg.CACert == "" { - log.Error("missing CACert for Ieee8021xConfig: ", cfg.ProfileName) - return utils.MissingOrIncorrectProfile + log.Error("missing caCert for config: ", cfg.ProfileName) + return utils.MissingOrInvalidConfiguration } if cfg.PrivateKey == "" { - log.Error("missing PrivateKey for Ieee8021xConfig: ", cfg.ProfileName) - return utils.MissingOrIncorrectProfile + log.Error("missing privateKey for config: ", cfg.ProfileName) + return utils.MissingOrInvalidConfiguration } authenticationProtocol := models.AuthenticationProtocol(cfg.AuthenticationProtocol) // not all defined protocols are supported @@ -340,40 +383,40 @@ func (f *Flags) verifyIeee8021xConfig(cfg config.Ieee8021xConfig) int { break case models.AuthenticationProtocolPEAPv0_EAPMSCHAPv2: if cfg.Password == "" { - log.Error("missing Password for for PEAPv0_EAPMSCHAPv2 Ieee8021xConfig: ", cfg.ProfileName) - return utils.MissingOrIncorrectPassword + log.Error("missing password for for PEAPv0_EAPMSCHAPv2 config: ", cfg.ProfileName) + return utils.MissingOrInvalidConfiguration } break case models.AuthenticationProtocolEAPTTLS_MSCHAPv2: - log.Errorf("Unsupported AuthenticationProtocolEAPTTLS_MSCHAPv2 (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) - return utils.Ieee8021xConfigurationFailed + log.Errorf("unsupported AuthenticationProtocolEAPTTLS_MSCHAPv2 (%d) for config: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration case models.AuthenticationProtocolPEAPv1_EAPGTC: - log.Errorf("Unsupported AuthenticationProtocolPEAPv1_EAPGTC (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) - return utils.Ieee8021xConfigurationFailed + log.Errorf("unsupported AuthenticationProtocolPEAPv1_EAPGTC (%d) for config: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration case models.AuthenticationProtocolEAPFAST_MSCHAPv2: - log.Errorf("Unsupported AuthenticationProtocolEAPFAST_MSCHAPv2 (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) - return utils.Ieee8021xConfigurationFailed + log.Errorf("unsupported AuthenticationProtocolEAPFAST_MSCHAPv2 (%d) for config: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration case models.AuthenticationProtocolEAPFAST_GTC: - log.Errorf("Unsupported AuthenticationProtocolEAPFAST_GTC (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) - return utils.Ieee8021xConfigurationFailed + log.Errorf("unsupported AuthenticationProtocolEAPFAST_GTC (%d) for config: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration case models.AuthenticationProtocolEAP_MD5: - log.Errorf("Unsupported AuthenticationProtocolEAP_MD5 (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) - return utils.Ieee8021xConfigurationFailed + log.Errorf("unsupported AuthenticationProtocolEAP_MD5 (%d) for config: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration case models.AuthenticationProtocolEAP_PSK: - log.Errorf("Unsupported AuthenticationProtocolEAP_PSK (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) - return utils.Ieee8021xConfigurationFailed + log.Errorf("unsupported AuthenticationProtocolEAP_PSK (%d) for config: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration case models.AuthenticationProtocolEAP_SIM: - log.Errorf("Unsupported AuthenticationProtocolEAP_SIM (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) - return utils.Ieee8021xConfigurationFailed + log.Errorf("unsupported AuthenticationProtocolEAP_SIM (%d) for config: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration case models.AuthenticationProtocolEAP_AKA: - log.Errorf("Unsupported AuthenticationProtocolEAP_AKA (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) - return utils.Ieee8021xConfigurationFailed + log.Errorf("unsupported AuthenticationProtocolEAP_AKA (%d) for config: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration case models.AuthenticationProtocolEAPFAST_TLS: - log.Errorf("Unsupported AuthenticationProtocolEAPFAST_TLS (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) - return utils.Ieee8021xConfigurationFailed + log.Errorf("unsupported AuthenticationProtocolEAPFAST_TLS (%d) for config: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration default: - log.Errorf("Invalid AuthenticationProtocol (%d) for Ieee8021xConfig: %s", cfg.AuthenticationProtocol, cfg.ProfileName) - return utils.Ieee8021xConfigurationFailed + log.Errorf("invalid AuthenticationProtocol (%d) for config: %s", cfg.AuthenticationProtocol, cfg.ProfileName) + return utils.MissingOrInvalidConfiguration } return utils.Success diff --git a/internal/flags/configure_test.go b/internal/flags/configure_test.go index b3e1fc60..f3a76bfc 100644 --- a/internal/flags/configure_test.go +++ b/internal/flags/configure_test.go @@ -1,6 +1,7 @@ package flags import ( + "fmt" "github.com/open-amt-cloud-toolkit/go-wsman-messages/pkg/cim/models" "rpc/internal/config" "rpc/pkg/utils" @@ -60,7 +61,7 @@ func TestPromptForSecrets(t *testing.T) { } func TestCmdLine(t *testing.T) { - jsonCfgStr := `{"WifiConfigs":[{"ProfileName":"wifiWPA", "SSID":"ssid", "Priority":1, "AuthenticationMethod":4, "EncryptionMethod":4}]}` + jsonCfgStr := `{"WifiConfigs":[{"ProfileName":"wifiWPA", "SSID":"ssid", "PskPassphrase": "testPSK", "Priority":1, "AuthenticationMethod":4, "EncryptionMethod":4}]}` t.Run("expect IncorrectCommandLineParameters with no subcommand", func(t *testing.T) { f := NewFlags([]string{`rpc`, `configure`}) @@ -131,6 +132,7 @@ func TestConfigJson(t *testing.T) { gotResult := flags.ParseFlags() assert.Equal(t, utils.Success, gotResult) } + func TestHandleAddWifiSettings(t *testing.T) { cases := []struct { description string @@ -202,6 +204,7 @@ var wifiCfgWPA = config.WifiConfig{ Priority: 1, AuthenticationMethod: int(models.AuthenticationMethod_WPA_PSK), EncryptionMethod: int(models.EncryptionMethod_TKIP), + PskPassphrase: "wifiWPAPassPhrase", } var wifiCfgWPA2 = config.WifiConfig{ @@ -210,7 +213,7 @@ var wifiCfgWPA2 = config.WifiConfig{ Priority: 2, AuthenticationMethod: int(models.AuthenticationMethod_WPA2_PSK), EncryptionMethod: int(models.EncryptionMethod_CCMP), - PskPassphrase: "wifiWPAPassPhrase", + PskPassphrase: "wifiWPA2PassPhrase", } var wifiCfgWPA8021xEAPTLS = config.WifiConfig{ @@ -263,94 +266,94 @@ func runVerifyWifiConfiguration(t *testing.T, expectedResult int, wifiCfgs confi assert.Equal(t, expectedResult, gotResult) } -func TestVerifyWifiConfigurationFile(t *testing.T) { +func TestVerifyWifiConfiguration(t *testing.T) { t.Run("expect Success for correct configs", func(t *testing.T) { runVerifyWifiConfiguration(t, utils.Success, config.WifiConfigs{wifiCfgWPA, wifiCfgWPA2, wifiCfgWPA8021xEAPTLS, wifiCfgWPA28021xPEAPv0_EAPMSCHAPv2}, config.Ieee8021xConfigs{ieee8021xCfgEAPTLS, ieee8021xCfgPEAPv0_EAPMSCHAPv2}) }) - t.Run("expect MissingOrIncorrectProfile when missing ProfileName", func(t *testing.T) { + t.Run("expect MissingOrInvalidConfiguration when missing ProfileName", func(t *testing.T) { orig := wifiCfgWPA.ProfileName wifiCfgWPA.ProfileName = "" - runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + runVerifyWifiConfiguration(t, utils.MissingOrInvalidConfiguration, config.WifiConfigs{wifiCfgWPA}, config.Ieee8021xConfigs{}) wifiCfgWPA.ProfileName = orig }) - t.Run("expect MissingOrIncorrectProfile when missing SSID", func(t *testing.T) { + t.Run("expect MissingOrInvalidConfiguration when missing SSID", func(t *testing.T) { orig := wifiCfgWPA.SSID wifiCfgWPA.SSID = "" - runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + runVerifyWifiConfiguration(t, utils.MissingOrInvalidConfiguration, config.WifiConfigs{wifiCfgWPA}, config.Ieee8021xConfigs{}) wifiCfgWPA.SSID = orig }) - t.Run("expect MissingOrIncorrectProfile with invalid Priority", func(t *testing.T) { + t.Run("expect MissingOrInvalidConfiguration with invalid Priority", func(t *testing.T) { orig := wifiCfgWPA.Priority wifiCfgWPA.Priority = 0 - runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + runVerifyWifiConfiguration(t, utils.MissingOrInvalidConfiguration, config.WifiConfigs{wifiCfgWPA}, config.Ieee8021xConfigs{}) wifiCfgWPA.Priority = orig }) - t.Run("expect MissingOrIncorrectProfile with invalid AuthenticationMethod", func(t *testing.T) { + t.Run("expect MissingOrInvalidConfiguration with invalid AuthenticationMethod", func(t *testing.T) { orig := wifiCfgWPA.AuthenticationMethod wifiCfgWPA.AuthenticationMethod = int(models.AuthenticationMethod_DMTFReserved) - runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + runVerifyWifiConfiguration(t, utils.MissingOrInvalidConfiguration, config.WifiConfigs{wifiCfgWPA}, config.Ieee8021xConfigs{}) wifiCfgWPA.AuthenticationMethod = orig }) - t.Run("expect MissingOrIncorrectProfile with invalid EncryptionMethod", func(t *testing.T) { + t.Run("expect MissingOrInvalidConfiguration with invalid EncryptionMethod", func(t *testing.T) { orig := wifiCfgWPA.EncryptionMethod wifiCfgWPA.EncryptionMethod = int(models.EncryptionMethod_DMTFReserved) - runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + runVerifyWifiConfiguration(t, utils.MissingOrInvalidConfiguration, config.WifiConfigs{wifiCfgWPA}, config.Ieee8021xConfigs{}) wifiCfgWPA.EncryptionMethod = orig }) - t.Run("expect MissingOrIncorrectProfile with missing passphrase", func(t *testing.T) { + t.Run("expect MissingOrInvalidConfiguration with missing passphrase", func(t *testing.T) { orig := wifiCfgWPA2.PskPassphrase wifiCfgWPA2.PskPassphrase = "" - runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + runVerifyWifiConfiguration(t, utils.MissingOrInvalidConfiguration, config.WifiConfigs{wifiCfgWPA2}, config.Ieee8021xConfigs{}) wifiCfgWPA2.PskPassphrase = orig }) - t.Run("expect MissingOrIncorrectProfile with missing ieee8021x ProfileName", func(t *testing.T) { + t.Run("expect MissingOrInvalidConfiguration with missing ieee8021x ProfileName", func(t *testing.T) { orig8021xName := ieee8021xCfgEAPTLS.ProfileName ieee8021xCfgEAPTLS.ProfileName = "" - runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + runVerifyWifiConfiguration(t, utils.MissingOrInvalidConfiguration, config.WifiConfigs{wifiCfgWPA8021xEAPTLS}, config.Ieee8021xConfigs{ieee8021xCfgEAPTLS}) ieee8021xCfgEAPTLS.ProfileName = orig8021xName }) - t.Run("expect MissingOrIncorrectProfile with PskPassphrase is present for ieee8021x profile", func(t *testing.T) { + t.Run("expect MissingOrInvalidConfiguration with PskPassphrase is present for ieee8021x profile", func(t *testing.T) { wifiCfgWPA8021xEAPTLS.PskPassphrase = "shouldn't be here" - runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + runVerifyWifiConfiguration(t, utils.MissingOrInvalidConfiguration, config.WifiConfigs{wifiCfgWPA8021xEAPTLS}, config.Ieee8021xConfigs{ieee8021xCfgEAPTLS}) wifiCfgWPA8021xEAPTLS.PskPassphrase = "" }) - t.Run("expect MissingOrIncorrectProfile with PskPassphrase is present for ieee8021x profile", func(t *testing.T) { + t.Run("expect MissingOrInvalidConfiguration with PskPassphrase is present for ieee8021x profile", func(t *testing.T) { wifiCfgWPA28021xPEAPv0_EAPMSCHAPv2.PskPassphrase = "shouldn't be here" - runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + runVerifyWifiConfiguration(t, utils.MissingOrInvalidConfiguration, config.WifiConfigs{wifiCfgWPA28021xPEAPv0_EAPMSCHAPv2}, config.Ieee8021xConfigs{ieee8021xCfgPEAPv0_EAPMSCHAPv2}) wifiCfgWPA28021xPEAPv0_EAPMSCHAPv2.PskPassphrase = "" }) - t.Run("expect MissingOrIncorrectProfile with duplicate ieee8021x ProfileName", func(t *testing.T) { + t.Run("expect MissingOrInvalidConfiguration with duplicate ieee8021x ProfileName", func(t *testing.T) { orig8021xName := ieee8021xCfgEAPTLS.ProfileName ieee8021xCfgEAPTLS.ProfileName = ieee8021xCfgPEAPv0_EAPMSCHAPv2.ProfileName wifiCfgWPA8021xEAPTLS.Ieee8021xProfileName = ieee8021xCfgPEAPv0_EAPMSCHAPv2.ProfileName // authMethod 5 - runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + runVerifyWifiConfiguration(t, utils.MissingOrInvalidConfiguration, config.WifiConfigs{wifiCfgWPA8021xEAPTLS}, config.Ieee8021xConfigs{ieee8021xCfgEAPTLS, ieee8021xCfgPEAPv0_EAPMSCHAPv2}) // authMethod 7 - runVerifyWifiConfiguration(t, utils.MissingOrIncorrectProfile, + runVerifyWifiConfiguration(t, utils.MissingOrInvalidConfiguration, config.WifiConfigs{wifiCfgWPA28021xPEAPv0_EAPMSCHAPv2}, config.Ieee8021xConfigs{ieee8021xCfgEAPTLS, ieee8021xCfgPEAPv0_EAPMSCHAPv2}) ieee8021xCfgEAPTLS.ProfileName = orig8021xName @@ -360,67 +363,125 @@ func TestVerifyWifiConfigurationFile(t *testing.T) { func TestVerifyMatchingIeee8021xConfig(t *testing.T) { name := "profileName" - cfg := config.Ieee8021xConfig{} - t.Run("expect MissingOrIncorrectProfile with missing name", func(t *testing.T) { - f := Flags{} - resultCode := f.verifyMatchingIeee8021xConfig("") - assert.Equal(t, utils.MissingOrIncorrectProfile, resultCode) + f := Flags{} + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, config.Ieee8021xConfig{}) + t.Run("expect MissingOrInvalidConfiguration with missing configuration", func(t *testing.T) { + f2 := Flags{} + resultCode := f2.verifyMatchingIeee8021xConfig("") + assert.Equal(t, utils.MissingOrInvalidConfiguration, resultCode) }) - t.Run("expect MissingOrIncorrectProfile if no matching profile", func(t *testing.T) { - f := Flags{} - f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) + t.Run("expect MissingOrInvalidConfiguration if no matching profile", func(t *testing.T) { resultCode := f.verifyMatchingIeee8021xConfig(name) - assert.Equal(t, utils.MissingOrIncorrectProfile, resultCode) + assert.Equal(t, utils.MissingOrInvalidConfiguration, resultCode) }) - t.Run("expect MissingOrIncorrectProfile if missing username", func(t *testing.T) { - f := Flags{} - cfg.ProfileName = name - f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) + t.Run("expect MissingOrInvalidConfiguration if missing username", func(t *testing.T) { + f.LocalConfig.Ieee8021xConfigs[0].ProfileName = name resultCode := f.verifyMatchingIeee8021xConfig(name) - assert.Equal(t, utils.MissingOrIncorrectProfile, resultCode) + assert.Equal(t, utils.MissingOrInvalidConfiguration, resultCode) }) - t.Run("expect MissingOrIncorrectProfile if missing ClientCert", func(t *testing.T) { - f := Flags{} - cfg.Username = "UserName" - f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) + t.Run("expect MissingOrInvalidConfiguration if missing ClientCert", func(t *testing.T) { + f.LocalConfig.Ieee8021xConfigs[0].Username = "UserName" resultCode := f.verifyMatchingIeee8021xConfig(name) - assert.Equal(t, utils.MissingOrIncorrectProfile, resultCode) + assert.Equal(t, utils.MissingOrInvalidConfiguration, resultCode) }) - t.Run("expect MissingOrIncorrectProfile if missing CACert", func(t *testing.T) { - f := Flags{} - cfg.ClientCert = "AABBCCDDEEFF" - f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) + t.Run("expect MissingOrInvalidConfiguration if missing CACert", func(t *testing.T) { + f.LocalConfig.Ieee8021xConfigs[0].ClientCert = "AABBCCDDEEFF" resultCode := f.verifyMatchingIeee8021xConfig(name) - assert.Equal(t, utils.MissingOrIncorrectProfile, resultCode) + assert.Equal(t, utils.MissingOrInvalidConfiguration, resultCode) }) - t.Run("expect MissingOrIncorrectProfile if missing PrivateKey", func(t *testing.T) { - f := Flags{} - cfg.CACert = "AABBCCDDEEFF" - f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) + t.Run("expect MissingOrInvalidConfiguration if missing PrivateKey", func(t *testing.T) { + f.LocalConfig.Ieee8021xConfigs[0].CACert = "AABBCCDDEEFF" resultCode := f.verifyMatchingIeee8021xConfig(name) - assert.Equal(t, utils.MissingOrIncorrectProfile, resultCode) + assert.Equal(t, utils.MissingOrInvalidConfiguration, resultCode) }) - t.Run("expect MissingOrIncorrectProfile if unsupported/invalid AuthenticationProtocol", func(t *testing.T) { - f := Flags{} - cfg.PrivateKey = "AABBCCDDEEFF" - cfg.AuthenticationProtocol = int(models.AuthenticationProtocolEAP_AKA) - f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) + t.Run("expect MissingOrInvalidConfiguration if missing PskPassphrase", func(t *testing.T) { + f.LocalConfig.Ieee8021xConfigs[0].PrivateKey = "AABBCCDDEEFF" + f.LocalConfig.Ieee8021xConfigs[0].AuthenticationProtocol = int(models.AuthenticationProtocolPEAPv0_EAPMSCHAPv2) resultCode := f.verifyMatchingIeee8021xConfig(name) - assert.Equal(t, utils.Ieee8021xConfigurationFailed, resultCode) + assert.Equal(t, utils.MissingOrInvalidConfiguration, resultCode) }) - t.Run("expect MissingOrIncorrectProfile if missing PskPassphrase", func(t *testing.T) { - f := Flags{} - cfg.AuthenticationProtocol = int(models.AuthenticationProtocolPEAPv0_EAPMSCHAPv2) - f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) + t.Run("expect Success", func(t *testing.T) { + f.LocalConfig.Ieee8021xConfigs[0].AuthenticationProtocol = int(models.AuthenticationProtocolEAPTLS) resultCode := f.verifyMatchingIeee8021xConfig(name) - assert.Equal(t, utils.MissingOrIncorrectPassword, resultCode) + assert.Equal(t, utils.Success, resultCode) }) - t.Run("expect MissingOrIncorrectProfile if missing PskPassphrase", func(t *testing.T) { - f := Flags{} - cfg.AuthenticationProtocol = int(models.AuthenticationProtocolEAPTLS) - f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, cfg) + t.Run("expect MissingOrInvalidConfiguration for unsupported AuthenticationProtocolEAPTTLS_MSCHAPv2", func(t *testing.T) { + f.LocalConfig.Ieee8021xConfigs[0].AuthenticationProtocol = int(models.AuthenticationProtocolEAPTTLS_MSCHAPv2) resultCode := f.verifyMatchingIeee8021xConfig(name) - assert.Equal(t, utils.Success, resultCode) + assert.Equal(t, utils.MissingOrInvalidConfiguration, resultCode) }) +} + +func TestInvalidAuthenticationMethods(t *testing.T) { + f := Flags{} + f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfgWPA) + cases := []struct { + method models.AuthenticationMethod + }{ + {method: models.AuthenticationMethod_Other}, + {method: models.AuthenticationMethod_OpenSystem}, + {method: models.AuthenticationMethod_SharedKey}, + {method: models.AuthenticationMethod_DMTFReserved}, + {method: models.AuthenticationMethod_WPA3_SAE}, + {method: models.AuthenticationMethod_WPA3_OWE}, + {method: models.AuthenticationMethod_VendorReserved}, + {method: 599}, + } + for _, tc := range cases { + t.Run(fmt.Sprintf("expect MissingOrInvalidConfiguration for AuthenticationProtocol %d", tc.method), + func(t *testing.T) { + f.LocalConfig.WifiConfigs[0].AuthenticationMethod = int(tc.method) + resultCode := f.verifyWifiConfigurations() + assert.Equal(t, utils.MissingOrInvalidConfiguration, resultCode) + }) + } +} +func TestInvalidEncryptionMethods(t *testing.T) { + f := Flags{} + f.LocalConfig.WifiConfigs = append(f.LocalConfig.WifiConfigs, wifiCfgWPA) + cases := []struct { + method models.EncryptionMethod + }{ + {method: models.EncryptionMethod_Other}, + {method: models.EncryptionMethod_WEP}, + {method: models.EncryptionMethod_None}, + {method: models.EncryptionMethod_DMTFReserved}, + {method: 599}, + } + for _, tc := range cases { + t.Run(fmt.Sprintf("expect MissingOrInvalidConfiguration for AuthenticationProtocol %d", tc.method), + func(t *testing.T) { + f.LocalConfig.WifiConfigs[0].EncryptionMethod = int(tc.method) + resultCode := f.verifyWifiConfigurations() + assert.Equal(t, utils.MissingOrInvalidConfiguration, resultCode) + }) + } +} + +func TestInvalidAuthenticationProtocols(t *testing.T) { + f := Flags{} + f.LocalConfig.Ieee8021xConfigs = append(f.LocalConfig.Ieee8021xConfigs, ieee8021xCfgEAPTLS) + cases := []struct { + protocol models.AuthenticationProtocol + }{ + {protocol: models.AuthenticationProtocolEAPTTLS_MSCHAPv2}, + {protocol: models.AuthenticationProtocolPEAPv1_EAPGTC}, + {protocol: models.AuthenticationProtocolEAPFAST_MSCHAPv2}, + {protocol: models.AuthenticationProtocolEAPFAST_GTC}, + {protocol: models.AuthenticationProtocolEAP_MD5}, + {protocol: models.AuthenticationProtocolEAP_PSK}, + {protocol: models.AuthenticationProtocolEAP_SIM}, + {protocol: models.AuthenticationProtocolEAP_AKA}, + {protocol: models.AuthenticationProtocolEAPFAST_TLS}, + {protocol: 599}, + } + for _, tc := range cases { + t.Run(fmt.Sprintf("expect MissingOrInvalidConfiguration for AuthenticationProtocol %d", tc.protocol), + func(t *testing.T) { + f.LocalConfig.Ieee8021xConfigs[0].AuthenticationProtocol = int(tc.protocol) + resultCode := f.verifyIeee8021xConfig(f.LocalConfig.Ieee8021xConfigs[0]) + assert.Equal(t, utils.MissingOrInvalidConfiguration, resultCode) + }) + } } diff --git a/internal/flags/flags.go b/internal/flags/flags.go index e7b67f71..dcf47a78 100644 --- a/internal/flags/flags.go +++ b/internal/flags/flags.go @@ -65,6 +65,7 @@ type Flags struct { TenantID string UseCCM bool UseACM bool + configContent string LocalConfig config.Config amtInfoCommand *flag.FlagSet amtActivateCommand *flag.FlagSet @@ -226,8 +227,8 @@ func (f *Flags) ReadPasswordFromUser() (bool, int) { } func (f *Flags) handleLocalConfig() int { - if f.LocalConfig.FilePath != "" { - err := cleanenv.ReadConfig(f.LocalConfig.FilePath, &f.LocalConfig) + if f.configContent != "" { + err := cleanenv.ReadConfig(f.configContent, &f.LocalConfig) if err != nil { log.Error("config error: ", err) return utils.FailedReadingConfiguration diff --git a/pkg/utils/constants.go b/pkg/utils/constants.go index 23a49318..b1bd6cc1 100644 --- a/pkg/utils/constants.go +++ b/pkg/utils/constants.go @@ -61,7 +61,8 @@ const ( MissingOrIncorrectSecondaryDNS = 32 InvalidParameterCombination = 33 FailedReadingConfiguration = 34 - InvalidUserInput = 35 + MissingOrInvalidConfiguration = 35 + InvalidUserInput = 36 // (70-99) Connection Errors RPSAuthenticationFailed = 70 @@ -84,7 +85,6 @@ const ( WifiConfigurationWithWarnings = 112 UnmarshalMessageFailed = 113 DeleteWifiConfigFailed = 114 - MissingWifiConfiguration = 115 MissingOrIncorrectWifiProfileName = 116 MissingIeee8021xConfiguration = 117 From ce38b482b24d1c21550725fc9113bc2e05b043a3 Mon Sep 17 00:00:00 2001 From: Walt M Date: Wed, 23 Aug 2023 09:31:28 -0700 Subject: [PATCH 29/29] initial commit --- internal/amt/commands.go | 1 + internal/local/info.go | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/amt/commands.go b/internal/amt/commands.go index fce3e4f3..7613dcba 100644 --- a/internal/amt/commands.go +++ b/internal/amt/commands.go @@ -227,6 +227,7 @@ func (amt AMTCommand) GetDNSSuffix() (string, error) { } func (amt AMTCommand) GetCertificateHashes() ([]CertHashEntry, error) { + // TODO: process flag -system and -user err := amt.PTHI.Open(false) amtEntryList := []CertHashEntry{} if err != nil { diff --git a/internal/local/info.go b/internal/local/info.go index ab4ff57d..f46df287 100644 --- a/internal/local/info.go +++ b/internal/local/info.go @@ -3,12 +3,13 @@ package local import ( "encoding/json" "fmt" - log "github.com/sirupsen/logrus" "os" "rpc/internal/amt" "rpc/pkg/utils" "strconv" "strings" + + log "github.com/sirupsen/logrus" ) func (service *ProvisioningService) DisplayAMTInfo() int { @@ -153,6 +154,8 @@ func (service *ProvisioningService) DisplayAMTInfo() int { } } if service.flags.AmtInfo.Cert { + // TODO: process flag -system and -user + result, err := amtCommand.GetCertificateHashes() if err != nil { log.Error(err)