here's my problem :
I have a programme that need a password to work so I thought I could make an AccountManager. I took the code from this tutorial and it works just fine : I have a new account in setting->accounts !
BUT to test if it was safe I did another programme (lets call it Prog2 and the firt one Prog1) with the same code and supprise, I have full access to the password of the account I created with Prog2 with Prog1.
I know that it's possible to secure the account cause I tried with google and facebook accounts and I could not have access to their password.
Here's my code :
PS : if at the end of a String there is a '1' it's because I changed it in Prog1 and not in Prog2 to test if these variable had some effect
Authenticator
public class Authenticator extends AbstractAccountAuthenticator {
private String TAG = "CoderzHeavenAuthenticator";
private final Context mContext;
public Authenticator(Context context) {
super(context);
// I hate you! Google - set mContext as protected!
this.mContext = context;
}
@Override
public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {
Log.d("CoderzHeaven", TAG + "> addAccount");
final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
intent.putExtra(AuthenticatorActivity.ARG_ACCOUNT_TYPE, accountType);
intent.putExtra(AuthenticatorActivity.ARG_AUTH_TYPE, authTokenType);
intent.putExtra(AuthenticatorActivity.ARG_IS_ADDING_NEW_ACCOUNT, true);
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
final Bundle bundle = new Bundle();
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
return bundle;
}
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
Log.d("CoderzHeaven", TAG + "> getAuthToken");
// If the caller requested an authToken type we don't support, then
// return an error
if (!authTokenType.equals(AccountGeneral.AUTHTOKEN_TYPE_READ_ONLY) && !authTokenType.equals(AUTHTOKEN_TYPE_FULL_ACCESS)) {
final Bundle result = new Bundle();
result.putString(AccountManager.KEY_ERROR_MESSAGE, "invalid authTokenType");
return result;
}
// Extract the username and password from the Account Manager, and ask
// the server for an appropriate AuthToken.
final AccountManager am = AccountManager.get(mContext);
String authToken = am.peekAuthToken(account, authTokenType);
Log.d("CoderzHeaven", TAG + "> peekAuthToken returned - " + authToken);
// Lets give another try to authenticate the user
if (TextUtils.isEmpty(authToken)) {
final String password = am.getPassword(account);
if (password != null) {
try {
Log.d("CoderzHeaven", TAG + "> re-authenticating with the existing password");
//authToken = sServerAuthenticate.userSignIn(account.name, password, authTokenType);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// If we get an authToken - we return it
if (!TextUtils.isEmpty(authToken)) {
final Bundle result = new Bundle();
result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
return result;
}
// If we get here, then we couldn't access the user's password - so we
// need to re-prompt them for their credentials. We do that by creating
// an intent to display our AuthenticatorActivity.
final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
intent.putExtra(AuthenticatorActivity.ARG_ACCOUNT_TYPE, account.type);
intent.putExtra(AuthenticatorActivity.ARG_AUTH_TYPE, authTokenType);
intent.putExtra(AuthenticatorActivity.ARG_ACCOUNT_NAME, account.name);
final Bundle bundle = new Bundle();
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
return bundle;
}
@Override
public String getAuthTokenLabel(String authTokenType) {
if (AUTHTOKEN_TYPE_FULL_ACCESS.equals(authTokenType))
return AUTHTOKEN_TYPE_FULL_ACCESS_LABEL;
else if (AUTHTOKEN_TYPE_READ_ONLY.equals(authTokenType))
return AUTHTOKEN_TYPE_READ_ONLY_LABEL;
else
return authTokenType + " (Label)";
}
@Override
public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {
final Bundle result = new Bundle();
result.putBoolean(KEY_BOOLEAN_RESULT, false);
return result;
}
@Override
public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
return null;
}
@Override
public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
return null;
}
@Override
public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
return null;
}
}
AuthenticatorService
public class AuthenticatorService extends Service {
private Authenticator authenticator;
public AuthenticatorService() {
super();
}
public IBinder onBind(Intent intent) {
IBinder ret = null;
if (intent.getAction().equals(android.accounts.AccountManager.ACTION_AUTHENTICATOR_INTENT))
ret = getAuthenticator().getIBinder();
return ret;
}
private Authenticator getAuthenticator() {
if (authenticator == null)
authenticator = new Authenticator(this);
return authenticator;
}
}
AuthenticatorActivity
public class AuthenticatorActivity extends AccountAuthenticatorActivity implements OnClickListener{
public final static String ARG_ACCOUNT_TYPE = "ACCOUNT_TYPE1";
public final static String ARG_AUTH_TYPE = "AUTH_TYPE1";
public final static String ARG_ACCOUNT_NAME = "ACCOUNT_NAME1";
public final static String ARG_IS_ADDING_NEW_ACCOUNT = "IS_ADDING_ACCOUNT1";
public static final String KEY_ERROR_MESSAGE = "ERR_MSG1";
public final static String PARAM_USER_PASS = "USER_PASS1";
private final String TAG = this.getClass().getSimpleName();
private AccountManager mAccountManager;
private String mAuthTokenType;
String authtoken = "12345678910"; // this
String password = "1234510";
String accountName;
public Account findAccount(String accountName) {
for (Account account : mAccountManager.getAccounts())
if (TextUtils.equals(account.name, accountName) && TextUtils.equals(account.type, getString(R.string.auth_type))) {
System.out.println("FOUND");
return account;
}
return null;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_login);
Log.d(TAG, "onCreate");
mAccountManager = AccountManager.get(getBaseContext());
// If this is a first time adding, then this will be null
accountName = getIntent().getStringExtra(ARG_ACCOUNT_NAME);
mAuthTokenType = getIntent().getStringExtra(ARG_AUTH_TYPE);
if (mAuthTokenType == null)
mAuthTokenType = getString(R.string.auth_type);
findAccount(accountName);
System.out.println(mAuthTokenType + ", accountName : " + accountName);
((Button)findViewById(R.id.submit)).setOnClickListener(this);
}
void userSignIn() {
// You should probably call your server with user credentials and get
// the authentication token here.
// For demo, I have hard-coded it.
authtoken = "12345678910";
accountName = ((EditText) findViewById(R.id.accountName)).getText().toString().trim();
password = ((EditText) findViewById(R.id.accountPassword)).getText().toString().trim();
if (accountName.length() > 0) {
Bundle data = new Bundle();
data.putString(AccountManager.KEY_ACCOUNT_NAME, accountName);
data.putString(AccountManager.KEY_ACCOUNT_TYPE, mAuthTokenType);
data.putString(AccountManager.KEY_AUTHTOKEN, authtoken);
data.putString(PARAM_USER_PASS, password);
// Some extra data about the user
Bundle userData = new Bundle();
userData.putString("UserID", "25");
data.putBundle(AccountManager.KEY_USERDATA, userData);
//Make it an intent to be passed back to the Android Authenticator
final Intent res = new Intent();
res.putExtras(data);
//Create the new account with Account Name and TYPE
final Account account = new Account(accountName, mAuthTokenType);
//Add the account to the Android System
if (mAccountManager.addAccountExplicitly(account, password, userData)) {
// worked
Log.d(TAG, "Account added");
mAccountManager.setAuthToken(account, mAuthTokenType, authtoken);
setAccountAuthenticatorResult(data);
setResult(RESULT_OK, res);
finish();
} else {
// guess not
Log.d(TAG, "Account NOT added");
}
}
}
@Override
public void onClick(View v) {
userSignIn();
}
}
AccountGeneral
public class AccountGeneral {
/**
* Account name
*/
public static final String ACCOUNT_NAME = "CoderzHeaven1";
/**
* Auth token types
*/
public static final String AUTHTOKEN_TYPE_READ_ONLY = "Read only1";
public static final String AUTHTOKEN_TYPE_READ_ONLY_LABEL = "Read only access to an CoderzHeaven account1";
public static final String AUTHTOKEN_TYPE_FULL_ACCESS = "Full access1";
public static final String AUTHTOKEN_TYPE_FULL_ACCESS_LABEL = "Full access to an CoderzHeaven account1";
}