Allow selection of a CA certificate for a VPN profile
This solution is just temporary as it really is not that user-friendly to select CA certificates with a Spinner widget.
This commit is contained in:
@@ -79,6 +79,31 @@
|
|||||||
android:inputType="textPassword|textNoSuggestions"
|
android:inputType="textPassword|textNoSuggestions"
|
||||||
android:hint="@string/profile_password_hint" />
|
android:hint="@string/profile_password_hint" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="@string/profile_ca_label" />
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/ca_auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/profile_ca_auto_label" />
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/ca_show_all"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:text="@string/profile_ca_show_all" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/ca_spinner"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="5dp" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
@@ -41,8 +41,13 @@
|
|||||||
<string name="profile_username_label">Username:</string>
|
<string name="profile_username_label">Username:</string>
|
||||||
<string name="profile_password_label">Password:</string>
|
<string name="profile_password_label">Password:</string>
|
||||||
<string name="profile_password_hint">(prompt when needed)</string>
|
<string name="profile_password_hint">(prompt when needed)</string>
|
||||||
|
<string name="profile_ca_label">CA certificate:</string>
|
||||||
|
<string name="profile_ca_auto_label">Select automatically</string>
|
||||||
|
<string name="profile_ca_show_all">Show all certificates</string>
|
||||||
<!-- Warnings/Notifications in the details view -->
|
<!-- Warnings/Notifications in the details view -->
|
||||||
<string name="alert_text_no_input_gateway">Please enter the gateway address here</string>
|
<string name="alert_text_no_input_gateway">Please enter the gateway address here</string>
|
||||||
<string name="alert_text_no_input_username">Please enter your username here</string>
|
<string name="alert_text_no_input_username">Please enter your username here</string>
|
||||||
|
<string name="alert_text_nocertfound_title">No CA certificate selected</string>
|
||||||
|
<string name="alert_text_nocertfound">Please select one or activate <i>Select automatically</i></string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -17,34 +17,56 @@
|
|||||||
|
|
||||||
package org.strongswan.android.ui;
|
package org.strongswan.android.ui;
|
||||||
|
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
|
||||||
import org.strongswan.android.R;
|
import org.strongswan.android.R;
|
||||||
import org.strongswan.android.data.VpnProfile;
|
import org.strongswan.android.data.VpnProfile;
|
||||||
import org.strongswan.android.data.VpnProfileDataSource;
|
import org.strongswan.android.data.VpnProfileDataSource;
|
||||||
|
import org.strongswan.android.logic.TrustedCertificateManager;
|
||||||
|
import org.strongswan.android.ui.adapter.TrustedCertificateAdapter;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.AdapterView.OnItemSelectedListener;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.CompoundButton;
|
||||||
|
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
|
||||||
public class VpnProfileDetailActivity extends Activity
|
public class VpnProfileDetailActivity extends Activity
|
||||||
{
|
{
|
||||||
private VpnProfileDataSource mDataSource;
|
private VpnProfileDataSource mDataSource;
|
||||||
private Long mId;
|
private Long mId;
|
||||||
private VpnProfile mProfile;
|
private VpnProfile mProfile;
|
||||||
|
private boolean mCertsLoaded;
|
||||||
|
private String mCertAlias;
|
||||||
|
private Spinner mCertSpinner;
|
||||||
|
private TrustedCertificateAdapter.CertEntry mSelectedCert;
|
||||||
private EditText mName;
|
private EditText mName;
|
||||||
private EditText mGateway;
|
private EditText mGateway;
|
||||||
private EditText mUsername;
|
private EditText mUsername;
|
||||||
private EditText mPassword;
|
private EditText mPassword;
|
||||||
|
private CheckBox mCheckAll;
|
||||||
|
private CheckBox mCheckAuto;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState)
|
public void onCreate(Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
||||||
|
|
||||||
/* the title is set when we load the profile, if any */
|
/* the title is set when we load the profile, if any */
|
||||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
@@ -59,6 +81,45 @@ public class VpnProfileDetailActivity extends Activity
|
|||||||
mGateway = (EditText)findViewById(R.id.gateway);
|
mGateway = (EditText)findViewById(R.id.gateway);
|
||||||
mUsername = (EditText)findViewById(R.id.username);
|
mUsername = (EditText)findViewById(R.id.username);
|
||||||
|
|
||||||
|
mCheckAll = (CheckBox)findViewById(R.id.ca_show_all);
|
||||||
|
mCheckAuto = (CheckBox)findViewById(R.id.ca_auto);
|
||||||
|
mCertSpinner = (Spinner)findViewById(R.id.ca_spinner);
|
||||||
|
|
||||||
|
mCheckAuto.setOnCheckedChangeListener(new OnCheckedChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||||
|
{
|
||||||
|
updateCertSpinner();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mCheckAll.setOnCheckedChangeListener(new OnCheckedChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
|
||||||
|
{
|
||||||
|
Hashtable<String, X509Certificate> certs;
|
||||||
|
certs = isChecked ? TrustedCertificateManager.getInstance().getAllCACertificates()
|
||||||
|
: TrustedCertificateManager.getInstance().getUserCACertificates();
|
||||||
|
mCertSpinner.setAdapter(new TrustedCertificateAdapter(VpnProfileDetailActivity.this, certs));
|
||||||
|
mSelectedCert = (TrustedCertificateAdapter.CertEntry)mCertSpinner.getSelectedItem();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mCertSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemSelected(AdapterView<?> parent, View view,
|
||||||
|
int pos, long id)
|
||||||
|
{
|
||||||
|
mSelectedCert = (TrustedCertificateAdapter.CertEntry)parent.getSelectedItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNothingSelected(AdapterView<?> arg0)
|
||||||
|
{
|
||||||
|
mSelectedCert = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
mId = savedInstanceState == null ? null : savedInstanceState.getLong(VpnProfileDataSource.KEY_ID);
|
mId = savedInstanceState == null ? null : savedInstanceState.getLong(VpnProfileDataSource.KEY_ID);
|
||||||
if (mId == null)
|
if (mId == null)
|
||||||
{
|
{
|
||||||
@@ -67,6 +128,8 @@ public class VpnProfileDetailActivity extends Activity
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadProfileData();
|
loadProfileData();
|
||||||
|
|
||||||
|
new CertificateLoadTask().execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -108,6 +171,111 @@ public class VpnProfileDetailActivity extends Activity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show an alert in case the previously selected certificate is not found anymore
|
||||||
|
* or the user did not select a certificate in the spinner.
|
||||||
|
*/
|
||||||
|
private void showCertificateAlert()
|
||||||
|
{
|
||||||
|
AlertDialog.Builder adb = new AlertDialog.Builder(VpnProfileDetailActivity.this);
|
||||||
|
adb.setTitle(R.string.alert_text_nocertfound_title);
|
||||||
|
adb.setMessage(R.string.alert_text_nocertfound);
|
||||||
|
adb.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int id)
|
||||||
|
{
|
||||||
|
dialog.cancel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
adb.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronously executed task which confirms that the certificates are loaded.
|
||||||
|
* They are loaded from the main Activity already but might not be ready yet, or
|
||||||
|
* unloaded again.
|
||||||
|
*
|
||||||
|
* Once loaded the CA certificate spinner and checkboxes are updated
|
||||||
|
* accordingly.
|
||||||
|
*/
|
||||||
|
private class CertificateLoadTask extends AsyncTask<Void, Void, TrustedCertificateManager>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute()
|
||||||
|
{
|
||||||
|
setProgressBarIndeterminateVisibility(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TrustedCertificateManager doInBackground(Void... params)
|
||||||
|
{
|
||||||
|
return TrustedCertificateManager.getInstance().load();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(TrustedCertificateManager result)
|
||||||
|
{
|
||||||
|
TrustedCertificateAdapter adapter;
|
||||||
|
if (mCertAlias != null && mCertAlias.startsWith("system:"))
|
||||||
|
{
|
||||||
|
mCheckAll.setChecked(true);
|
||||||
|
adapter = new TrustedCertificateAdapter(VpnProfileDetailActivity.this,
|
||||||
|
result.getAllCACertificates());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mCheckAll.setChecked(false);
|
||||||
|
adapter = new TrustedCertificateAdapter(VpnProfileDetailActivity.this,
|
||||||
|
result.getUserCACertificates());
|
||||||
|
}
|
||||||
|
mCertSpinner.setAdapter(adapter);
|
||||||
|
|
||||||
|
if (mCertAlias != null)
|
||||||
|
{
|
||||||
|
int position = adapter.getItemPosition(mCertAlias);
|
||||||
|
if (position == -1)
|
||||||
|
{ /* previously selected certificate is not here anymore */
|
||||||
|
showCertificateAlert();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mCertSpinner.setSelection(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mSelectedCert = (TrustedCertificateAdapter.CertEntry)mCertSpinner.getSelectedItem();
|
||||||
|
|
||||||
|
setProgressBarIndeterminateVisibility(false);
|
||||||
|
mCertsLoaded = true;
|
||||||
|
updateCertSpinner();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the CA certificate selection UI depending on whether the
|
||||||
|
* certificate should be automatically selected or not.
|
||||||
|
*/
|
||||||
|
private void updateCertSpinner()
|
||||||
|
{
|
||||||
|
if (!mCheckAuto.isChecked())
|
||||||
|
{
|
||||||
|
if (mCertsLoaded)
|
||||||
|
{
|
||||||
|
mCertSpinner.setEnabled(true);
|
||||||
|
mCertSpinner.setVisibility(View.VISIBLE);
|
||||||
|
mCheckAll.setEnabled(true);
|
||||||
|
mCheckAll.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mCertSpinner.setEnabled(false);
|
||||||
|
mCertSpinner.setVisibility(View.GONE);
|
||||||
|
mCheckAll.setEnabled(false);
|
||||||
|
mCheckAll.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save or update the profile depending on whether we actually have a
|
* Save or update the profile depending on whether we actually have a
|
||||||
* profile object or not (this was created in updateProfileData)
|
* profile object or not (this was created in updateProfileData)
|
||||||
@@ -149,6 +317,11 @@ public class VpnProfileDetailActivity extends Activity
|
|||||||
mUsername.setError(getString(R.string.alert_text_no_input_username));
|
mUsername.setError(getString(R.string.alert_text_no_input_username));
|
||||||
valid = false;
|
valid = false;
|
||||||
}
|
}
|
||||||
|
if (!mCheckAuto.isChecked() && mSelectedCert == null)
|
||||||
|
{
|
||||||
|
showCertificateAlert();
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,6 +339,8 @@ public class VpnProfileDetailActivity extends Activity
|
|||||||
String password = mPassword.getText().toString().trim();
|
String password = mPassword.getText().toString().trim();
|
||||||
password = password.isEmpty() ? null : password;
|
password = password.isEmpty() ? null : password;
|
||||||
mProfile.setPassword(password);
|
mProfile.setPassword(password);
|
||||||
|
String certAlias = mCheckAuto.isChecked() ? null : mSelectedCert.mAlias;
|
||||||
|
mProfile.setCertificateAlias(certAlias);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -183,6 +358,7 @@ public class VpnProfileDetailActivity extends Activity
|
|||||||
mGateway.setText(mProfile.getGateway());
|
mGateway.setText(mProfile.getGateway());
|
||||||
mUsername.setText(mProfile.getUsername());
|
mUsername.setText(mProfile.getUsername());
|
||||||
mPassword.setText(mProfile.getPassword());
|
mPassword.setText(mProfile.getPassword());
|
||||||
|
mCertAlias = mProfile.getCertificateAlias();
|
||||||
getActionBar().setTitle(mProfile.getName());
|
getActionBar().setTitle(mProfile.getName());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -192,5 +368,8 @@ public class VpnProfileDetailActivity extends Activity
|
|||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mCheckAll.setChecked(false);
|
||||||
|
mCheckAuto.setChecked(mCertAlias == null);
|
||||||
|
updateCertSpinner();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user