blob: 93c73ded6fb60dbaecaa4085fb6dae71368f607c [file] [log] [blame]
// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package wifi
import (
"context"
"encoding/json"
"time"
"github.com/golang/protobuf/ptypes/empty"
"go.chromium.org/tast-tests/cros/common/tbdep"
"go.chromium.org/tast-tests/cros/common/crypto/certificate"
"go.chromium.org/tast-tests/cros/common/pci"
"go.chromium.org/tast-tests/cros/common/policy"
tdreq "go.chromium.org/tast-tests/cros/common/testdevicerequirements"
"go.chromium.org/tast-tests/cros/common/wifi/security"
"go.chromium.org/tast-tests/cros/common/wifi/security/tunneled1x"
"go.chromium.org/tast-tests/cros/common/wifi/security/wpa"
"go.chromium.org/tast-tests/cros/remote/wificell"
ap "go.chromium.org/tast-tests/cros/remote/wificell/hostapd"
ps "go.chromium.org/tast-tests/cros/services/cros/policy"
"go.chromium.org/tast-tests/cros/services/cros/wifi"
"go.chromium.org/tast/core/ctxutil"
"go.chromium.org/tast/core/testing"
)
var (
eapCertPolicyBasic1 = certificate.TestCert1()
deviceGUID = "device_network_config"
userAPSSID = ap.RandomSSID("TAST_TEST_USER_")
deviceAPSSID = ap.RandomSSID("TAST_TEST_DEVICE_")
)
type policyBasicTestcase struct {
sameAP bool
devAPOpts []ap.Option
devSecConfFac security.ConfigFactory
policy *policy.DeviceOpenNetworkConfiguration
}
func init() {
testing.AddTest(&testing.Test{
Func: PolicyBasic,
LacrosStatus: testing.LacrosVariantUnneeded,
Desc: "Verifies that DUT can connect to the APs with device policy and per-user policy",
Contacts: []string{
"chromeos-wifi-champs@google.com", // WiFi oncall rotation
},
BugComponent: "b:893827", // ChromeOS > Platform > Connectivity > WiFi
Attr: []string{"group:wificell", "wificell_func"},
TestBedDeps: []string{tbdep.Wificell, tbdep.WifiStateNormal, tbdep.BluetoothStateNormal, tbdep.PeripheralWifiStateWorking},
SoftwareDeps: []string{"chrome"},
ServiceDeps: []string{wificell.ShillServiceName, "tast.cros.policy.PolicyService"},
Timeout: 10 * time.Minute,
Fixture: wificell.FixtureID(wificell.TFFeaturesEnroll),
Requirements: []string{tdreq.WiFiProcPassFW, tdreq.WiFiProcPassAVL, tdreq.WiFiProcPassAVLBeforeUpdates, tdreq.WiFiProcPassMatfunc, tdreq.WiFiProcPassMatfuncBeforeUpdates},
VariantCategory: `{"name": "WifiBtChipset_Soc_Kernel"}`,
SearchFlags: []*testing.StringPair{
pci.SearchFlag(&policy.DeviceOpenNetworkConfiguration{}, pci.Served),
pci.SearchFlag(&policy.OpenNetworkConfiguration{}, pci.Served),
},
Params: []testing.Param{
{
// Verify that DUT can connect to a WPA-EAP AP before sign in and still connect to the same WPA-EAP AP after sign in (b/192279295)
Name: "same_eap_ap",
Val: policyBasicTestcase{
sameAP: true,
devAPOpts: []ap.Option{ap.Mode(ap.Mode80211nPure), ap.Channel(6), ap.HTCaps(ap.HTCapHT20), ap.SSID(userAPSSID)},
devSecConfFac: tunneled1x.NewConfigFactory(
eapCertPolicyBasic1.CACred.Cert, eapCertPolicyBasic1.ServerCred, eapCertPolicyBasic1.CACred.Cert, "testuser", "password",
tunneled1x.Mode(wpa.ModePureWPA2),
tunneled1x.OuterProtocol(tunneled1x.Layer1TypePEAP),
tunneled1x.InnerProtocol(tunneled1x.Layer2TypeMSCHAPV2),
tunneled1x.Phase2User("tast-user@managedchrome.com", "test0000", tunneled1x.Layer2TypeMSCHAPV2),
),
policy: &policy.DeviceOpenNetworkConfiguration{
Val: &policy.ONC{
NetworkConfigurations: []*policy.ONCNetworkConfiguration{
{
GUID: deviceGUID,
Name: "DeviceWideNetworkConfig",
Type: "WiFi",
WiFi: &policy.ONCWifi{
AutoConnect: true,
Security: "WPA-EAP",
SSID: userAPSSID,
EAP: &policy.ONCEap{
Outer: "PEAP",
Inner: "MSCHAPv2",
Identity: "testuser",
Password: "password",
UseSystemCAs: false,
},
},
},
},
},
},
},
},
{
// Verify that DUT can connect to an open AP before sign in and switch to a WPA-EAP AP after sign in
Name: "open",
Val: policyBasicTestcase{
sameAP: false,
devAPOpts: []ap.Option{ap.Mode(ap.Mode80211nPure), ap.Channel(6), ap.HTCaps(ap.HTCapHT20), ap.SSID(deviceAPSSID)},
devSecConfFac: nil,
policy: &policy.DeviceOpenNetworkConfiguration{
Val: &policy.ONC{
NetworkConfigurations: []*policy.ONCNetworkConfiguration{
{
GUID: deviceGUID,
Name: "DeviceWideNetworkConfig",
Type: "WiFi",
WiFi: &policy.ONCWifi{
AutoConnect: true,
Security: "None",
SSID: deviceAPSSID,
},
},
},
},
},
},
},
{
// Verify that DUT can connect to a WPA-PSK AP before sign in and switch to a WPA-EAP AP after sign in
Name: "wpa_psk",
Val: policyBasicTestcase{
sameAP: false,
devAPOpts: []ap.Option{ap.Mode(ap.Mode80211nPure), ap.Channel(6), ap.HTCaps(ap.HTCapHT20), ap.SSID(deviceAPSSID)},
devSecConfFac: wpa.NewConfigFactory(
"chromeos", wpa.Mode(wpa.ModePureWPA2),
wpa.Ciphers2(wpa.CipherCCMP),
),
policy: &policy.DeviceOpenNetworkConfiguration{
Val: &policy.ONC{
NetworkConfigurations: []*policy.ONCNetworkConfiguration{
{
GUID: deviceGUID,
Name: "DeviceWideNetworkConfig",
Type: "WiFi",
WiFi: &policy.ONCWifi{
AutoConnect: true,
Security: "WPA-PSK",
SSID: deviceAPSSID,
Passphrase: "chromeos",
},
},
},
},
},
},
},
{
// Verify that DUT can connect to a WPA-EAP AP before sign in and switch to a different WPA-EAP AP after sign in
Name: "wpa_eap",
ExtraAttr: []string{"wificell_cq"},
Val: policyBasicTestcase{
sameAP: false,
devAPOpts: []ap.Option{ap.Mode(ap.Mode80211nPure), ap.Channel(6), ap.HTCaps(ap.HTCapHT20), ap.SSID(deviceAPSSID)},
devSecConfFac: tunneled1x.NewConfigFactory(
eapCertPolicyBasic1.CACred.Cert, eapCertPolicyBasic1.ServerCred, eapCertPolicyBasic1.CACred.Cert, "testuser", "password",
tunneled1x.Mode(wpa.ModePureWPA2),
tunneled1x.OuterProtocol(tunneled1x.Layer1TypePEAP),
tunneled1x.InnerProtocol(tunneled1x.Layer2TypeMSCHAPV2),
),
policy: &policy.DeviceOpenNetworkConfiguration{
Val: &policy.ONC{
NetworkConfigurations: []*policy.ONCNetworkConfiguration{
{
GUID: deviceGUID,
Name: "DeviceWideNetworkConfig",
Type: "WiFi",
WiFi: &policy.ONCWifi{
AutoConnect: true,
Security: "WPA-EAP",
SSID: deviceAPSSID,
EAP: &policy.ONCEap{
Outer: "PEAP",
Inner: "MSCHAPv2",
Identity: "testuser",
Password: "password",
UseSystemCAs: false,
},
},
},
},
},
},
},
},
},
})
}
/*
PolicyBasic test verifies if the DUT can connect to specific APs using the enterprise provisioned per-device or per-user policies
by correctly parsing the Open Network Configuration (ONC).
ONC spec: https://chromium.googlesource.com/chromium/src/+/main/components/onc/docs/onc_spec.md
Here are the full steps this test takes:
1. Start two AP BSSes, one to be used in the per-device policy and one to be used in the per-user policy.
2. Provision the per-device and per-user policy to the DUT.
3. Wait for the DUT to connect to the AP provisioned with the device policy and check connection via Ping.
4. Log in the user account, wait for the DUT to connect to the AP provisioned with the user's policy and check connection via Ping.
5. Clean up test, including disconnect, remove SSID entry and deconfig APs.
*/
func PolicyBasic(ctx context.Context, s *testing.State) {
userGUID := "user_network_config"
userAPOpts := []ap.Option{ap.Mode(ap.Mode80211nPure), ap.Channel(36), ap.HTCaps(ap.HTCapHT20), ap.SSID(userAPSSID)}
userSecConfFac := tunneled1x.NewConfigFactory(
eapCertPolicyBasic1.CACred.Cert, eapCertPolicyBasic1.ServerCred, eapCertPolicyBasic1.CACred.Cert, "tast-user@managedchrome.com", "test0000",
tunneled1x.Mode(wpa.ModePureWPA2),
tunneled1x.OuterProtocol(tunneled1x.Layer1TypePEAP),
tunneled1x.InnerProtocol(tunneled1x.Layer2TypeMSCHAPV2),
)
userNetPolicy := policy.OpenNetworkConfiguration{
Val: &policy.ONC{
NetworkConfigurations: []*policy.ONCNetworkConfiguration{
{
GUID: userGUID,
Name: "UserNetworkConfig",
Type: "WiFi",
WiFi: &policy.ONCWifi{
AutoConnect: true,
Security: "WPA-EAP",
SSID: userAPSSID,
EAP: &policy.ONCEap{
Outer: "PEAP",
Inner: "MSCHAPv2",
Identity: "${LOGIN_EMAIL}",
Password: "${PASSWORD}",
UseSystemCAs: false,
},
},
},
},
},
}
tc := s.Param().(policyBasicTestcase)
tf := s.FixtValue().(*wificell.TestFixture)
pc := ps.NewPolicyServiceClient(tf.RPC().Conn)
s.Log("Configuring device-wide Wi-Fi network")
deviceAP, err := tf.ConfigureAP(ctx, tc.devAPOpts, tc.devSecConfFac)
if err != nil {
s.Fatal("Failed to configure device-wide network AP, err: ", err)
}
defer func(ctx context.Context, ap *wificell.APIface) {
if err := tf.DeconfigAP(ctx, ap); err != nil {
s.Error("Failed to deconfig ap, err: ", err)
}
}(ctx, deviceAP)
ctx, cancel := tf.ReserveForDeconfigAP(ctx, deviceAP)
defer cancel()
var userAP = deviceAP
if !tc.sameAP {
s.Log("Configuring user Wi-Fi network")
userAP, err = tf.ConfigureAP(ctx, userAPOpts, userSecConfFac)
if err != nil {
s.Fatal("Failed to configure user Wi-Fi network, err: ", err)
}
defer func(ctx context.Context, ap *wificell.APIface) {
if err := tf.DeconfigAP(ctx, ap); err != nil {
s.Error("Failed to deconfig user network ap, err: ", err)
}
}(ctx, userAP)
ctx, cancel = tf.ReserveForDeconfigAP(ctx, userAP)
defer cancel()
}
s.Log("Provision Wi-Fi policy and waiting for DUT to auto connect to device-wide network")
pb := policy.NewBlob()
pb.AddPolicy(tc.policy)
pb.AddPolicy(&userNetPolicy)
pJSON, err := json.Marshal(pb)
if err != nil {
s.Fatal("Error while marshalling policies to JSON: ", err)
}
if _, err := pc.StartChrome(ctx, &ps.StartChromeRequest{
PolicyJson: pJSON,
KeepEnrollment: true,
DeferLogin: true,
}); err != nil {
s.Fatal("Failed to start Chrome instance: ", err)
}
defer pc.StopChrome(ctx, &empty.Empty{})
ctx, cancel = ctxutil.Shorten(ctx, 5*time.Second)
defer cancel()
if err := tf.WaitWifiConnected(ctx, wificell.DefaultDUT, deviceGUID); err != nil {
s.Fatal("DUT failed to connect to AP with device Wi-Fi policy: ", err)
}
defer func(ctx context.Context) {
req := &wifi.DeleteEntriesForSSIDRequest{Ssid: []byte(deviceAP.Config().SSID)}
if _, err := tf.WifiClient().DeleteEntriesForSSID(ctx, req); err != nil {
s.Errorf("Failed to remove entries for SSID=%s, err: %v", deviceAP.Config().SSID, err)
}
}(ctx)
ctx, cancel = ctxutil.Shorten(ctx, 2*time.Second)
defer cancel()
if err := tf.VerifyConnection(ctx, deviceAP); err != nil {
s.Fatal("Failed to verify connection: ", err)
}
s.Log("Continue login and wait for DUT to auto connect")
if _, err = pc.ContinueLogin(ctx, &empty.Empty{}); err != nil {
s.Fatal(err, "failed to login")
}
if err := tf.WaitWifiConnected(ctx, wificell.DefaultDUT, userGUID); err != nil {
s.Fatal("DUT failed to connect to AP with user Wi-Fi policy: ", err)
}
defer func(ctx context.Context) {
if err := tf.DisconnectWifi(ctx); err != nil {
s.Log("Failed to disconnect WiFi: ", err)
}
req := &wifi.DeleteEntriesForSSIDRequest{Ssid: []byte(userAP.Config().SSID)}
if _, err := tf.WifiClient().DeleteEntriesForSSID(ctx, req); err != nil {
s.Errorf("Failed to remove entries for SSID=%s, err: %v", userAP.Config().SSID, err)
}
}(ctx)
ctx, cancel = tf.ReserveForDisconnect(ctx)
defer cancel()
if err := tf.VerifyConnection(ctx, userAP); err != nil {
s.Fatal("Failed to verify connection: ", err)
}
}