package com.afwsamples.testdpc.policy.wifimanagement;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiEnterpriseConfig;
import android.os.Bundle;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.afwsamples.testdpc.R;
import com.afwsamples.testdpc.common.CertificateUtil;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
/**
* Dialog for adding/editing EAP-TLS Wifi.
* We currently only support CA cert in x.509 format and client cert in PKCS12 format.
*/
public class WifiEapTlsCreateDialogFragment extends DialogFragment {
private final static int REQUEST_CA_CERT = 1;
private final static int REQUEST_USER_CERT = 2;
private final static String ARG_CONFIG = "config";
private static final String TAG = "wifi_eap_tls";
private WifiConfiguration mWifiConfiguration;
private Uri mCaCertUri;
private Uri mUserCertUri;
private EditText mSsidEditText;
private TextView mCaCertTextView;
private TextView mUserCertTextView;
private EditText mCertPasswordEditText;
private EditText mIdentityEditText;
public static WifiEapTlsCreateDialogFragment newInstance(WifiConfiguration config) {
Bundle arguments = new Bundle();
arguments.putParcelable(ARG_CONFIG, config);
WifiEapTlsCreateDialogFragment fragment = new WifiEapTlsCreateDialogFragment();
fragment.setArguments(arguments);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mWifiConfiguration = getArguments().getParcelable(ARG_CONFIG);
if (mWifiConfiguration == null) {
mWifiConfiguration = new WifiConfiguration();
}
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = LayoutInflater.from(getActivity());
View rootView = inflater.inflate(R.layout.eap_tls_wifi_config_dialog, null);
rootView.findViewById(R.id.import_ca_cert).setOnClickListener(
new ImportButtonOnClickListener(REQUEST_CA_CERT, "application/x-x509-ca-cert"));
rootView.findViewById(R.id.import_user_cert).setOnClickListener(
new ImportButtonOnClickListener(REQUEST_USER_CERT, "application/x-pkcs12"));
mCaCertTextView = (TextView) rootView.findViewById(R.id.selected_ca_cert);
mUserCertTextView = (TextView) rootView.findViewById(R.id.selected_user_cert);
mSsidEditText = (EditText) rootView.findViewById(R.id.ssid);
mCertPasswordEditText = (EditText) rootView.findViewById(R.id.wifi_client_cert_password);
mIdentityEditText = (EditText) rootView.findViewById(R.id.wifi_identity);
populateUi();
final AlertDialog dialog = new AlertDialog.Builder(getActivity())
.setTitle(R.string.create_eap_tls_wifi_configuration)
.setView(rootView)
.setPositiveButton(R.string.wifi_save, null)
.setNegativeButton(R.string.wifi_cancel, null)
.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialogInterface) {
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View view) {
// Only dismiss the dialog when we saved the config.
if (extractInputDataAndSave()) {
dialog.dismiss();
}
}
});
}
});
return dialog;
}
private void populateUi() {
if (mWifiConfiguration == null) {
return;
}
if (!TextUtils.isEmpty(mWifiConfiguration.SSID)) {
mSsidEditText.setText(mWifiConfiguration.SSID.replace("\"", ""));
}
mIdentityEditText.setText(mWifiConfiguration.enterpriseConfig.getIdentity());
// Both ca cert and client are not populated in the WifiConfiguration object.
updateSelectedCert(mCaCertTextView, null);
updateSelectedCert(mUserCertTextView, null);
}
private boolean extractInputDataAndSave() {
String ssid = mSsidEditText.getText().toString();
if (TextUtils.isEmpty(ssid)) {
mSsidEditText.setError(getString(R.string.error_missing_ssid));
return false;
} else {
mSsidEditText.setError(null);
}
if (mCaCertUri == null) {
showToast(R.string.error_missing_ca_cert);
return false;
}
if (mUserCertUri == null) {
showToast(R.string.error_missing_client_cert);
return false;
}
X509Certificate caCert = parseX509Certificate(mCaCertUri);
String certPassword = mCertPasswordEditText.getText().toString();
CertificateUtil.PKCS12ParseInfo parseInfo = null;
try {
parseInfo = CertificateUtil.parsePKCS12Certificate(
getActivity().getContentResolver(), mUserCertUri, certPassword);
} catch (KeyStoreException | NoSuchAlgorithmException | IOException |
CertificateException | UnrecoverableKeyException e) {
Log.e(TAG, "Fail to parse the input certificate: ", e);
}
if (parseInfo == null) {
showToast(R.string.error_missing_client_cert);
return false;
}
String identity = mIdentityEditText.getText().toString();
boolean success = saveWifiConfiguration(ssid, caCert, parseInfo.privateKey,
parseInfo.certificate, identity);
if (success) {
showToast(R.string.wifi_configs_header);
return true;
} else {
showToast(R.string.wifi_config_fail);
}
return false;
}
private boolean saveWifiConfiguration(String ssid, X509Certificate caCert,
PrivateKey privateKey, X509Certificate userCert, String identity) {
mWifiConfiguration.SSID = ssid;
mWifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
mWifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
enterpriseConfig.setCaCertificate(caCert);
enterpriseConfig.setClientKeyEntry(privateKey, userCert);
if (!TextUtils.isEmpty(identity)) {
enterpriseConfig.setIdentity(identity);
}
mWifiConfiguration.enterpriseConfig = enterpriseConfig;
return WifiConfigUtil.saveWifiConfiguration(getActivity(), mWifiConfiguration);
}
/**
* @param uri of the x509 certificate
* @return the X509Certificate object
*/
private X509Certificate parseX509Certificate(Uri uri) {
try {
CertificateFactory factory = CertificateFactory.getInstance("X.509");
InputStream inputStream = getActivity().getContentResolver().openInputStream(uri);
return (X509Certificate) factory.generateCertificate(inputStream);
} catch (IOException | CertificateException ex) {
Log.e(TAG, "parseX509Certificate: ", ex);
return null;
}
}
private class ImportButtonOnClickListener implements View.OnClickListener {
private int mRequestCode;
private String mMimeType;
public ImportButtonOnClickListener(int requestCode, String mimeType) {
mRequestCode = requestCode;
mMimeType = mimeType;
}
@Override
public void onClick(View view) {
Intent certIntent = new Intent(Intent.ACTION_GET_CONTENT);
certIntent.setTypeAndNormalize(mMimeType);
try {
startActivityForResult(certIntent, mRequestCode);
} catch (ActivityNotFoundException e) {
Log.e(TAG, "no file picker: ", e);
}
}
}
private void updateSelectedCert(TextView textView, Uri uri) {
String displayName = null;
if (uri == null) {
displayName = getString(R.string.selected_certificate_none);
} else {
final String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME};
Cursor cursor = getActivity().getContentResolver().query(uri, projection,
null, null, null);
if (cursor != null) {
try {
if (cursor.moveToFirst()) {
displayName = cursor.getString(0);
}
} finally {
cursor.close();
}
}
if (TextUtils.isEmpty(getString(R.string.wifi_unknown_cert))) {
displayName = getString(R.string.wifi_unknown_cert);
}
}
String selectedText = getString(R.string.selected_certificate, displayName);
textView.setText(selectedText);
}
private void showToast(int message) {
Toast.makeText(getActivity(), message, Toast.LENGTH_LONG).show();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (resultCode == Activity.RESULT_OK) {
switch (requestCode) {
case REQUEST_CA_CERT:
mCaCertUri = intent.getData();
updateSelectedCert(mCaCertTextView, mCaCertUri);
break;
case REQUEST_USER_CERT:
mUserCertUri = intent.getData();
updateSelectedCert(mUserCertTextView, mUserCertUri);
break;
}
}
}
}