Merge "[WIFI-Enterprise] Change the summary for Certificate Details." into main

This commit is contained in:
Charlotte Lu
2024-04-12 04:40:30 +00:00
committed by Android (Google) Code Review
2 changed files with 77 additions and 20 deletions

View File

@@ -37,6 +37,9 @@ import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.wifi.flags.Flags import com.android.wifi.flags.Flags
import com.android.wifitrackerlib.WifiEntry import com.android.wifitrackerlib.WifiEntry
import com.android.wifitrackerlib.WifiEntry.CertificateInfo.CERTIFICATE_VALIDATION_METHOD_USING_CERTIFICATE_PINNING
import com.android.wifitrackerlib.WifiEntry.CertificateInfo.CERTIFICATE_VALIDATION_METHOD_USING_INSTALLED_ROOTCA
import com.android.wifitrackerlib.WifiEntry.CertificateInfo.CERTIFICATE_VALIDATION_METHOD_USING_SYSTEM_CERTIFICATE
import java.security.KeyStore import java.security.KeyStore
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
@@ -44,15 +47,13 @@ class CertificateDetailsPreferenceController(context: Context, preferenceKey: St
ComposePreferenceController(context, preferenceKey) { ComposePreferenceController(context, preferenceKey) {
private lateinit var wifiEntry: WifiEntry private lateinit var wifiEntry: WifiEntry
lateinit var certificateAliases: String
lateinit var certX509: X509Certificate
fun setWifiEntry(entry: WifiEntry) { fun setWifiEntry(entry: WifiEntry) {
wifiEntry = entry wifiEntry = entry
} }
override fun getAvailabilityStatus(): Int { override fun getAvailabilityStatus(): Int {
return if (Flags.androidVWifiApi() && getCertX509(wifiEntry)) AVAILABLE return if (Flags.androidVWifiApi() && isCertificateDetailsAvailable(wifiEntry)) AVAILABLE
else CONDITIONALLY_UNAVAILABLE else CONDITIONALLY_UNAVAILABLE
} }
@@ -64,26 +65,52 @@ class CertificateDetailsPreferenceController(context: Context, preferenceKey: St
@Composable @Composable
fun CertificateDetails() { fun CertificateDetails() {
val context = LocalContext.current val context = LocalContext.current
val validationMethod = wifiEntry.certificateInfo!!.validationMethod
val certificateDetailsSummary = when (validationMethod) {
CERTIFICATE_VALIDATION_METHOD_USING_SYSTEM_CERTIFICATE ->
stringResource(R.string.wifi_certificate_summary_system)
CERTIFICATE_VALIDATION_METHOD_USING_INSTALLED_ROOTCA -> {
val aliasesSize = wifiEntry.certificateInfo?.caCertificateAliases?.size
if (aliasesSize == 1) stringResource(R.string.one_cacrt)
else
String.format(
stringResource(R.string.wifi_certificate_summary_Certificates),
aliasesSize
)
}
else -> stringResource(R.string.wifi_certificate_summary_pinning)
}
Preference(object : PreferenceModel { Preference(object : PreferenceModel {
override val title = stringResource(com.android.internal.R.string.ssl_certificate) override val title = stringResource(com.android.internal.R.string.ssl_certificate)
override val summary = { certificateAliases } override val summary = { certificateDetailsSummary }
override val onClick: () -> Unit = { createCertificateDetailsDialog(context, certX509) } override val onClick: () -> Unit = {
if (validationMethod == CERTIFICATE_VALIDATION_METHOD_USING_INSTALLED_ROOTCA)
getCertX509(wifiEntry)?.let {
createCertificateDetailsDialog(
context,
it
)
}
}
}) })
} }
private fun getCertX509(wifiEntry: WifiEntry): Boolean { private fun getCertX509(wifiEntry: WifiEntry): X509Certificate? {
certificateAliases = val certificateAliases =
wifiEntry.wifiConfiguration?.enterpriseConfig?.caCertificateAliases?.get(0) wifiEntry.certificateInfo?.caCertificateAliases?.get(0)
?: return false ?: return null
return try { return try {
val keyStore = KeyStore.getInstance("AndroidKeyStore") val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(AndroidKeyStoreLoadStoreParameter(KeyProperties.NAMESPACE_WIFI)) keyStore.load(AndroidKeyStoreLoadStoreParameter(KeyProperties.NAMESPACE_WIFI))
val cert = keyStore.getCertificate(certificateAliases) val cert = keyStore.getCertificate(certificateAliases)
certX509 = KeyChain.toCertificate(cert.encoded) KeyChain.toCertificate(cert.encoded)
true
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Failed to open Android Keystore.", e) Log.e(TAG, "Failed to open Android Keystore.", e)
false null
} }
} }
@@ -124,6 +151,15 @@ class CertificateDetailsPreferenceController(context: Context, preferenceKey: St
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setEnabled(false) dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setEnabled(false)
} }
private fun isCertificateDetailsAvailable(wifiEntry: WifiEntry): Boolean {
val validationMethod = wifiEntry.certificateInfo?.validationMethod
return validationMethod in listOf(
CERTIFICATE_VALIDATION_METHOD_USING_SYSTEM_CERTIFICATE,
CERTIFICATE_VALIDATION_METHOD_USING_INSTALLED_ROOTCA,
CERTIFICATE_VALIDATION_METHOD_USING_CERTIFICATE_PINNING
)
}
companion object { companion object {
const val TAG = "CertificateDetailsPreferenceController" const val TAG = "CertificateDetailsPreferenceController"
} }

View File

@@ -17,6 +17,7 @@
package com.android.settings.wifi.details2 package com.android.settings.wifi.details2
import android.content.Context import android.content.Context
import android.platform.test.annotations.RequiresFlagsEnabled
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertIsDisplayed
@@ -24,13 +25,15 @@ import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.onNodeWithText
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import java.security.cert.X509Certificate import com.android.settings.R
import com.android.wifitrackerlib.WifiEntry
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.kotlin.any import org.mockito.kotlin.any
import org.mockito.kotlin.doNothing import org.mockito.kotlin.doNothing
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock import org.mockito.kotlin.mock
import org.mockito.kotlin.spy import org.mockito.kotlin.spy
import org.mockito.kotlin.whenever import org.mockito.kotlin.whenever
@@ -40,21 +43,26 @@ class CertificateDetailsPreferenceControllerTest {
@get:Rule @get:Rule
val composeTestRule = createComposeRule() val composeTestRule = createComposeRule()
private val mockCertX509 = mock<X509Certificate> {}
private val context: Context = spy(ApplicationProvider.getApplicationContext()) { private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
doNothing().whenever(mock).startActivity(any()) doNothing().whenever(mock).startActivity(any())
} }
private val controller = CertificateDetailsPreferenceController(context, TEST_KEY) private val controller = CertificateDetailsPreferenceController(context, TEST_KEY)
private val mockCertificateInfo = mock<WifiEntry.CertificateInfo> {
it.validationMethod =
WifiEntry.CertificateInfo.CERTIFICATE_VALIDATION_METHOD_USING_INSTALLED_ROOTCA
it.caCertificateAliases = arrayOf(MOCK_CA)
}
private val mockWifiEntry =
mock<WifiEntry> { on { certificateInfo } doReturn mockCertificateInfo }
@Before @Before
fun setUp() { fun setUp() {
controller.certificateAliases = MOCK_CA controller.setWifiEntry(mockWifiEntry)
controller.certX509 = mockCertX509
} }
@Test @Test
@RequiresFlagsEnabled(com.android.wifi.flags.Flags.FLAG_ANDROID_V_WIFI_API)
fun title_isDisplayed() { fun title_isDisplayed() {
composeTestRule.setContent { composeTestRule.setContent {
CompositionLocalProvider(LocalContext provides context) { CompositionLocalProvider(LocalContext provides context) {
@@ -62,8 +70,21 @@ class CertificateDetailsPreferenceControllerTest {
} }
} }
composeTestRule.onNodeWithText(context.getString(com.android.internal.R.string.ssl_certificate)) composeTestRule.onNodeWithText(
.assertIsDisplayed() context.getString(com.android.internal.R.string.ssl_certificate)
).assertIsDisplayed()
}
@Test
@RequiresFlagsEnabled(com.android.wifi.flags.Flags.FLAG_ANDROID_V_WIFI_API)
fun one_caCertificate_summary() {
composeTestRule.setContent {
CompositionLocalProvider(LocalContext provides context) {
controller.Content()
}
}
composeTestRule.onNodeWithText(context.getString(R.string.one_cacrt)).assertIsDisplayed()
} }
private companion object { private companion object {