Merge "Rework account security bootstrap procedure" into honeycomb
This commit is contained in:
commit
3dc2fcaac3
@ -18,6 +18,7 @@ package com.android.email.activity.setup;
|
|||||||
|
|
||||||
import com.android.email.R;
|
import com.android.email.R;
|
||||||
import com.android.email.SecurityPolicy;
|
import com.android.email.SecurityPolicy;
|
||||||
|
import com.android.email.Utility;
|
||||||
import com.android.email.activity.ActivityHelper;
|
import com.android.email.activity.ActivityHelper;
|
||||||
import com.android.email.provider.EmailContent.Account;
|
import com.android.email.provider.EmailContent.Account;
|
||||||
import com.android.email.provider.EmailContent.HostAuth;
|
import com.android.email.provider.EmailContent.HostAuth;
|
||||||
@ -26,6 +27,7 @@ import android.app.Activity;
|
|||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,6 +49,11 @@ public class AccountSecurity extends Activity {
|
|||||||
private static final int REQUEST_PASSWORD = 2;
|
private static final int REQUEST_PASSWORD = 2;
|
||||||
private static final int REQUEST_ENCRYPTION = 3;
|
private static final int REQUEST_ENCRYPTION = 3;
|
||||||
|
|
||||||
|
private boolean mTriedAddAdministrator = false;
|
||||||
|
private boolean mTriedSetPassword = false;
|
||||||
|
private boolean mTriedSetEncryption = false;
|
||||||
|
private Account mAccount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for generating intent for this activity (which is intended to be launched
|
* Used for generating intent for this activity (which is intended to be launched
|
||||||
* from a notification.)
|
* from a notification.)
|
||||||
@ -67,20 +74,73 @@ public class AccountSecurity extends Activity {
|
|||||||
ActivityHelper.debugSetWindowFlags(this);
|
ActivityHelper.debugSetWindowFlags(this);
|
||||||
|
|
||||||
Intent i = getIntent();
|
Intent i = getIntent();
|
||||||
long accountId = i.getLongExtra(EXTRA_ACCOUNT_ID, -1);
|
final long accountId = i.getLongExtra(EXTRA_ACCOUNT_ID, -1);
|
||||||
SecurityPolicy security = SecurityPolicy.getInstance(this);
|
SecurityPolicy security = SecurityPolicy.getInstance(this);
|
||||||
security.clearNotification(accountId);
|
security.clearNotification(accountId);
|
||||||
if (accountId != -1) {
|
if (accountId == -1) {
|
||||||
// TODO: spin up a thread to do this in the background, because of DB ops
|
finish();
|
||||||
Account account = Account.restoreAccountWithId(this, accountId);
|
return;
|
||||||
if (account != null) {
|
}
|
||||||
if (account.mSecurityFlags != 0) {
|
|
||||||
|
// Let onCreate exit, while background thread retrieves account.
|
||||||
|
// Then start the security check/bootstrap process.
|
||||||
|
new AsyncTask<Void, Void, Account>() {
|
||||||
|
@Override
|
||||||
|
protected Account doInBackground(Void... params) {
|
||||||
|
return Account.restoreAccountWithId(AccountSecurity.this, accountId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Account result) {
|
||||||
|
mAccount = result;
|
||||||
|
if (mAccount != null && mAccount.mSecurityFlags != 0) {
|
||||||
// This account wants to control security
|
// This account wants to control security
|
||||||
|
tryAdvanceSecurity(mAccount);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After any of the activities return, try to advance to the "next step"
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
tryAdvanceSecurity(mAccount);
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Walk the user through the required steps to become an active administrator and with
|
||||||
|
* the requisite security settings for the given account.
|
||||||
|
*
|
||||||
|
* These steps will be repeated each time we return from a given attempt (e.g. asking the
|
||||||
|
* user to choose a device pin/password). In a typical activation, we may repeat these
|
||||||
|
* steps a few times. It may go as far as step 5 (password) or step 6 (encryption), but it
|
||||||
|
* will terminate when step 2 (isActive()) succeeds.
|
||||||
|
*
|
||||||
|
* If at any point we do not advance beyond a given user step, (e.g. the user cancels
|
||||||
|
* instead of setting a password) we simply repost the security notification, and exit.
|
||||||
|
* We never want to loop here.
|
||||||
|
*/
|
||||||
|
private void tryAdvanceSecurity(Account account) {
|
||||||
|
SecurityPolicy security = SecurityPolicy.getInstance(this);
|
||||||
|
|
||||||
|
// Step 1. Check if we are an active device administrator, and stop here to activate
|
||||||
if (!security.isActiveAdmin()) {
|
if (!security.isActiveAdmin()) {
|
||||||
|
if (mTriedAddAdministrator) {
|
||||||
|
repostNotification(account, security);
|
||||||
|
finish();
|
||||||
|
} else {
|
||||||
|
mTriedAddAdministrator = true;
|
||||||
// retrieve name of server for the format string
|
// retrieve name of server for the format string
|
||||||
HostAuth hostAuth =
|
HostAuth hostAuth = HostAuth.restoreHostAuthWithId(this, account.mHostAuthKeyRecv);
|
||||||
HostAuth.restoreHostAuthWithId(this, account.mHostAuthKeyRecv);
|
if (hostAuth == null) {
|
||||||
if (hostAuth != null) {
|
repostNotification(account, security);
|
||||||
|
finish();
|
||||||
|
} else {
|
||||||
// try to become active - must happen here in activity, to get result
|
// try to become active - must happen here in activity, to get result
|
||||||
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
|
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
|
||||||
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
|
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
|
||||||
@ -89,92 +149,69 @@ public class AccountSecurity extends Activity {
|
|||||||
this.getString(R.string.account_security_policy_explanation_fmt,
|
this.getString(R.string.account_security_policy_explanation_fmt,
|
||||||
hostAuth.mAddress));
|
hostAuth.mAddress));
|
||||||
startActivityForResult(intent, REQUEST_ENABLE);
|
startActivityForResult(intent, REQUEST_ENABLE);
|
||||||
// keep this activity on stack to process result
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// already active - try to set actual policies, finish, and return
|
// Step 2. Check if the current aggregate security policy is being satisfied by the
|
||||||
boolean startedActivity = setActivePolicies();
|
// DevicePolicyManager (the current system security level).
|
||||||
if (startedActivity) {
|
if (security.isActive(null)) {
|
||||||
// keep this activity on stack to process result
|
Account.clearSecurityHoldOnAllAccounts(this);
|
||||||
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// Step 3. Try to assert the current aggregate security requirements with the system.
|
||||||
* Handle the eventual result of the user allowing us to become an active device admin
|
security.setActivePolicies();
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
boolean startedActivity = false;
|
|
||||||
switch (requestCode) {
|
|
||||||
case REQUEST_PASSWORD:
|
|
||||||
case REQUEST_ENCRYPTION:
|
|
||||||
// Force the result code and just check the DPM to check for actual success
|
|
||||||
resultCode = Activity.RESULT_OK;
|
|
||||||
//$FALL-THROUGH$
|
|
||||||
case REQUEST_ENABLE:
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
|
||||||
// now active - try to set actual policies
|
|
||||||
startedActivity = setActivePolicies();
|
|
||||||
} else {
|
|
||||||
// failed - repost notification, and exit
|
|
||||||
final long accountId = getIntent().getLongExtra(EXTRA_ACCOUNT_ID, -1);
|
|
||||||
if (accountId != -1) {
|
|
||||||
new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
SecurityPolicy.getInstance(AccountSecurity.this)
|
|
||||||
.policiesRequired(accountId);
|
|
||||||
}
|
|
||||||
}.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!startedActivity) {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// Step 4. Recheck the security policy, and determine what changes are needed (if any)
|
||||||
* Now that we are connected as an active device admin, try to set the device to the
|
// to satisfy the requirements.
|
||||||
* correct security level, and ask for a password if necessary.
|
int inactiveReasons = security.getInactiveReasons(null);
|
||||||
* @return true if we started another activity (and should not finish(), as we're waiting for
|
|
||||||
* their result.)
|
// Step 5. If password is needed, try to have the user set it
|
||||||
*/
|
|
||||||
private boolean setActivePolicies() {
|
|
||||||
SecurityPolicy sp = SecurityPolicy.getInstance(this);
|
|
||||||
// check current security level - if sufficient, we're done!
|
|
||||||
if (sp.isActive(null)) {
|
|
||||||
Account.clearSecurityHoldOnAllAccounts(this);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// set current security level
|
|
||||||
sp.setActivePolicies();
|
|
||||||
// check current security level - if sufficient, we're done!
|
|
||||||
int inactiveReasons = sp.getInactiveReasons(null);
|
|
||||||
if (inactiveReasons == 0) {
|
|
||||||
Account.clearSecurityHoldOnAllAccounts(this);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// If password or encryption required, launch relevant intent
|
|
||||||
if ((inactiveReasons & SecurityPolicy.INACTIVE_NEED_PASSWORD) != 0) {
|
if ((inactiveReasons & SecurityPolicy.INACTIVE_NEED_PASSWORD) != 0) {
|
||||||
|
if (mTriedSetPassword) {
|
||||||
|
repostNotification(account, security);
|
||||||
|
finish();
|
||||||
|
} else {
|
||||||
|
mTriedSetPassword = true;
|
||||||
// launch the activity to have the user set a new password.
|
// launch the activity to have the user set a new password.
|
||||||
Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
|
Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
|
||||||
startActivityForResult(intent, REQUEST_PASSWORD);
|
startActivityForResult(intent, REQUEST_PASSWORD);
|
||||||
return true;
|
}
|
||||||
} else if ((inactiveReasons & SecurityPolicy.INACTIVE_NEED_ENCRYPTION) != 0) {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6. If encryption is needed, try to have the user set it
|
||||||
|
if ((inactiveReasons & SecurityPolicy.INACTIVE_NEED_ENCRYPTION) != 0) {
|
||||||
|
if (mTriedSetEncryption) {
|
||||||
|
repostNotification(account, security);
|
||||||
|
finish();
|
||||||
|
} else {
|
||||||
|
mTriedSetEncryption = true;
|
||||||
// launch the activity to start up encryption.
|
// launch the activity to start up encryption.
|
||||||
Intent intent = new Intent(DevicePolicyManager.ACTION_START_ENCRYPTION);
|
Intent intent = new Intent(DevicePolicyManager.ACTION_START_ENCRYPTION);
|
||||||
startActivityForResult(intent, REQUEST_ENCRYPTION);
|
startActivityForResult(intent, REQUEST_ENCRYPTION);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 7. No problems were found, so clear holds and exit
|
||||||
|
Account.clearSecurityHoldOnAllAccounts(this);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark an account as not-ready-for-sync and post a notification to bring the user back here
|
||||||
|
* eventually.
|
||||||
|
*/
|
||||||
|
private void repostNotification(final Account account, final SecurityPolicy security) {
|
||||||
|
Utility.runAsync(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
security.policiesRequired(account.mId);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user