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.wifi.flags.Flags
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.cert.X509Certificate
@@ -44,15 +47,13 @@ class CertificateDetailsPreferenceController(context: Context, preferenceKey: St
ComposePreferenceController(context, preferenceKey) {
private lateinit var wifiEntry: WifiEntry
lateinit var certificateAliases: String
lateinit var certX509: X509Certificate
fun setWifiEntry(entry: WifiEntry) {
wifiEntry = entry
}
override fun getAvailabilityStatus(): Int {
return if (Flags.androidVWifiApi() && getCertX509(wifiEntry)) AVAILABLE
return if (Flags.androidVWifiApi() && isCertificateDetailsAvailable(wifiEntry)) AVAILABLE
else CONDITIONALLY_UNAVAILABLE
}
@@ -64,26 +65,52 @@ class CertificateDetailsPreferenceController(context: Context, preferenceKey: St
@Composable
fun CertificateDetails() {
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 {
override val title = stringResource(com.android.internal.R.string.ssl_certificate)
override val summary = { certificateAliases }
override val onClick: () -> Unit = { createCertificateDetailsDialog(context, certX509) }
override val summary = { certificateDetailsSummary }
override val onClick: () -> Unit = {
if (validationMethod == CERTIFICATE_VALIDATION_METHOD_USING_INSTALLED_ROOTCA)
getCertX509(wifiEntry)?.let {
createCertificateDetailsDialog(
context,
it
)
}
}
})
}
private fun getCertX509(wifiEntry: WifiEntry): Boolean {
certificateAliases =
wifiEntry.wifiConfiguration?.enterpriseConfig?.caCertificateAliases?.get(0)
?: return false
private fun getCertX509(wifiEntry: WifiEntry): X509Certificate? {
val certificateAliases =
wifiEntry.certificateInfo?.caCertificateAliases?.get(0)
?: return null
return try {
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(AndroidKeyStoreLoadStoreParameter(KeyProperties.NAMESPACE_WIFI))
val cert = keyStore.getCertificate(certificateAliases)
certX509 = KeyChain.toCertificate(cert.encoded)
true
KeyChain.toCertificate(cert.encoded)
} catch (e: Exception) {
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)
}
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 {
const val TAG = "CertificateDetailsPreferenceController"
}

View File

@@ -17,6 +17,7 @@
package com.android.settings.wifi.details2
import android.content.Context
import android.platform.test.annotations.RequiresFlagsEnabled
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalContext
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.test.core.app.ApplicationProvider
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.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.doNothing
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.whenever
@@ -40,21 +43,26 @@ class CertificateDetailsPreferenceControllerTest {
@get:Rule
val composeTestRule = createComposeRule()
private val mockCertX509 = mock<X509Certificate> {}
private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
doNothing().whenever(mock).startActivity(any())
}
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
fun setUp() {
controller.certificateAliases = MOCK_CA
controller.certX509 = mockCertX509
controller.setWifiEntry(mockWifiEntry)
}
@Test
@RequiresFlagsEnabled(com.android.wifi.flags.Flags.FLAG_ANDROID_V_WIFI_API)
fun title_isDisplayed() {
composeTestRule.setContent {
CompositionLocalProvider(LocalContext provides context) {
@@ -62,8 +70,21 @@ class CertificateDetailsPreferenceControllerTest {
}
}
composeTestRule.onNodeWithText(context.getString(com.android.internal.R.string.ssl_certificate))
.assertIsDisplayed()
composeTestRule.onNodeWithText(
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 {